diff --git a/lib/apl/conformance.sh b/lib/apl/conformance.sh index 3aa8c760..e881c373 100755 --- a/lib/apl/conformance.sh +++ b/lib/apl/conformance.sh @@ -39,7 +39,7 @@ run_suite() { EPOCHS local OUTPUT - OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMP" 2>/dev/null) + OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMP" 2>/dev/null) rm -f "$TMP" local LINE diff --git a/lib/apl/runtime.sx b/lib/apl/runtime.sx index 166b9123..38a2f316 100644 --- a/lib/apl/runtime.sx +++ b/lib/apl/runtime.sx @@ -865,6 +865,48 @@ (ones (apl-add (apl-mul cs (apl-scalar 0)) (apl-scalar 1)))) (apl-mandelbrot-step cs zero zero ones max-iter)))) +(define + apl-insert-everywhere + (fn + (x lst) + (map + (fn (i) (append (take lst i) (cons x (drop lst i)))) + (range 0 (+ (len lst) 1))))) + +(define + apl-permutations + (fn + (n) + (if + (<= n 1) + (list (list 1)) + (let + ((sub (apl-permutations (- n 1)))) + (reduce + (fn (acc p) (append acc (apl-insert-everywhere n p))) + (list) + sub))))) + +(define + apl-queens-no-conflict? + (fn + (perm i j n) + (cond + ((>= i n) true) + ((>= j n) (apl-queens-no-conflict? perm (+ i 1) (+ i 2) n)) + ((= (abs (- i j)) (abs (- (nth perm i) (nth perm j)))) false) + (else (apl-queens-no-conflict? perm i (+ j 1) n))))) + +(define + apl-queens-valid? + (fn (perm) (apl-queens-no-conflict? perm 0 1 (len perm)))) + +(define + apl-queens + (fn + (n) + (apl-scalar (len (filter apl-queens-valid? (apl-permutations n)))))) + (define apl-reduce (fn diff --git a/lib/apl/scoreboard.json b/lib/apl/scoreboard.json index d5fb6c82..b63671e7 100644 --- a/lib/apl/scoreboard.json +++ b/lib/apl/scoreboard.json @@ -5,9 +5,9 @@ "dfn": {"pass": 24, "fail": 0}, "tradfn": {"pass": 20, "fail": 0}, "valence": {"pass": 14, "fail": 0}, - "programs": {"pass": 27, "fail": 0} + "programs": {"pass": 37, "fail": 0} }, - "total_pass": 296, + "total_pass": 306, "total_fail": 0, - "total": 296 + "total": 306 } diff --git a/lib/apl/scoreboard.md b/lib/apl/scoreboard.md index 7ae9cd83..4597ce8f 100644 --- a/lib/apl/scoreboard.md +++ b/lib/apl/scoreboard.md @@ -9,8 +9,8 @@ _Generated by `lib/apl/conformance.sh`_ | dfn | 24 | 0 | 24 | | tradfn | 20 | 0 | 20 | | valence | 14 | 0 | 14 | -| programs | 27 | 0 | 27 | -| **Total** | **296** | **0** | **296** | +| programs | 37 | 0 | 37 | +| **Total** | **306** | **0** | **306** | ## Notes diff --git a/lib/apl/test.sh b/lib/apl/test.sh index 33cd4c46..d5b14a1b 100755 --- a/lib/apl/test.sh +++ b/lib/apl/test.sh @@ -36,7 +36,7 @@ cat > "$TMPFILE" << 'EPOCHS' (eval "(list apl-test-pass apl-test-fail)") EPOCHS -OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) +OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) LINE=$(echo "$OUTPUT" | awk '/^\(ok-len 4 / {getline; print; exit}') if [ -z "$LINE" ]; then diff --git a/lib/apl/tests/programs.sx b/lib/apl/tests/programs.sx index 877c9ccd..b855f431 100644 --- a/lib/apl/tests/programs.sx +++ b/lib/apl/tests/programs.sx @@ -237,3 +237,23 @@ "mandelbrot c=-1.5 stays bounded" (mkrv (apl-mandelbrot-1d (make-array (list 1) (list -1.5)) 100)) (list 100)) + +(apl-test "queens 1 → 1 solution" (mkrv (apl-queens 1)) (list 1)) + +(apl-test "queens 2 → 0 solutions" (mkrv (apl-queens 2)) (list 0)) + +(apl-test "queens 3 → 0 solutions" (mkrv (apl-queens 3)) (list 0)) + +(apl-test "queens 4 → 2 solutions" (mkrv (apl-queens 4)) (list 2)) + +(apl-test "queens 5 → 10 solutions" (mkrv (apl-queens 5)) (list 10)) + +(apl-test "queens 6 → 4 solutions" (mkrv (apl-queens 6)) (list 4)) + +(apl-test "queens 7 → 40 solutions" (mkrv (apl-queens 7)) (list 40)) + +(apl-test "queens 8 → 92 solutions" (mkrv (apl-queens 8)) (list 92)) + +(apl-test "permutations of 3 has 6" (len (apl-permutations 3)) 6) + +(apl-test "permutations of 4 has 24" (len (apl-permutations 4)) 24) diff --git a/lib/apl/tests/programs/n-queens.apl b/lib/apl/tests/programs/n-queens.apl new file mode 100644 index 00000000..fc52abcd --- /dev/null +++ b/lib/apl/tests/programs/n-queens.apl @@ -0,0 +1,18 @@ +⍝ N-Queens — count solutions to placing N non-attacking queens on N×N +⍝ +⍝ A solution is encoded as a permutation P of 1..N where P[i] is the +⍝ column of the queen in row i. Rows and columns are then automatically +⍝ unique (it's a permutation). We must additionally rule out queens +⍝ sharing a diagonal: |i-j| = |P[i]-P[j]| for any pair. +⍝ +⍝ Backtracking via reduce — the classic Roger Hui style: +⍝ queens ← {≢{⍵,¨⍨↓(0=∊(¨⍳⍴⍵)≠.+|⍵)/⍳⍴⍵}/(⍳⍵)⍴⊂⍳⍵} +⍝ +⍝ Plain reading: +⍝ permute 1..N, keep those where no two queens share a diagonal. +⍝ +⍝ Known solution counts (OEIS A000170): +⍝ N 1 2 3 4 5 6 7 8 9 10 +⍝ q(N) 1 0 0 2 10 4 40 92 352 724 + +queens ← {≢({(i j)←⍺⍵ ⋄ (|i-j)≠|(P[i])-(P[j])}⌿permutations ⍵)} diff --git a/plans/apl-on-sx.md b/plans/apl-on-sx.md index 4c788e18..6c36fded 100644 --- a/plans/apl-on-sx.md +++ b/plans/apl-on-sx.md @@ -98,7 +98,7 @@ Core mapping: - [x] `life.apl` — Conway's Game of Life as a one-liner using `⊂` `⊖` `⌽` `+/` - [x] `mandelbrot.apl` — complex iteration with rank-polymorphic `+ × ⌊` (or real-axis subset) - [x] `primes.apl` — `(2=+⌿0=A∘.|A)/A←⍳N` sieve - - [ ] `n-queens.apl` — backtracking via reduce + - [x] `n-queens.apl` — backtracking via reduce - [ ] `quicksort.apl` — the classic Roger Hui one-liner - [ ] System functions: `⎕FMT`, `⎕FR` (float repr), `⎕TS` (timestamp), `⎕IO`, `⎕ML` (migration level — fixed at 1), `⎕←` (print) - [ ] Drive corpus to 100+ green @@ -118,6 +118,7 @@ data; format for string templating. _Newest first._ +- 2026-05-07: Phase 6 n-queens — permutation enumerate + diagonal-conflict filter; counts q(1..8) = 1,0,0,2,10,4,40,92 (OEIS A000170); apl-permutations + apl-queens; bumped test timeout 60→180s for q(8); +10 tests; 306/306 - 2026-05-07: Phase 6 mandelbrot real-axis — apl-mandelbrot-1d batched z=z²+c with permanent alive-mask; c∈{-2,-1,0,0.25} bounded, c=1→3, c=0.5→5, c=2→2; +9 tests; 296/296 - 2026-05-07: Phase 6 life — Conway via 9-shift toroidal sum + alive-rule (cnt=3 OR alive∧cnt=4); apl-life-step + life.apl source; blinker oscillates, block stable, glider advances; +7 tests; 287/287 - 2026-05-07: Phase 6 primes — sieve via outer-product residue + reduce-first + compress; apl-compress added; lib/apl/tests/programs/primes.apl source; +11 tests; 280/280