Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Five infrastructure fixes to make the Hui formulation
{1 ⍵ ∨.∧ 3 4 = +/+/¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵} work:
1. apl-each-dyadic: unbox enclosed-array scalar before pairing;
preserve array results instead of disclosing
2. apl-outer: same dict-vs-number wrap detection
3. apl-reduce: dict-aware wrap in reducer; don't double-wrap
the final result in apl-scalar when it's already a dict
4. broadcast-dyadic: leading-axis extension for shape-(k) vs
shape-(k …) — `3 4 = M[5,5]` → shape (2 5 5)
5. :vec eval keeps non-scalar dicts intact (no flatten-to-first)
life.apl: drop leading ⊃ (Hui's ⊃ assumes inner-product produces
enclosed cell; our extension-style impl produces clean (5 5)).
Comment block in life.apl explains.
5 e2e tests: blinker oscillates period-2, 2×2 block stable,
empty grid stays empty, source file load via apl-run-file.
Full suite 578/578.
131 lines
3.9 KiB
Plaintext
131 lines
3.9 KiB
Plaintext
; End-to-end tests of the classic-program archetypes — running APL
|
||
; source through the full pipeline (tokenize → parse → eval-ast → runtime).
|
||
;
|
||
; These mirror the algorithms documented in lib/apl/tests/programs/*.apl
|
||
; but use forms our pipeline supports today (named functions instead of
|
||
; the inline ⍵← rebinding idiom; multi-stmt over single one-liners).
|
||
|
||
(define mkrv (fn (arr) (get arr :ravel)))
|
||
(define mksh (fn (arr) (get arr :shape)))
|
||
|
||
; ---------- factorial via ∇ recursion (cf. n-queens style) ----------
|
||
|
||
(apl-test
|
||
"e2e: factorial 5! = 120"
|
||
(mkrv (apl-run "fact ← {0=⍵:1 ⋄ ⍵×∇⍵-1} ⋄ fact 5"))
|
||
(list 120))
|
||
|
||
(apl-test
|
||
"e2e: factorial 7! = 5040"
|
||
(mkrv (apl-run "fact ← {0=⍵:1 ⋄ ⍵×∇⍵-1} ⋄ fact 7"))
|
||
(list 5040))
|
||
|
||
(apl-test
|
||
"e2e: factorial via ×/⍳N (no recursion)"
|
||
(mkrv (apl-run "fact ← {×/⍳⍵} ⋄ fact 6"))
|
||
(list 720))
|
||
|
||
; ---------- sum / triangular numbers (sum-1..N) ----------
|
||
|
||
(apl-test
|
||
"e2e: triangular(10) = 55"
|
||
(mkrv (apl-run "tri ← {+/⍳⍵} ⋄ tri 10"))
|
||
(list 55))
|
||
|
||
(apl-test
|
||
"e2e: triangular(100) = 5050"
|
||
(mkrv (apl-run "tri ← {+/⍳⍵} ⋄ tri 100"))
|
||
(list 5050))
|
||
|
||
; ---------- sum of squares ----------
|
||
|
||
(apl-test
|
||
"e2e: sum-of-squares 1..5 = 55"
|
||
(mkrv (apl-run "ss ← {+/⍵×⍵} ⋄ ss ⍳5"))
|
||
(list 55))
|
||
|
||
(apl-test
|
||
"e2e: sum-of-squares 1..10 = 385"
|
||
(mkrv (apl-run "ss ← {+/⍵×⍵} ⋄ ss ⍳10"))
|
||
(list 385))
|
||
|
||
; ---------- divisor-counting (prime-sieve building blocks) ----------
|
||
|
||
(apl-test
|
||
"e2e: divisor counts 1..5 via outer mod"
|
||
(mkrv (apl-run "P ← ⍳ 5 ⋄ +⌿ 0 = P ∘.| P"))
|
||
(list 1 2 2 3 2))
|
||
|
||
(apl-test
|
||
"e2e: divisor counts 1..10"
|
||
(mkrv (apl-run "P ← ⍳ 10 ⋄ +⌿ 0 = P ∘.| P"))
|
||
(list 1 2 2 3 2 4 2 4 3 4))
|
||
|
||
(apl-test
|
||
"e2e: prime-mask 1..10 (count==2)"
|
||
(mkrv (apl-run "P ← ⍳ 10 ⋄ 2 = +⌿ 0 = P ∘.| P"))
|
||
(list 0 1 1 0 1 0 1 0 0 0))
|
||
|
||
; ---------- monadic primitives chained ----------
|
||
|
||
(apl-test
|
||
"e2e: sum of |abs| = 15"
|
||
(mkrv (apl-run "+/|¯1 ¯2 ¯3 ¯4 ¯5"))
|
||
(list 15))
|
||
|
||
(apl-test
|
||
"e2e: max of squares 1..6"
|
||
(mkrv (apl-run "⌈/(⍳6)×⍳6"))
|
||
(list 36))
|
||
|
||
; ---------- nested named functions ----------
|
||
|
||
(apl-test
|
||
"e2e: compose dbl and sq via two named fns"
|
||
(mkrv (apl-run "dbl ← {⍵+⍵} ⋄ sq ← {⍵×⍵} ⋄ sq dbl 3"))
|
||
(list 36))
|
||
|
||
(apl-test
|
||
"e2e: max-of-two as named dyadic fn"
|
||
(mkrv (apl-run "mx ← {⍺⌈⍵} ⋄ 5 mx 3"))
|
||
(list 5))
|
||
|
||
(apl-test
|
||
"e2e: sqrt-via-newton 1 step from 1 → 2.5"
|
||
(mkrv (apl-run "step ← {(⍵+⍺÷⍵)÷2} ⋄ 4 step 1"))
|
||
(list 2.5))
|
||
|
||
(begin
|
||
(apl-test
|
||
"life.apl: blinker 5×5 → vertical blinker"
|
||
(mkrv
|
||
(apl-run
|
||
"life ← {1 ⍵ ∨.∧ 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵} ⋄ life 5 5 ⍴ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0"))
|
||
(list 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0))
|
||
(apl-test
|
||
"life.apl: blinker oscillates (period 2)"
|
||
(mkrv
|
||
(apl-run
|
||
"life ← {1 ⍵ ∨.∧ 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵} ⋄ life life 5 5 ⍴ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0"))
|
||
(list 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0))
|
||
(apl-test
|
||
"life.apl: 2×2 block stable"
|
||
(mkrv
|
||
(apl-run
|
||
"life ← {1 ⍵ ∨.∧ 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵} ⋄ life 4 4 ⍴ 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0"))
|
||
(list 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0))
|
||
(apl-test
|
||
"life.apl: empty grid stays empty"
|
||
(mkrv
|
||
(apl-run
|
||
"life ← {1 ⍵ ∨.∧ 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵} ⋄ life 5 5 ⍴ 0"))
|
||
(list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
|
||
(apl-test
|
||
"life.apl: source-file as-written runs"
|
||
(let
|
||
((dfn (apl-run-file "lib/apl/tests/programs/life.apl"))
|
||
(board
|
||
(apl-run "5 5 ⍴ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0")))
|
||
(get (apl-call-dfn-m dfn board) :ravel))
|
||
(list 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0)))
|