; Phase 3/7 (optional) — relational scheduling on lib/minikanren CLP(FD). ; Each node gets a slot var; edges impose fd-lt; fd-label searches. The ASAP solution ; agrees with plan.sx's greedy Kahn waves; enumerating all solutions is the extra. ; ---- linear chain a -> b -> c: exactly one minimal schedule ---- (define sc-chain (artdag/build (list (list "a" "src" (list) {}) (list "b" "blur" (list "a") {:radius 1}) (list "c" "blur" (list "b") {:radius 2})))) (define sc-chain-a (artdag/dag-id sc-chain "a")) (define sc-chain-b (artdag/dag-id sc-chain "b")) (define sc-chain-c (artdag/dag-id sc-chain "c")) (define sc-chain-asap (artdag/schedule-asap sc-chain)) (artdag-test "chain: ASAP schedule exists" (nil? sc-chain-asap) false) (artdag-test "chain: slots are strictly increasing along the chain" (list (get sc-chain-asap sc-chain-a) (get sc-chain-asap sc-chain-b) (get sc-chain-asap sc-chain-c)) (list 1 2 3)) (artdag-test "chain: makespan equals chain length" (artdag/schedule-makespan sc-chain-asap) 3) (artdag-test "chain: exactly one schedule when slots = node count (no slack)" (len (artdag/schedules sc-chain 3)) 1) (artdag-test "chain: ASAP batches are one node per slot" (map len (artdag/schedule->batches sc-chain sc-chain-asap)) (list 1 1 1)) (artdag-test "chain: ASAP schedule is valid (deps respected)" (artdag/schedule-valid? sc-chain sc-chain-asap) true) ; ---- diamond a -> b,c -> d: b and c are parallel ---- (define sc-dia (artdag/build (list (list "a" "src" (list) {}) (list "b" "blur" (list "a") {:radius 1}) (list "c" "bright" (list "a") {:radius 1}) (list "d" "over" (list "b" "c") {} true)))) (define sc-dia-asap (artdag/schedule-asap sc-dia)) (artdag-test "diamond: ASAP makespan is 3 (a | b,c | d)" (artdag/schedule-makespan sc-dia-asap) 3) (artdag-test "diamond: ASAP batch sizes are 1,2,1" (map len (artdag/schedule->batches sc-dia sc-dia-asap)) (list 1 2 1)) (artdag-test "diamond: FD ASAP batches agree with plan.sx greedy waves" (= (artdag/schedule->batches sc-dia sc-dia-asap) (map artdag/sort-strings (artdag/plan sc-dia 0))) true) (artdag-test "diamond: every enumerated schedule is valid" (every? (fn (asn) (artdag/schedule-valid? sc-dia asn)) (artdag/schedules sc-dia 4)) true) (artdag-test "diamond: b and c share a slot in the ASAP schedule" (= (get sc-dia-asap (artdag/dag-id sc-dia "b")) (get sc-dia-asap (artdag/dag-id sc-dia "c"))) true) ; ---- parallelism cap: filter schedules to <= cap nodes per slot ---- (artdag-test "cap 1: the ASAP (b,c parallel) schedule is excluded, serial ones remain" (every? (fn (asn) (every? (fn (b) (<= (len b) 1)) (artdag/schedule->batches sc-dia asn))) (artdag/schedules-capped sc-dia 4 1)) true) (artdag-test "cap 1: at least one serial schedule exists within 4 slots" (> (len (artdag/schedules-capped sc-dia 4 1)) 0) true) (artdag-test "cap 2: admits the parallel ASAP schedule" (if (some (fn (shape) (= shape (list 1 2 1))) (map (fn (asn) (map len (artdag/schedule->batches sc-dia asn))) (artdag/schedules-capped sc-dia 4 2))) true false) true) ; ---- unsatisfiable: too few slots for the chain ---- (artdag-test "chain: no schedule when slots < chain length" (nil? (artdag/schedule sc-chain 2)) true)