From 0f130529007ac0bf093cf303490746f60b872763 Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 7 May 2026 06:23:03 +0000 Subject: [PATCH] =?UTF-8?q?apl:=20quicksort=20recursive=20partition=20?= =?UTF-8?q?=E2=80=94=20Phase=206=20classics=20complete=20(+9=20tests,=2031?= =?UTF-8?q?5/315)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apl/runtime.sx | 18 +++++++++++ lib/apl/scoreboard.json | 6 ++-- lib/apl/scoreboard.md | 4 +-- lib/apl/tests/programs.sx | 47 ++++++++++++++++++++++++++++ lib/apl/tests/programs/quicksort.apl | 25 +++++++++++++++ plans/apl-on-sx.md | 5 +-- 6 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 lib/apl/tests/programs/quicksort.apl diff --git a/lib/apl/runtime.sx b/lib/apl/runtime.sx index 38a2f316..8533664d 100644 --- a/lib/apl/runtime.sx +++ b/lib/apl/runtime.sx @@ -907,6 +907,24 @@ (n) (apl-scalar (len (filter apl-queens-valid? (apl-permutations n)))))) +(define + apl-quicksort + (fn + (arr) + (let + ((ravel (get arr :ravel))) + (if + (<= (len ravel) 1) + arr + (let + ((pivot (apl-scalar (first ravel)))) + (let + ((less (apl-quicksort (apl-compress (apl-lt arr pivot) arr))) + (eq (apl-compress (apl-eq arr pivot) arr)) + (greater + (apl-quicksort (apl-compress (apl-gt arr pivot) arr)))) + (apl-catenate less (apl-catenate eq greater)))))))) + (define apl-reduce (fn diff --git a/lib/apl/scoreboard.json b/lib/apl/scoreboard.json index b63671e7..771f4996 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": 37, "fail": 0} + "programs": {"pass": 46, "fail": 0} }, - "total_pass": 306, + "total_pass": 315, "total_fail": 0, - "total": 306 + "total": 315 } diff --git a/lib/apl/scoreboard.md b/lib/apl/scoreboard.md index 4597ce8f..9a346610 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 | 37 | 0 | 37 | -| **Total** | **306** | **0** | **306** | +| programs | 46 | 0 | 46 | +| **Total** | **315** | **0** | **315** | ## Notes diff --git a/lib/apl/tests/programs.sx b/lib/apl/tests/programs.sx index b855f431..7d97976a 100644 --- a/lib/apl/tests/programs.sx +++ b/lib/apl/tests/programs.sx @@ -257,3 +257,50 @@ (apl-test "permutations of 3 has 6" (len (apl-permutations 3)) 6) (apl-test "permutations of 4 has 24" (len (apl-permutations 4)) 24) + +(apl-test + "quicksort empty" + (mkrv (apl-quicksort (make-array (list 0) (list)))) + (list)) + +(apl-test + "quicksort single" + (mkrv (apl-quicksort (make-array (list 1) (list 42)))) + (list 42)) + +(apl-test + "quicksort already sorted" + (mkrv (apl-quicksort (make-array (list 5) (list 1 2 3 4 5)))) + (list 1 2 3 4 5)) + +(apl-test + "quicksort reverse sorted" + (mkrv (apl-quicksort (make-array (list 5) (list 5 4 3 2 1)))) + (list 1 2 3 4 5)) + +(apl-test + "quicksort with duplicates" + (mkrv (apl-quicksort (make-array (list 7) (list 3 1 4 1 5 9 2)))) + (list 1 1 2 3 4 5 9)) + +(apl-test + "quicksort all equal" + (mkrv (apl-quicksort (make-array (list 5) (list 7 7 7 7 7)))) + (list 7 7 7 7 7)) + +(apl-test + "quicksort negatives" + (mkrv (apl-quicksort (make-array (list 5) (list -3 1 -1 2 0)))) + (list -3 -1 0 1 2)) + +(apl-test + "quicksort 11-element pi" + (mkrv + (apl-quicksort (make-array (list 11) (list 3 1 4 1 5 9 2 6 5 3 5)))) + (list 1 1 2 3 3 4 5 5 5 6 9)) + +(apl-test + "quicksort preserves length" + (first + (mksh (apl-quicksort (make-array (list 7) (list 3 1 4 1 5 9 2))))) + 7) diff --git a/lib/apl/tests/programs/quicksort.apl b/lib/apl/tests/programs/quicksort.apl new file mode 100644 index 00000000..c9dd345d --- /dev/null +++ b/lib/apl/tests/programs/quicksort.apl @@ -0,0 +1,25 @@ +⍝ Quicksort — the classic Roger Hui one-liner +⍝ +⍝ Q ← {1≥≢⍵:⍵ ⋄ (∇⍵⌿⍨⍵p←⍵⌷⍨?≢⍵} +⍝ +⍝ Read right-to-left: +⍝ ?≢⍵ : pick a random index in 1..length +⍝ ⍵⌷⍨… : take that element as pivot p +⍝ ⍵>p : boolean — elements greater than pivot +⍝ ∇⍵⌿⍨… : recursively sort the > partition +⍝ (p=⍵)/⍵ : keep elements equal to pivot +⍝ ⍵

p} diff --git a/plans/apl-on-sx.md b/plans/apl-on-sx.md index 6c36fded..ddf175b1 100644 --- a/plans/apl-on-sx.md +++ b/plans/apl-on-sx.md @@ -94,12 +94,12 @@ Core mapping: - [x] `lib/apl/conformance.sh` + runner, `scoreboard.json` + `scoreboard.md` ### Phase 6 — classic programs + drive corpus -- [ ] Classic programs in `lib/apl/tests/programs/`: +- [x] Classic programs in `lib/apl/tests/programs/`: - [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 - [x] `n-queens.apl` — backtracking via reduce - - [ ] `quicksort.apl` — the classic Roger Hui one-liner + - [x] `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 - [ ] Idiom corpus — `lib/apl/tests/idioms.sx` covering classic Roger Hui / Phil Last idioms @@ -118,6 +118,7 @@ data; format for string templating. _Newest first._ +- 2026-05-07: Phase 6 quicksort — recursive less/eq/greater partition via apl-compress, deterministic-pivot variant; tests cover empty/single/sorted/reverse/duplicates/negatives; **all 5 classic programs done**; +9 tests; 315/315 - 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