basedpl 0.1.63__tar.gz → 0.1.64__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {basedpl-0.1.63 → basedpl-0.1.64}/Cargo.lock +12 -11
- {basedpl-0.1.63 → basedpl-0.1.64}/Cargo.toml +3 -3
- {basedpl-0.1.63 → basedpl-0.1.64}/DEV.md +33 -21
- {basedpl-0.1.63 → basedpl-0.1.64}/PKG-INFO +1 -1
- {basedpl-0.1.63/python/basedpl → basedpl-0.1.64/editors/jetbrains/BPL.tmbundle/Syntaxes}/bpl.tmLanguage.json +1 -1
- {basedpl-0.1.63/python/basedpl → basedpl-0.1.64/editors/jetbrains/BPL.tmbundle/Syntaxes}/hpl.tmLanguage.json +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/vim/syntax/bpl.vim +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/arrays.ipynb +164 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/bpl.xml +1 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/dyalog.ipynb +96 -24
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/evaluation.qmd +16 -5
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/at.qmd +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-slash.qmd +1 -1
- basedpl-0.1.64/nbs/glyphs/downstile.qmd +25 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/greater-than-or-equal.qmd +3 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/greater-than.qmd +3 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/less-than-or-equal.qmd +3 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/less-than.qmd +3 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/partial.qmd +1 -1
- basedpl-0.1.64/nbs/glyphs/upstile.qmd +19 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/hpl.xml +1 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/introspection.ipynb +2 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/llms.txt +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/magics.ipynb +197 -48
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/modules.qmd +6 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/notebooks.ipynb +98 -27
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/bpl.js +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/hpl.tmLanguage.json +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/python.ipynb +716 -197
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/01_basics.ipynb +3 -3
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/explain.qmd +10 -4
- basedpl-0.1.64/nbs/system/nc.qmd +3 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/terms.qmd +1 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/py/src/lib.rs +4 -13
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/__init__.py +20 -4
- {basedpl-0.1.63/editors/jetbrains/BPL.tmbundle/Syntaxes → basedpl-0.1.64/python/basedpl}/bpl.tmLanguage.json +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/bpltests.py +112 -7
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/editors.py +4 -3
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/functions.py +0 -4
- {basedpl-0.1.63/editors/jetbrains/BPL.tmbundle/Syntaxes → basedpl-0.1.64/python/basedpl}/hpl.tmLanguage.json +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/printing.py +1 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/agreement.rs +9 -5
- {basedpl-0.1.63 → basedpl-0.1.64}/src/array/storage.rs +57 -14
- {basedpl-0.1.63 → basedpl-0.1.64}/src/array/text.rs +2 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/src/array.rs +60 -19
- {basedpl-0.1.63 → basedpl-0.1.64}/src/batch.rs +60 -30
- {basedpl-0.1.63 → basedpl-0.1.64}/src/data.rs +4 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/derivative.rs +19 -28
- {basedpl-0.1.63 → basedpl-0.1.64}/src/display.rs +1 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/distribution.rs +7 -11
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/assign.rs +92 -60
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/binder.rs +258 -206
- basedpl-0.1.64/src/eval/bindings.rs +395 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/dissect.rs +1 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/idioms.rs +15 -8
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/operators.rs +90 -23
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval/session.rs +149 -193
- basedpl-0.1.64/src/eval/tree.rs +771 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/eval.rs +102 -116
- {basedpl-0.1.63 → basedpl-0.1.64}/src/explain.rs +51 -50
- {basedpl-0.1.63 → basedpl-0.1.64}/src/files.rs +2 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/fusion.rs +52 -32
- {basedpl-0.1.63 → basedpl-0.1.64}/src/image.rs +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/src/js.rs +2 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/keyed.rs +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/src/lib.rs +1 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/linear.rs +44 -48
- basedpl-0.1.64/src/name.rs +72 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/number.rs +7 -31
- {basedpl-0.1.63 → basedpl-0.1.64}/src/pervasive.rs +313 -360
- {basedpl-0.1.63 → basedpl-0.1.64}/src/primitive/numeric.rs +101 -80
- {basedpl-0.1.63 → basedpl-0.1.64}/src/primitive/search.rs +3 -6
- {basedpl-0.1.63 → basedpl-0.1.64}/src/primitive/structural.rs +14 -57
- {basedpl-0.1.63 → basedpl-0.1.64}/src/primitive.rs +23 -33
- {basedpl-0.1.63 → basedpl-0.1.64}/src/reference.rs +101 -29
- {basedpl-0.1.63 → basedpl-0.1.64}/src/selection.rs +8 -5
- {basedpl-0.1.63 → basedpl-0.1.64}/src/syntax.rs +55 -28
- {basedpl-0.1.63 → basedpl-0.1.64}/src/system.rs +120 -62
- {basedpl-0.1.63 → basedpl-0.1.64}/src/timing.rs +7 -33
- {basedpl-0.1.63 → basedpl-0.1.64}/src/transform.rs +22 -17
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/explain.rs +10 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/highlighting.mjs +1 -1
- basedpl-0.1.64/tests/instructions.txt +32 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/README.md +3 -3
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/core.bpl +347 -13
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference.rs +2 -2
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/scaling.rs +5 -8
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/speed.rs +1 -1
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/speed.txt +6 -4
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_api.py +12 -3
- basedpl-0.1.64/tests/test_instructions.py +9 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/wasm.mjs +8 -8
- basedpl-0.1.63/nbs/glyphs/downstile.qmd +0 -23
- basedpl-0.1.63/nbs/glyphs/upstile.qmd +0 -17
- basedpl-0.1.63/nbs/system/nc.qmd +0 -3
- basedpl-0.1.63/src/eval/tree.rs +0 -324
- {basedpl-0.1.63 → basedpl-0.1.64}/.cargo/config.toml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.gitattributes +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.github/workflows/ci.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.github/workflows/docs.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.github/workflows/speed.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.github/workflows/test.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/.gitignore +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/CONTRIBUTING.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/LICENSE +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/_config.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/_layouts/default.html +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/build.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/jetbrains/BPL.tmbundle/info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/jetbrains/BPL.xml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/jetbrains/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.icns +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.keylayout +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-de.txt +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.icns +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.keylayout +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-es.txt +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.icns +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.keylayout +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-fr.txt +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.icns +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.keylayout +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-uk.txt +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.icns +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.keylayout +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/macos/BasedPL-us.txt +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/vim/ftdetect/bpl.vim +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/build.ps1 +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/install.ps1 +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/keyboard.c +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/keyboard.def +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/keyboard.rc +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/editors/windows/layout.h +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/index_files/figure-commonmark/cell-17-output-1.svg +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/index_files/figure-commonmark/cell-18-output-1.svg +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/index_files/figure-html/cell-17-output-1.svg +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/index_files/figure-html/cell-18-output-1.svg +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/LICENSE-april +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/array.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/dyalog.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/graph.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/numeric.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/power.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/regex.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/string.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/lib/tree.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/.gitignore +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/_quarto.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/assignment.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/bqn.xml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/bracket-types.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/cli.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/comparison.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/data.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/dfns.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/distributions.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/driver.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/dyalog.xml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/fonts/LICENSE-SAX2 +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/fonts/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/fonts/SAX2B.ttf +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/fonts/SAX2B.woff2 +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/fonts.css +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/attractor.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/boids.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/dragon.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/flow.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/mandelbrot.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/mandelbrot32.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/orbits.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/phyllotaxis.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/prefs.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery/reaction.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/gallery.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/getting-started.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/_metadata.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/alpha-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/alpha.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/backslash-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/backslash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/braces.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/brackets.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/bullet.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-backslash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-divide.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-star.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-stile.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle-times.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/circle.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/colon.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/comma-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/comma.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/del-diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/del-stile.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/del.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/delta-stile.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/diamond-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/diamond.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/domino.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/dot.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/down-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/down-shoe.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/down-tack.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/epsilon-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/epsilon.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/equal-underbar-slash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/equal-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/equals.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/error-guard.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/exclamation.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/hash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/hydrant.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/infinity.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/inverted-question.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/iota-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/iota.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/jot-diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/jot.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/lamp.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/left-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/left-shoe-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/left-shoe.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/left-tack.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/left-tail-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/minus.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/not-equals.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/obelus.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/omega-underbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/omega.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/overbar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/parentheses.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/pi.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/plus.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quad-colon.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quad-diamond.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quad-equal.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quad-jot.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quad.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/question.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/quote.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/radical.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/rho.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/right-arrow-from-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/right-left-arrows.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/right-shoe.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/right-tack.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/right-tail-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/slash-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/slash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/squad.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/star-diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/star.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/stile-tilde.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/stile.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/superscript-b.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/thorn.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/tilde-diaeresis.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/tilde.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/times.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/up-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/up-down-arrow.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/up-shoe.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/up-tack.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/vee-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/vee.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/wedge-bar.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/wedge.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs/zilde.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs-study.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/glyphs.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/hanzi-notation-zh.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/hanzi-notation.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/index.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/indexing.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/keyboard.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/keyed.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/nbdev.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/numbers.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/overview.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/papers/aplwiki-arrays.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/papers/brickman-depth-1-scalars.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/papers/mercer-based-system.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/gallery.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/monaco-worker.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/page.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground/worker.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/playground.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/plot.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/principles.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/processes.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/puppy.jpg +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/regex.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/repl.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/scripts.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/sidebar.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/strings.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/02_functions.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/03_operators.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/04_nested-arrays.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/05_searching-indexing.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/06_rearranging-arrays.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/study/07_numerical-tools.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/style.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/styles.css +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/syntax.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/_metadata.yml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/c.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/canvas.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/constants.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/copy.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/csv.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/date.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/decompose.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/deflate.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/delay.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/detach.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/distribution.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/edge.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/element.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/ex.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/fetch.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/float.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/hash.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/host.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/image.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/index.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/js.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/json.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/literal.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/load.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/memory.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/metadata.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/mime.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/mkdir.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/nget.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/nl.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/normalize.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/nput.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/path.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/plot.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/prefs.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/r.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/rand.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/readdir.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/remove.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/rename.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/signal.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/src.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/storage.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/svg.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/time.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/ucs.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/uuid.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/vfi.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system/xml.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/system-functions.qmd +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/web.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/nbs/xml.ipynb +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/package-lock.json +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/package.json +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/README.md +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/aplcart.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/april.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/bqn.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/core.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/dyalog.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/provenance/ngn.jsonl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/py/Cargo.toml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/py/build.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/pyproject.toml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/_modidx.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/dyalog.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/font.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/fonts.css +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/input.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/ipython.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/keyboards.json +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/keyboards.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/layout.json +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/lb.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/notebook_runner.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/notebooks.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/reference.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/syntax.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/windows_keyboard.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/python/basedpl/worker.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/rustfmt.toml +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/scripts/install-macos.sh +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/scripts/prep.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/canvas.js +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/canvas.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/csv.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/date.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/element.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/error.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/execution.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/fusion/blocks.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/host.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/host_web.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/image/codecs.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/image/imageio.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/inspection.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/json.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/number_theory.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/optimize.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/plot.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/polynomial.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/primitive/indexing.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/protocol.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/regex.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/search.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/settings.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/symbols.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/src/xml.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/common/mod.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/conftest.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/core.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/derivatives.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/input.mjs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-aplcart +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-april +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-bqn +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-bqncrate +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-dyalog +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/LICENSE-ngn +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/aplcart.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/april.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/bqn.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/distributions.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/dyalog.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/graphics.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/lib.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/ngn.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/regex.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/static-int32.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/static.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/support/april.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/support/avl.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/support/redblack.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/support/sbst.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/reference/support/splay.bpl +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/settings.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_basic.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_bpltests.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_glyphs.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_graphics.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_ipython.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_kernel.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_keylayout.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_notebooks.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_reference.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_repl.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_windows_keyboard.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/test_worker.py +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/units.rs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/wasm-pkg.mjs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/wasm-speed.mjs +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/tests/windows_keyboard.c +0 -0
- {basedpl-0.1.63 → basedpl-0.1.64}/wheel/data/share/jupyter/kernels/bpl/kernel.json +0 -0
|
@@ -93,7 +93,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
|
|
|
93
93
|
|
|
94
94
|
[[package]]
|
|
95
95
|
name = "basedpl"
|
|
96
|
-
version = "0.1.
|
|
96
|
+
version = "0.1.64"
|
|
97
97
|
dependencies = [
|
|
98
98
|
"base64 0.23.1",
|
|
99
99
|
"bytemuck",
|
|
@@ -137,7 +137,7 @@ dependencies = [
|
|
|
137
137
|
|
|
138
138
|
[[package]]
|
|
139
139
|
name = "basedpl-cli"
|
|
140
|
-
version = "0.1.
|
|
140
|
+
version = "0.1.64"
|
|
141
141
|
dependencies = [
|
|
142
142
|
"async-trait",
|
|
143
143
|
"basedpl",
|
|
@@ -150,7 +150,7 @@ dependencies = [
|
|
|
150
150
|
|
|
151
151
|
[[package]]
|
|
152
152
|
name = "basedpl-py"
|
|
153
|
-
version = "0.1.
|
|
153
|
+
version = "0.1.64"
|
|
154
154
|
dependencies = [
|
|
155
155
|
"basedpl",
|
|
156
156
|
"num-bigint",
|
|
@@ -165,7 +165,7 @@ dependencies = [
|
|
|
165
165
|
|
|
166
166
|
[[package]]
|
|
167
167
|
name = "basedpl-wasm"
|
|
168
|
-
version = "0.1.
|
|
168
|
+
version = "0.1.64"
|
|
169
169
|
dependencies = [
|
|
170
170
|
"basedpl",
|
|
171
171
|
"js-sys",
|
|
@@ -1413,9 +1413,9 @@ dependencies = [
|
|
|
1413
1413
|
|
|
1414
1414
|
[[package]]
|
|
1415
1415
|
name = "rustymath"
|
|
1416
|
-
version = "0.1.
|
|
1416
|
+
version = "0.1.42"
|
|
1417
1417
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1418
|
-
checksum = "
|
|
1418
|
+
checksum = "111e9789646e0ba43eddc96c9cfdf41adaed3070d1a6c13b3153696a0f557f09"
|
|
1419
1419
|
dependencies = [
|
|
1420
1420
|
"foldhash",
|
|
1421
1421
|
"half",
|
|
@@ -1429,13 +1429,14 @@ dependencies = [
|
|
|
1429
1429
|
"rand",
|
|
1430
1430
|
"rayon",
|
|
1431
1431
|
"strength_reduce",
|
|
1432
|
+
"web-time",
|
|
1432
1433
|
]
|
|
1433
1434
|
|
|
1434
1435
|
[[package]]
|
|
1435
1436
|
name = "rustymath-buffer"
|
|
1436
|
-
version = "0.1.
|
|
1437
|
+
version = "0.1.42"
|
|
1437
1438
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1438
|
-
checksum = "
|
|
1439
|
+
checksum = "3a1accc013378abf14e1a2001dcfd326963eaf5751ed2e3eebd0e851e5dd46f9"
|
|
1439
1440
|
dependencies = [
|
|
1440
1441
|
"pyo3",
|
|
1441
1442
|
"rustymath",
|
|
@@ -1699,9 +1700,9 @@ dependencies = [
|
|
|
1699
1700
|
|
|
1700
1701
|
[[package]]
|
|
1701
1702
|
name = "tokio"
|
|
1702
|
-
version = "1.54.
|
|
1703
|
+
version = "1.54.1"
|
|
1703
1704
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1704
|
-
checksum = "
|
|
1705
|
+
checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3"
|
|
1705
1706
|
dependencies = [
|
|
1706
1707
|
"bytes",
|
|
1707
1708
|
"libc",
|
|
@@ -2085,7 +2086,7 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
|
|
2085
2086
|
|
|
2086
2087
|
[[package]]
|
|
2087
2088
|
name = "xtask"
|
|
2088
|
-
version = "0.1.
|
|
2089
|
+
version = "0.1.64"
|
|
2089
2090
|
dependencies = [
|
|
2090
2091
|
"anyhow",
|
|
2091
2092
|
"rustymath",
|
|
@@ -5,14 +5,14 @@ members = ["py"]
|
|
|
5
5
|
join_comments = true
|
|
6
6
|
|
|
7
7
|
[workspace.package]
|
|
8
|
-
version = "0.1.
|
|
8
|
+
version = "0.1.64"
|
|
9
9
|
edition = "2024"
|
|
10
10
|
rust-version = "1.98"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
|
|
13
13
|
[workspace.dependencies]
|
|
14
|
-
rustymath = { version = ">=0.1.
|
|
15
|
-
rustymath-buffer = ">=0.1.
|
|
14
|
+
rustymath = { version = ">=0.1.42, <1", default-features = false }
|
|
15
|
+
rustymath-buffer = ">=0.1.42, <1"
|
|
16
16
|
pyo3 = ">=0.29.2, <1"
|
|
17
17
|
pyo3-build-config = ">=0.29.2, <1"
|
|
18
18
|
|
|
@@ -28,15 +28,19 @@ An already-running Python process retains its loaded extension. In a kernel, use
|
|
|
28
28
|
|
|
29
29
|
Measure with `BASEDPL_COSTS=1 cargo test --test speed` or `basedpl.bpltests.time_cases(cases)`. Both count costs in copies. A copy is the time to write as many floats as the data has items, each negated, into a second buffer. Budgets are single-thread measurements. Use `time_cases(..., threads=...)` separately for scaling. `speed_costs()` reads the cases in `tests/speed.txt`. `cases=` selects expressions, `wasm=DIR` selects a browser build, `bpl=PATH` selects another native `bpl`, such as a saved copy, and `native=True` times rustymath's own linear algebra, which dev builds compile in. `logged_costs(log)` reads CI output. `cargo_costs(path)` runs either project's Rust speed test, and `pytest_costs(path)` runs rustymath's Python speed test.
|
|
30
30
|
|
|
31
|
-
Costs in copies can't show a per-call change of a few percent, because code layout alone moves a timing by more than that. `instructions(cases)` counts instructions, which load and layout don't change. Each case is BPL that makes one call per step of `N`, such as `{⍵}⍣N⊢0`. A map such as `f¨N⍴0` calls a dfn once on all its cells, so it gives no per-call cost. It runs fresh single-threaded `bpl` processes at
|
|
31
|
+
Costs in copies can't show a per-call change of a few percent, because code layout alone moves a timing by more than that. `instructions(cases)` counts instructions, which load and layout don't change. Each case is BPL that makes one call per step of `N`, such as `{⍵}⍣N⊢0`. A map such as `f¨N⍴0` calls a dfn once on all its cells, so it gives no per-call cost. It runs fresh single-threaded `bpl` processes at four values of `N`. For each pair of successive values, it divides the difference in instructions retired by the difference in `N`, which cancels startup and `setup=`, and it reports the median of those three slopes. The median drops a one-off cost that starts once `N` passes some size, because such a cost falls between only one pair. `≢•ucs N⍴"ab" "cde"` has one: it retires about 5×10⁶ more instructions from about 131,350 items on. Every value of `N` lies past the warm-up, from a rough count at 1,000 steps, because a case that allocates an array at each step retires extra instructions over its first steps while the allocator settles. Each process pays a different warm-up, up to about 5×10⁶ instructions, so successive values of `N` lie 5×10⁸ instructions apart, where that difference moves a slope by under 1%. `counts=` sets two or more values instead. It reads `/usr/bin/time -l` on macOS and `perf stat` on Linux, and `bpl=PATH` counts a saved copy.
|
|
32
32
|
|
|
33
|
-
`
|
|
33
|
+
`tests/instructions.txt` holds the instructions that each case retires for each step, as counted on macOS on Apple silicon. Most cases make one call per step, from `{⍵}⍣N⊢0` to `fib`. Three map a function over the same 64 cells each step, through Each, Rank's general path and a system function's own item map. `instruction_budgets()` counts each case through `instructions` and marks a case `over` when it retires more than 3% above its count, and `stale` when it retires more than 3% below it. `tests/test_instructions.py` fails on either mark, and skips on other platforms. The change that makes a call cheaper also lowers each count it moves. A new compiler version can inline differently and move the counts, and then they're set again from `bpl-tests instruction_budgets`. CI checks only the speed budgets.
|
|
34
|
+
|
|
35
|
+
When a count moves, `profile_diff(case, base)` shows which functions moved it, on macOS. For each build, a fresh process repeats the case on one thread while `sample` counts how often each function is at the top of the main thread's stack. A function's share of those samples, times the build's count from `instructions`, estimates its instructions per step. The estimate assumes every function retires instructions at the same rate. A function that one build inlines and the other calls out of line appears under one build alone. Run it before reading machine code. `base` is a saved copy, and `bpl=PATH` sets the other build, the installed one by default.
|
|
36
|
+
|
|
37
|
+
`bpl-tests NAME ARGUMENT...` runs one of these functions from the shell and prints its result: `check_file`, `check_page`, `time_cases`, `instructions`, `instruction_budgets`, `profile_diff`, `speed_costs`, `cargo_costs`, `pytest_costs` or `wasm_test`. Run long checks and timings this way, not in the shared kernel, which runs one cell at a time for every agent. For example, `bpl-tests time_cases '+/v' --threads 4` times `+/v` on four threads. `time_cases`, `instructions` and `speed_costs` take cases as positional arguments. When a case starts with `-`, put the cases last, after `--`, as in `bpl-tests speed_costs -- '-.×m' '+/v'`. `bpl-tests NAME -h` lists a function's arguments.
|
|
34
38
|
|
|
35
39
|
On each push, the `Test` workflow logs every native cost in its `test` job and every wasm cost in its `wasm` job. The speed test that writes them times the test-profile build that the budgets limit. `bpl --costs FILE` times the cases in a file in `speed.txt`'s format as the speed test does, and prints each cost with this machine's budget, without failing on a budget. The manual `Speed` workflow runs it on a `dist` build, the profile releases use, on CI's runner, beside its wasm timing. The `Release` workflow runs it on each binary it builds, on GitHub's runners. Their logs show what releases cost, for comparison with the `Test` workflow's. `logged_costs` reads all three workflows' logs. When you review a run, look for costs over their budgets and for costs that changed by more than 20%. Study a slowdown until you know its cause only when it appears in more than one CI run, or when two or more similar cases slow by similar amounts. Treat any other slowdown as normal variation.
|
|
36
40
|
|
|
37
41
|
An initial budget is twice what a first-principles analysis says the case should cost, as each budget file's header says. A later budget comes from a fuller understanding of the case than that analysis gives, such as a platform difference or a cost the analysis missed, and the case's comment records it. A case over its budget needs study, which finds either a speed bug to fix or something the analysis missed. Avoid raising a budget to match a run without understanding why the case costs what it does. Each case line in a budget file holds a native budget for macOS on Apple silicon, then one for Linux on CI's x86 runner, then, in basedpl's file, a wasm budget. One expected cost serves every platform at first, until a specific difference on one platform is found. macOS running matrix products and decompositions on Accelerate, where CI runs rustymath's own kernels, is such a difference. A comment above each case, or above its group, gives the expected cost with its reason, and any platform's own cost with the reason for it. `set_budgets(expected)` writes the budgets for the cases that `expected` names, a dict from each case's code to its expected cost. `builds=` limits the change to one platform's column, for a cost that differs there. A case can appear in more than one section, such as `[copies]` and `[widths]`. `sections=` limits the change to the sections it names. `path=` selects one of rustymath's budget files, `tests/speed.txt` or `tests/speed_python.txt`.
|
|
38
42
|
|
|
39
|
-
`tests/explain.rs`'s `speed_cases_take_their_routes` runs each speed case once more, after a warm-up run, as `•explain` runs its text (`timing::routes`). It fails on any slow-path event that the case's lines don't name: a pending array that a fused group computed on its own (`stored`), a call that computed pending items (`forced`), a batched map's fallback (`fallbacks`), a write that left an array mixed (`mixed`), or a route that handled items one at a time (`itemwise`). A line above a case names one event, as `•explain`'s record names it: the function for `forced`, the reason for `stored` and `fallbacks`, the code for `mixed` and the route for `itemwise`. `# allows RECORD "EVENT": principle` names an event that a principle allows, such as a matrix product reading its arguments whole. `# gap RECORD "EVENT": what should happen` names an event that a faster route should remove, and the test prints these gaps, which `cargo test -- --nocapture` shows. Any other event is a route to study, as a case over its budget is: add an `allows` line only for a principle, and a `gap` line once the study finds what should happen. The test also fails on a line whose event no longer appears, so a fixed gap's line goes.
|
|
43
|
+
`tests/explain.rs`'s `speed_cases_take_their_routes` runs each speed case once more, after a warm-up run, as `•explain` runs its text (`timing::routes`). It fails on any slow-path event that the case's lines don't name: a pending array that a fused group computed on its own (`stored`), a call that computed pending items (`forced`), a batched map's fallback (`fallbacks`), a write that left an array mixed (`mixed`), or a route that handled items one at a time (`itemwise`). A line above a case names one event, as `•explain`'s record names it: the function for `forced`, the reason for `stored` and `fallbacks`, the code for `mixed` and the route for `itemwise`. A faster route that code considered and didn't take is a decline (`declined`), named by its route and reason, as in `fusion: an exact argument`. A case needn't name a decline, because each one explains another event, but a `gap` line can name one to record why the fast route was refused. Code in either repository reports a decline through `rustymath::events::declined`, which costs one atomic load unless `•explain` runs. `# allows RECORD "EVENT": principle` names an event that a principle allows, such as a matrix product reading its arguments whole. `# gap RECORD "EVENT": what should happen` names an event that a faster route should remove, and the test prints these gaps, which `cargo test -- --nocapture` shows. Any other event is a route to study, as a case over its budget is: add an `allows` line only for a principle, and a `gap` line once the study finds what should happen. The test also fails on a line whose event no longer appears, so a fixed gap's line goes.
|
|
40
44
|
|
|
41
45
|
The speed tests and the scaling test time each failing case again after the rest, after each pause in `rustymath::timing::RETRY_PAUSES`, and fail only for a case that fails every time. Each retry prints the case's earlier and new costs, even in a passing run. `logged_costs` keeps a retried case's lowest cost. Study a case that needs a retry in most runs, as you would a slowdown.
|
|
42
46
|
|
|
@@ -86,7 +90,7 @@ Use published dependency ranges with the lower bounds required by the APIs in us
|
|
|
86
90
|
|
|
87
91
|
LTO-off incremental builds keep an edit from recompiling every caller that inlined it. Measured on 18 October 2026 in a local incremental build, thin-local LTO doubled the rebuild after a one-line edit that recompiles large units, from about 8 s to about 18 s, cut the calls from `Steps::combined` into other units from 21 to 8, and moved the speed cases by 5% or less. Moving lines changes the code below them, because each panic site, such as a bounds check, holds its line. Every unit that holds that code then recompiles. Related source is split into child modules to limit those shifts. For example, `fusion/blocks.rs` holds the generic block runner of `fusion.rs`. After a one-line edit to `Graph::run`, the rebuild recompiles one unit of about 140 KB and takes about 2.4 s. It took about 9 s when the runner sat below it in the same file. Children use `use super::*` and expose items to parents and siblings with `pub(super)`. Parents own public re-exports.
|
|
88
92
|
|
|
89
|
-
Generic loop instances can concentrate in the defining module's codegen unit. A closure passed to a generic adapter such as `map` makes an instance that can compile in another codegen unit. Every edit to the closure's function then recompiles that unit. When `Graph::run` built a vector with `map`, an edit to it recompiled a 1.9 MB unit in about 8 s. It now uses a plain loop. Mark loop helpers `#[inline]` when their instances need to compile with the caller's kernel table, including nested helpers. Kernel tables have separate modules: `booleans`, `wholes`, `
|
|
93
|
+
Generic loop instances can concentrate in the defining module's codegen unit. A closure passed to a generic adapter such as `map` makes an instance that can compile in another codegen unit. Every edit to the closure's function then recompiles that unit. When `Graph::run` built a vector with `map`, an edit to it recompiled a 1.9 MB unit in about 8 s. It now uses a plain loop. Mark loop helpers `#[inline]` when their instances need to compile with the caller's kernel table, including nested helpers. Kernel tables have separate modules: `booleans`, `wholes`, `float_kernels` and `complex_kernels`. `at_widths!` gives the concrete widths their own modules. Keep new tables separate and add kernel specializations only for measured gains.
|
|
90
94
|
|
|
91
95
|
Use `cargo build --lib --bins --profile test --timings` to inspect the normal build. Its report under `target/cargo-timings/` separates frontend and codegen time. `BASEDPL_UNITS=1 cargo test --test units -- --nocapture` lists large units and their functions. `BASEDPL_SIZES=pattern cargo test --test units -- --nocapture` measures machine code matching a demangled-name regex. `BASEDPL_SIZES` sees only basedpl's own codegen units. `BASEDPL_SIZES_DIFF=old:new cargo test --test units machine_code_growth -- --nocapture` compares two binaries, such as copies of `bpl` from before and after a change, by generic function across every crate. `BASEDPL_CALLS=pattern cargo test --test units -- --nocapture` lists each call from a function whose demangled name matches to a function in another codegen unit, in basedpl's build and in the rustymath rlib it links. LLVM can't inline those calls in this profile. rustymath's DEV.md gives the cause, under "Loops and codegen". After an edit, `BASEDPL_RECOMPILED=pattern cargo test --test units -- --nocapture` lists the units that the rebuild compiled again, each with its biggest functions whose demangled names match. These commands diagnose the current compilation arrangement; don't create scratch builds to approximate it.
|
|
92
96
|
|
|
@@ -94,8 +98,8 @@ Use `cargo build --lib --bins --profile test --timings` to inspect the normal bu
|
|
|
94
98
|
|
|
95
99
|
| Files | Responsibility |
|
|
96
100
|
|---|---|
|
|
97
|
-
| `syntax.rs`, `eval/binder.rs`, `eval/tree.rs` | Structural parse, runtime category binding, trains, dot access and subscripts, and
|
|
98
|
-
| `eval.rs`, `eval/session.rs`, `eval/operators.rs`, `eval/idioms.rs`, `eval/assign.rs` | Shared calls, sessions/modules, operators, fast combinations, scopes and assignments. |
|
|
101
|
+
| `syntax.rs`, `name.rs`, `eval/binder.rs`, `eval/tree.rs` | Structural parse, interned names, runtime category binding, trains, dot access and subscripts, and dfn statements' compiled recordings. |
|
|
102
|
+
| `eval.rs`, `eval/session.rs`, `eval/bindings.rs`, `eval/operators.rs`, `eval/idioms.rs`, `eval/assign.rs` | Shared calls, sessions/modules, binding storage, operators, fast combinations, scopes and assignments. |
|
|
99
103
|
| `execution.rs`, `error.rs` | Cancellation, deadlines, input/output and retained diagnostics. |
|
|
100
104
|
| `array.rs`, `array/storage.rs`, `array/text.rs` | Values, layouts, compact/mixed storage, gathering and source formatting. |
|
|
101
105
|
| `agreement.rs`, `keyed.rs`, `selection.rs` | Rustymath's broadcasting `Agreement` with basedpl's layouts and their renderer, reading paired items, named/keyed alignment, and selection/writeback. |
|
|
@@ -116,27 +120,35 @@ User-facing language rules belong in `nbs/syntax.qmd`, `evaluation.qmd`, `number
|
|
|
116
120
|
|
|
117
121
|
## Parser, evaluator and scopes
|
|
118
122
|
|
|
119
|
-
The lexer/parser records byte spans and structural syntax without evaluating expressions. `parse` distinguishes complete input, incomplete input and errors. It reads numbers under the
|
|
123
|
+
The lexer/parser records byte spans and structural syntax without evaluating expressions. `parse` distinguishes complete input, incomplete input and errors. It reads numbers under the current settings, which are process-wide (`settings.rs`). `Session::parse` passes the parser the `hanzi_aliases` setting. `syntax_tree` supplies source tools with structural nodes and recovers invalid chunks as `Error` nodes. `highlight` shares the lexer.
|
|
120
124
|
|
|
121
125
|
`symbols.rs` owns APL, simplified and traditional Hanzi spellings. Its rows also hold each glyph's names: a glyph name for the character, which is also its page's file name in `nbs/glyphs/`, and a name for each valence, or one name where both valences do the same thing. The glyph reference, named entry, help and Python's exported names all read them there. `hanzi_aliases` enables Hanzi glyph spellings, canonicalizing token decisions while retaining original source and spans. Other Hanzi remain name characters. `_` quotes the next non-whitespace character into a name, including a glyph alias. The `notation` preference affects structured function/operator display, not stored source, serialization or structural APIs; help and editor metadata use the same spelling table.
|
|
122
126
|
|
|
123
|
-
The binder resolves runtime categories right to left. It owns unfinished strands, trains and bound arguments; shared function nodes are immutable. Grammatical reduction produces application requests instead of calling functions. Primitive/operator rows own names, operand kinds, ranks, pervasion, axis behaviour and reduction identities. Change those rows instead of duplicating metadata in consumers. A non-extending primitive above its natural ranks runs through Rank; pervasive Each/Outer/Rank paths reuse whole-array kernels.
|
|
127
|
+
The binder resolves runtime categories right to left. It owns unfinished strands, trains and bound arguments; shared function nodes are immutable. Grammatical reduction produces application requests instead of calling functions. An array that holds a function as an item has its own binder category, `Callable` (`Category::bound`), while `Category::of`, which assignment's grammar reads, keeps it `Value`. `Binder::push` works out each entity's role once, as it pushes it: `Category::before` resolves `Callable` against the role of the entity below, which is to its right, to `Function` where that entity is a subject or an absent `⍺`, and to `Value` otherwise. `Rule::get` and the strengths don't change, and recordings check `Callable` as a category of its own. A function-only operand slot converts such an array to `FunctionNode::Array` in `constant_operand`, and `Function::from_value` makes the same conversion where a call by text needs a function. Primitive/operator rows own names, operand kinds, ranks, pervasion, axis behaviour and reduction identities. Change those rows instead of duplicating metadata in consumers. A non-extending primitive above its natural ranks runs through Rank; pervasive Each/Outer/Rank paths reuse whole-array kernels.
|
|
124
128
|
|
|
125
129
|
Dot names rewrite to Pick, and dot brackets/subscripts to selection. `ⱼ`, `ₑ` or `ᵣ` between two arrays then rewrites to the primitives it stands for, as `xⱼy` to `x+y×0ⱼ1` (`syntax::joined_term`). Dot parentheses evaluate a namespace: `T.(expr)` and `T⍎text` bind each key on the first axis of `T` to its item or major cell as a local, resolve other names in the caller and keep assignments local. They share the scoped execution route and lexical lifetime checks. Between functions, dot remains inner product.
|
|
126
130
|
|
|
127
|
-
Lexical frames use non-owning parent indices. Closures see live bindings, not snapshots. Plain assignment is local; modified/selective assignment updates the nearest existing binding. Retain the resolved
|
|
131
|
+
`Bindings` (`eval/bindings.rs`) holds every binding: the frames of running calls and scopes, each module's names, the current frame and the running module. Other code reads and writes bindings only through its methods. A lookup gives where a name is bound, as a `Place`, with its binding, and reads, writes and removals take a `Place`. `Bindings::here` gives the place where a plain assignment binds a name. Parsing interns each name as a `Name` (`name.rs`), a number that is the same in every session, and a name becomes text again only where text comes in or goes out. Each frame has slots on one stack that every frame shares: first one for each of the six names that a call binds itself, then one for each of a dfn's locals, the names before an `←` in its statements (`Definition::locals`). A call allocates nothing for its names. A call with no left argument binds `⍺` to an absent argument, so lookup finds the call's own `⍺` and never an outer frame's. A name without a slot, such as one that `⍎` binds or an assignment in a scope binds, goes in its frame's side map. A scope's frame holds its record, and a lookup that the side map misses there reads a key through the record's own index of its keys (`Keys::position`), so a scope copies nothing and a key's text never becomes a `Name`. Each module keeps its names as entries that an index finds, and deleting a name empties its entry without moving the others. A compiled read of a name carries an address (`Bindings::address`): the slots on its lexical chain that can hold it, and its module's entry. It reads through `Bindings::load`, which looks the name up as an uncompiled read does where a frame on the chain binds names without slots or the running module isn't the recorded one. Lexical frames use non-owning parent indices. Closures see live bindings, not snapshots. Plain assignment is local; modified/selective assignment updates the nearest existing binding. Retain the resolved place and original array across modifier calls rather than looking the name up again. Returns and outer writes reject functions, including those nested in arrays/prototypes, whose frames would not survive. Tail calls retain dependencies from arguments and the called function. No collector is used; recheck this lifetime reasoning before permitting escaping lexical captures.
|
|
128
132
|
|
|
129
133
|
Module 0 owns session names. Each `•load` runs in a new module, without the caller's frame and with echo off, and returns its non-private names alphabetically. Modules remain for the session's lifetime. Recursive loading of a canonical path is a DOMAIN error. Paths starting `./` or `../` resolve against the source file; other paths use the working directory. Execute/load do not run the top-level preference header.
|
|
130
134
|
|
|
131
135
|
Dfns run statements in order and return the last statement's value. Final assignments are silent. An absent left argument propagates through the binder's absent-binding rules; default-left assignment runs only when needed. Guard handlers see bindings as they stood at failure; nothing rolls back. Wildcard `∞::` excludes interrupt, timeout and unsupported errors. Explicit named guards can catch them; catching an interrupt clears its flag.
|
|
132
136
|
|
|
133
|
-
The binder
|
|
137
|
+
The binder compiles a dfn statement on the statement's first evaluation (`eval/tree.rs`). Its recorder follows the binder's two stacks over registers and constants, and emits an instruction for each node that needs evaluating and for each reduction. A move between the stacks and the drop of an absent `⍺` compile to nothing, and a derive or a bind on constants compiles to a constant, so an operator bound to a constant operand, as in `⍤1`, derives once. Later evaluations run the instructions: they make the same calls in the same order, checking the category of each name, group and call result against the recorded one. Each checked instruction keeps a template of the binder's state at that point: what its two stacks hold, its cursor, the leaf it had just resolved or the result it had just pushed, and the assignment it was making. Where a category differs, the binder carries on from that state (`Binder::resumed`). Registers hold the binder's own entities (`binder::Entity`), in an inline array of 8 (`INLINE`) or on the heap for a statement that needs more. The recording keeps its constants as entities, and an instruction borrows them, so a call reads a constant's array or function without copying it (`array_of`, `function_of`). The binder evaluates a statement every time when the statement selects. The parse tree depends on the evaluator, because each `syntax::Statement` holds its own recording. A change to a reduction that the binder records (a drop, a strand, an attach, a call, a derive, a bound right operand or a train) must change the recorder and the instructions too. `strand`, `attached`, `split_call`, `derived`, `bound_right`, `train` and `tails` in `eval/binder.rs` serve both, and the binder tells the recorder its cursor and whether a call is its last reduction. The `_ => rc.fail()` arm in `Binder::reduce` stops recording any statement with a reduction that the instructions don't cover. The binder then evaluates that statement correctly every time.
|
|
138
|
+
|
|
139
|
+
Each group or run in the statement is a level, whose instructions sit inline between an `Enter` and an `Exit`, so one loop runs the statement. The recorder writes a level's instructions straight into the statement's as the binder evaluates the level, keeping a mirror of the level's binder (`tree::Walk`) while it runs. A failed check resumes the binder of the level that holds the instruction. Where the group's value keeps its recorded category, the instructions after its `Exit` carry on. Otherwise the level that holds it resumes, and so on out to the statement. Dot access, subscripts, joiners and runs that start with an operator rewrite a statement before the binder walks it (`Session::joined`, `Session::members`), and the recording keeps the rewritten nodes. Whether a rewrite applies, and whether a run starts with an operator or ends in a dyadic one, depend on what names hold, which one reader reads without evaluating anything (`Session::static_category`): a name by its binding, a dot path by its field, and any other group by the operand grammar of assignment targets (`assignment_operand`). While a statement records, the reader keeps a fact for each name or dot path it read, with the name's address and the category it found (`tree::Fact`). A recording checks a level's facts again when the level starts, and the binder evaluates the statement or group from its own nodes where one differs. A run that ends in a dyadic operator is a level whose binder starts with the run's right operand on its stack, read where the level that holds it keeps it.
|
|
140
|
+
|
|
141
|
+
A group or run whose leaves are all literals, primitives, operator glyphs or such groups, and which makes no call, records as the array or function it gave, so a train like `(+/÷≢)` builds once. The recorder drops such a group's instructions by truncating the statement's back to where the group started (`Recorder::truncate`). A run that ends in a dyadic operator, whose right operand is constant, records as a constant too. A group whose value is a train with a computed tine exits with the train's tines (`Term::Tines`). A call of that group calls the tines in place (`Op::CallTines`, `operators::train_call`). The call builds the train and calls it instead in three cases: while a transformation or `•explain` runs, where two array tines are side by side, and where the last tine orders its argument (`idioms::orders`).
|
|
142
|
+
|
|
143
|
+
An assignment compiles to one instruction, which runs `Session::assigned`, the step after the target is found that the binder runs too: `Session::assign`, the one home of every target form, or a store of a plain name straight into the frame's slot for it, which `Bindings::here` found when the statement compiled. What a target's names hold decides where a target of more than one node starts (`Session::assignment_start`), so the instruction checks that start again, and the binder carries on with the assignment in progress where it moved. A default argument, an error guard's kinds and a dfn's last statement compile as other statements do.
|
|
144
|
+
|
|
145
|
+
Each item of a bracket literal is a level whose value goes into the literal at once, as `Session::item_result` converts it, and `Session::bracket` builds the literal for `resolve` and for the compiled `Array` instruction alike. A literal with a computed key that isn't constant stays with `resolve`. Each statement keeps the recording of its first evaluation (`Statement::recording`). A later call whose `⍺` is absent where that evaluation's held an argument, or the reverse, resumes the binder where the statement reads `⍺`.
|
|
134
146
|
|
|
135
|
-
Tail calls reuse frames while preserving lexical dependencies. Handlers disable tail reuse.
|
|
147
|
+
Tail calls reuse frames while preserving lexical dependencies. Handlers disable tail reuse. Evaluation depth is capped at 20,000 natively and at 346 in the browser, whose stack runs out first. Each call of a function other than a primitive counts toward it, and so do each statement of a dfn other than its last, each group, each run that ends in a dyadic operator and each bracket item, compiled or not. A compiled statement or level counts with `Session::descend` alone, without the interrupt check and stack growth of `Session::nested`. Calls of primitives other than `⍎` don't count, because a primitive never calls back into BPL. They skip the depth, capture and stack bookkeeping, and on numbers a form that applies a kernel to each pair of items runs that kernel at once (`Primitive::scalar_call`). A separate 20,000-frame limit bounds retained lexical frames. Late-bound name resolution stops at 128 levels. These are execution limits, not a sandbox against arbitrarily deep source, arrays or function graphs.
|
|
136
148
|
|
|
137
149
|
## Values, layouts and assignment
|
|
138
150
|
|
|
139
|
-
`Value` holds a number, character, function, operator or shared array. Compact storage holds a rustymath `buffer::Buffer` of Booleans, narrow integers, width-specific floats or complex numbers, or characters, all of one dtype, and `Items` borrows it as a `buffer::View`. BPL's promotion rules for those dtypes stay in basedpl, as `Promotion` in `array/storage.rs`. A rustymath buffer keeps the dtype it's given, and basedpl picks an integer's width from its values. Mixed storage holds `Value`s and memoizes its prototype
|
|
151
|
+
`Value` holds a number, character, function, operator or shared array. Compact storage holds a rustymath `buffer::Buffer` of Booleans, narrow integers, width-specific floats or complex numbers, or characters, all of one dtype, and `Items` borrows it as a `buffer::View`. BPL's promotion rules for those dtypes stay in basedpl, as `Promotion` in `array/storage.rs`. A rustymath buffer keeps the dtype it's given, and basedpl picks an integer's width from its values. Mixed storage holds `Value`s and memoizes its prototype, its innermost lexical dependency and whether any item is a function. Other properties are computed when needed. An array holds its layout and its storage in one allocation. Its `Shape` holds ranks 0 to 2 inline, so a small array allocates no shape. Constructors take `impl Into<Shape>`: pass a slice, or an array such as `[n]`, rather than building a `Vec`. A shape, key or name change on a shared array makes a view of the base array's storage and copies no items. A large result of a fusible float call holds a pending call in place of its storage, and computes the storage on the first read (`fusion.rs`). `Value::view` and `imported_buffer` are the public width-preserving frontend boundary. They give and take rustymath's `View` and `Buffer`, which basedpl's API re-exports as `basedpl::buffer`.
|
|
140
152
|
|
|
141
153
|
Atoms, rank-0 arrays and singleton vectors are distinct. Function nodes retain handles, not lexical frames or Python objects. Functions match by their parts; dfns and generators match by identity. Operators can be values and can cross the native Python boundary. Values and function nodes are `Send + Sync`.
|
|
142
154
|
|
|
@@ -152,7 +164,7 @@ Selective assignment removes the binding before writing. `Arc::make_mut` copies
|
|
|
152
164
|
|
|
153
165
|
Each, Rank and outer products call their operand through `each_pair` in `eval/operators.rs`. It first tries one batched call (`batch::tried`), then calls the operand once for each cell and assembles the results through shared layout and prototype rules. A 0-cell preserves an atom or encloses an array item. For custom operands, empty Each, Rank and outer product calls substitute prototypes for empty arguments and use prototype mode. Explicit effects remain observable when a call runs. Catchable prototype-call failures produce prototype zero, but interrupt, timeout and unsupported errors propagate. Restore prototype mode on success and error. A stencil runs as Rank over `↕`'s windows, and reads its specification through `↕`'s `WindowSpec` (`primitive/structural.rs`).
|
|
154
166
|
|
|
155
|
-
Rank tries `whole` before `each_pair`. `whole` calls the operand once where neither argument has a frame. It then tries `decomposed`, for `•decompose⍤2` on a stack of matrices, and `whole_cells` for a primitive or a product. `whole_cells` holds Rank's routes for whole arguments, which batched calls share (`batch::whole_call`). In order, they are `primitive::stacked`'s
|
|
167
|
+
Rank tries `whole` before `each_pair`. `whole` calls the operand once where neither argument has a frame. It then tries `decomposed`, for `•decompose⍤2` on a stack of matrices, and `whole_cells` for a primitive or a product. `whole_cells` holds Rank's routes for whole arguments, which batched calls share (`batch::whole_call`). In order, they are `primitive::stacked`, which runs `⌹` and `-.×` on stacks of inexact matrices through rustymath's `linalg::Stacked`, as rustymath's Python API runs them, and every `f.g` that rustymath has a product kernel for, on compact stacks of any item kind, through `linalg::Product` (an exact product that doesn't fit 64 bits keeps the call for each cell, which computes exactly), one padded call of a pervasive primitive (`padded_call`), `primitive_cells` for a primitive with one argument or with a left argument that every cell shares, and `paired_cells` for a primitive whose arguments' frames match or whose right argument every cell shares. An argument with no axes besides its cells' is the same in every cell. After `whole_cells`, `whole` tries `pervasive_cells`, for a pervasive primitive under nested Rank, and then, for a monadic operand, `cell_rule`, which also takes folds, atops and a bound left argument. `primitive_cells` runs a primitive on the whole argument along the cells' axes. A form that `extends` runs whole at a cell rank at least its own. Other forms follow the `cells` fact (`CellRule`) in their row of `Primitive::info()`. With it, `⊖ , ↑ ↓ ⌷ #` and rotate-first call their axis forms, `⍉` sends each cell's axes after the frame's, `≢` and `⍴` give constants, and a reshape that keeps a cell's items in order is a view. Any other form with a left argument that every cell shares takes `paired_cells`. `paired_cells` joins each pair of cells for `,` and `⍪`, and calls a form that extends once where both cells are at least its ranks. It first repeats an argument that every cell shares over the frame (`agreement::spread`). A pervasive primitive folds or scans a simple array along the cell's axis (`folded_cells`). `f/∘,` folds all the cell axes at once. An atop applies its inner function's rule, then Rank for its outer function. Each rule applies only where Rank's mix of the cells' results gives what the whole-array call gives. Nested results, and folds by other functions, keep the call for each cell.
|
|
156
168
|
|
|
157
169
|
Axis nodes select/move axes and reuse Rank when the function has no direct axis meaning. Vector-axis reduction uses the general composed-ravel rule, preserving axis order and the whole seed. Single-axis reductions retain direct kernels. Layout-only changes share storage. Structural results retain renderers where their rank permits; scans and in-place changes copy complete layouts. Match ignores renderers.
|
|
158
170
|
|
|
@@ -194,7 +206,7 @@ Hash maps and sets come from `rustymath::hashing`, as rustymath's DEV.md describ
|
|
|
194
206
|
|
|
195
207
|
A dispatch selects a primitive before its loop. Concrete `Kernels` tables call rustymath objects: `many` for slices and `one`/`checked` for scalar Numbers. `at_widths!` writes f32/f64 tables once. Arithmetic, circle-code conventions and scalar policy remain in the numeric modules rather than a second evaluator.
|
|
196
208
|
|
|
197
|
-
|
|
209
|
+
Arguments of mixed item types run through `Converting` where the object runs item by item in rustymath's own loop (`Results::INLINE`), which converts each item as it reads it. Other objects use `Chunked`, which reads each argument through rustymath's `Side`, converting a run at a time before calling one homogeneous implementation. Sharing those kernels avoids a storage-type cross-product of machine code. Compile only operand pairings that can occur. Same-type arguments can reach rustymath in one call; other shapes expand reused chunks or use block mappings to avoid per-item division.
|
|
198
210
|
|
|
199
211
|
Custom elementwise closures use `rustymath::pairs` and its uninitialized append path. Function objects use their own slice forms. Keep per-item bodies inlinable across codegen units; passing a closure by reference can introduce an uninlined `Fn` shim. Pass it by value, or wrap an existing reference in a new closure. Hot loops use slices and fixed chunks rather than iterator helpers that introduce calls in the incremental build. Avoid captured mutable flags that live in memory and block vectorization.
|
|
200
212
|
|
|
@@ -206,15 +218,15 @@ Ordinary pervasive kernels also read pending copies through their maps. `fusion:
|
|
|
206
218
|
|
|
207
219
|
`explain.rs` holds the events that `•explain` reports. One check in `Function::reported` serves both `•prefs ["fusion":$t]` and `•explain`: a call that computes a pending argument writes the pref's line and records a `forced` event. `Graph::explained` records a fused group where a graph runs, and where a fold reads through one. `Idiom::call` records each fast combination taken, by the name `Idiom::name` gives. `linear::scatter_add`, and the transpose of a gather that scatters a source's items, record each accumulation. `Selection::write_into`, where assignment and Under write, records each write that leaves a compact array mixed. Fusion runs graphs without a session, so events go to a sink on the evaluating thread, which holds them only while `•explain` runs. Outside it, `call` pays one branch on the session's flags. Each record node and pending array holds an `explain::Live` guard, which counts it for the thread that made it until it is dropped, on any thread. `•memory` reports those counts, and `Value::footprint` walks a value's allocations for its `bytes`.
|
|
208
220
|
|
|
209
|
-
`derivative.rs` implements `∂`. A dual is a tag, a primal and a tangent: a `transform::Carrier`, held in `Value::Carried` for a number and in `Data::Carried` for an array, whose primal and tangent can be pending. A record of linear calls is the other kind of carrier. Routing (`transform::call`) hands a call to the newest level among its arguments, as `Value::newest` finds it. It reads their outer layer, but a newer level inside an argument held in mixed storage wins, as an array of dual atoms beside an older dual shows. A call whose newest level is a `∂` call goes to `derivative::call`, which reads how to run it from the form's facts in `Primitive::info()` (`primitive::Facts`). It applies the partials table to pervasive forms and its own rule to `⌻`, and calls forms whose results carry no tangent on the primals. Structural glyphs, Under and selective assignment need no rules. Their own code moves each part of a carried array through the carrier's moves: `Carrier::view`, `Carrier::at`, `Carrier::copied`, and `transform::written` for writes, which a record answers through its ids. `Gather` copies a dual's primal and tangent together through `derivative::Join`. A glyph that copies its right argument through one plan, and a broadcast, copy a record tangent as one `Op::Copy` of the plan's `Steps` (`primitive::copied`, and `Form::Moves`'s `planned`). Its transpose reads through rustymath's `Steps::transposed`: the inverse map for a copy that reads each item at most once, and a correlation for windows that move by 1. A copy of a copy transposes in one read where the composed copy still transposes by reads (`linear::composed`). The record keeps the chain, because recognising windows needs each copy's own shape. A sum along a window's axis transposes as a sliding sum (`linear::slide`), and a spread axis as a sum along it. Windows that move by more than 1 transpose by rustymath's `signal::overlap_add`, which adds each window back where it read (`linear::strided_back`). Other copies, and copies of several sources, keep ids and scatter. `•explain` lists each scatter as an accumulation. In reverse mode, the rule for a `⌈` or `⌊` fold is a sum of the tangent times a mask of each lane's chosen item. Its transpose reads. Mix of a dual whose primal is nested mixes the primal and the tangent apart. `fold` and scans with `+`, `×`, `⌈` and `⌊`, `+.×` and outer products have rules, and kernels that read numbers directly leave active arguments to their general paths. Folds by primitives, products of primitives, `⌹`, `⊥` and stacks of matrices route through `transform::call` as operations (`primitive::Operation`), so their rules (`derivative::solve`, `decode`, `product_dual`, `determinant` and `fold_dual`) run on a `&Context` and call `Operation::call` for the products, folds and inverses that they need. Rank's routes for whole arguments send stacks that a level carries through `Pairing::Matrices`, so `⌹⍤2`, `+.×⍤2` and `-.×⍤2` take their stacked rules in one call, with the `batch` pref on or off. Attached rules, system functions, and folds and products by functions that aren't primitives route through the same `transform::call`, as `transform::Op`'s other variants. The rules for `⌹` and `-.×` keep the glyph's own result as the primal, so that a function computes the same values with or without `∂`. Their tangents and transposes multiply by `R`, the inverse that `numeric::matrix_inverse` takes from one factorization through rustymath's `
|
|
221
|
+
`derivative.rs` implements `∂`. A dual is a tag, a primal and a tangent: a `transform::Carrier`, held in `Value::Carried` for a number and in `Data::Carried` for an array, whose primal and tangent can be pending. A record of linear calls is the other kind of carrier. Routing (`transform::call`) hands a call to the newest level among its arguments, as `Value::newest` finds it. It reads their outer layer, but a newer level inside an argument held in mixed storage wins, as an array of dual atoms beside an older dual shows. A call whose newest level is a `∂` call goes to `derivative::call`, which reads how to run it from the form's facts in `Primitive::info()` (`primitive::Facts`). It applies the partials table to pervasive forms and its own rule to `⌻`, and calls forms whose results carry no tangent on the primals. Structural glyphs, Under and selective assignment need no rules. Their own code moves each part of a carried array through the carrier's moves: `Carrier::view`, `Carrier::at`, `Carrier::copied`, and `transform::written` for writes, which a record answers through its ids. `Gather` copies a dual's primal and tangent together through `derivative::Join`. A glyph that copies its right argument through one plan, and a broadcast, copy a record tangent as one `Op::Copy` of the plan's `Steps` (`primitive::copied`, and `Form::Moves`'s `planned`). Its transpose reads through rustymath's `Steps::transposed`: the inverse map for a copy that reads each item at most once, and a correlation for windows that move by 1. A copy of a copy transposes in one read where the composed copy still transposes by reads (`linear::composed`). The record keeps the chain, because recognising windows needs each copy's own shape. A sum along a window's axis transposes as a sliding sum (`linear::slide`), and a spread axis as a sum along it. Windows that move by more than 1 transpose by rustymath's `signal::overlap_add`, which adds each window back where it read (`linear::strided_back`). Other copies, and copies of several sources, keep ids and scatter. `•explain` lists each scatter as an accumulation. In reverse mode, the rule for a `⌈` or `⌊` fold is a sum of the tangent times a mask of each lane's chosen item. Its transpose reads. Mix of a dual whose primal is nested mixes the primal and the tangent apart. `fold` and scans with `+`, `×`, `⌈` and `⌊`, `+.×` and outer products have rules, and kernels that read numbers directly leave active arguments to their general paths. Folds by primitives, products of primitives, `⌹`, `⊥` and stacks of matrices route through `transform::call` as operations (`primitive::Operation`), so their rules (`derivative::solve`, `decode`, `product_dual`, `determinant` and `fold_dual`) run on a `&Context` and call `Operation::call` for the products, folds and inverses that they need. Rank's routes for whole arguments send stacks that a level carries through `Pairing::Matrices`, so `⌹⍤2`, `+.×⍤2` and `-.×⍤2` take their stacked rules in one call, with the `batch` pref on or off. Attached rules, system functions, and folds and products by functions that aren't primitives route through the same `transform::call`, as `transform::Op`'s other variants. The rules for `⌹` and `-.×` keep the glyph's own result as the primal, so that a function computes the same values with or without `∂`. Their tangents and transposes multiply by `R`, the inverse that `numeric::matrix_inverse` takes from one factorization through rustymath's `Stacked::inverse`, or by exact row reduction for exact matrices. `regular_inverse` gives UNSUPPORTED where rustymath's regularity test finds the matrix singular. With only `B` active, `R` is `⌹A`, a pseudoinverse included. With one number in `x`, `f∂ x` runs `f` once with `x` seeded along it. With more, `linearized` pushes a record level just below its `∂` call's level, then runs `f` once with each part of `x` seeded with a record at that level, from `linear.rs`: a tangent whose items are never computed, which the same rules extend into a graph of linear calls. A call whose newest level is a record level records the linear map that its form's facts name (`linear::call`). `reverse` then reads the Jacobian from the record, by a transpose for each result item or a forward evaluation for each number of `x`, whichever are fewer. A function with a JVP rule that `f∂←g` attached calls the rule with `⍺` a dual of zeros whose tangent is the argument's, so in reverse mode the rule extends the record too (`derivative::attached`). A call of such a function with two arguments gives DOMAIN ERROR wherever `∂` needs a derivative through it (`derivative::two_arguments`). Code that reads a dual array's storage gets its items as dual atoms, which is correct at per-item speed. A rule packs an array that holds its level's duals, at any depth, into one dual before it splits the array (`derivative::packed`). A reader outside a call sees a value through `transform.rs`'s read point. `Value::observed`, which counts, positions, ranks, selectors, `≡` and guards' predicates use, reads a dual's primal. The integer readers of `Items` read carried items through it (`Value::observed_number`), so a count or position that `∂` carries reads its primal. It returns a `Result` whose error, `transform::Stop`, names the level that owns a batched run. A stop is `ErrorKind::Stop`, which no guard catches, even one that names it, and which a handler that catches every error lets pass (`ErrorKind::is_control`). Display reads through `Value::displayed`, because it never runs inside a batched run. `Value::computed`, which kernels use through `primitive::numeric`, gives UNSUPPORTED for a dual atom. Writes to bindings outside a `∂` call are recorded and stripped when it returns.
|
|
210
222
|
|
|
211
|
-
`batch.rs` makes a map's batched call. `batch::tried`, which `each_pair` calls, begins a batched level for the run (`transform::Kind::Batched`), wraps each argument that has a frame in a `Batch` carrier at that level, calls the operand once, and ends the level. Each map first lays its arguments over its frame through its own agreement, the pairing that its calls on each cell read (`batch::Arguments::laid` and `agreement::laid_cells`). `each_pair` makes no batched call for one cell of atoms, which runs faster without one. Routing hands each call whose newest level is the run's to `batch::call`: a primitive, an operation that primitives name, such as a fold by a primitive or `+.×`, or an operation by a dfn. It leaves `⍕` and
|
|
223
|
+
`batch.rs` makes a map's batched call. `batch::tried`, which `each_pair` calls, begins a batched level for the run (`transform::Kind::Batched`), wraps each argument that has a frame in a `Batch` carrier at that level, calls the operand once, and ends the level. Each map first lays its arguments over its frame through its own agreement, the pairing that its calls on each cell read (`batch::Arguments::laid` and `agreement::laid_cells`). `each_pair` makes no batched call for one cell of atoms, which runs faster without one. Routing hands each call whose newest level is the run's to `batch::call`: a primitive, an operation that primitives name, such as a fold by a primitive or `+.×`, or an operation by a dfn. It leaves `⍕` and random draws to their own code. It runs any other system function once for each cell, on that cell's arguments, as the function runs once for each item of an argument that holds several, and joins the cells' results into one batch (`batch::system`, `batch::each_cell`). `batch::call` runs the call on the whole arguments by Rank's routes: `eval::whole_cells` through `batch::whole_call`, and `eval::folded_cells` for a fold. A primitive therefore batches wherever Rank runs it on whole arguments. A fold or scan that `folded_cells` doesn't cover, such as one by a dfn, runs the fold's own loop over the batch's items. Each stage is then one call, on item `j` of every cell (`Batch::at`). `fold_array` and `primitive_fold` join a result that holds stage batches into one batch (`joined`). Every fold and scan route decides its structural cases, such as a unit, empty lanes and the result's shape, through `FoldPlan`, and ends in `folded`, which alone gives the result its layout, fused folds included. A fold or scan by any function other than a primitive, over more than one lane, also tries a batched run of its own: `operators::by_lanes` moves the fold axis last and runs the derived fold over the lanes through `batch::tried`. `operators::by_triples` does the same for `f.g` where `g` isn't a primitive: one batched call of `g` on a frame of rows by contraction by columns, then the fold by `f` along the contraction, for each chunk of rows whose triples hold at most `batch::CHUNK` items (`operators::by_rows`, which products of primitives share). Each runs its usual loop from the start where its try gives `None`. A fold keeps its stops on its operand's `Definition` (`Function::remembers`). `batch::tries` holds the conditions for any try. A call that no route covers stops the run (`transform::Stop`). A call whose constants with axes, repeated over the frame, would hold more than 4 times the items of its arguments and more than `batch::CHUNK` items, 2²¹, stops the run with the cells of a chunk whose share holds at most `CHUNK` items (`oversized`, `Stop::chunk`). `tried` then runs the operand once on each chunk of that many cells (`batch::chunked`), each as a batched level on a frame of one axis, and joins the chunks' results as the run over cells assembles its cells' results. A chunk that stops for too many items again starts the chunks over with its own smaller chunk. Where one cell's share alone passes `CHUNK`, the map calls its operand once for each cell. Code that must run once for each cell asks the levels first (`Levels::effect`): output, input, `⍕` of a carried value, and the code in a system function that acts (`Effect::Acts`, through `Context::acts`), a guard or a call on prototypes that would catch an error (`Effect::Catches`), and a write to a binding outside the map's frames (`Effect::Writes`, through `Levels::record_write`). A read through `Value::observed`, as a count or a position makes, stops the run too. A guard whose predicate is a batch of the run splits the run instead (`Session::guard` through `operators::guard`). `batch::truths` gives each cell's Boolean, and each side runs once, as a guard case on its own cells (`Levels::case`), through the `Cells` that `⍚` uses. Each batched binding in the frames that the run started is read at the side's cells (`Session::restricted`, through `batch::read_cells` and `operators::cells_at`), and `Cells::assembled` joins the sides' results. During a case, the run's frame is the case's cells, a random draw draws for the case's cells, and a write to an enclosing frame stops the run. A guard of a dfn that already splits the cells in another frame stops the run as a recursive call (`Cause::Recursion`), and sides whose cells differ in layout or kind stop it as a call with no rule. Each stop carries its cause (`transform::Cause`), which says how long a dfn operand remembers it (`Cause::kept`). An effect, a write, an observing read or a recursive call lasts for every later call. A call that no route covers lasts while later calls repeat the arguments' kinds and cell shapes, and the memory guard lasts while they also repeat the frame's shape. A caught error never lasts, because whether an error arises depends on the cells' values. The dfn's `Definition` holds what it remembers (`Definition::remember`): `ALWAYS`, or a signature of the arguments (`batch::signature`), each holding the stop's cause (`batch::holding`). A later try that it covers falls back without calling the operand, with an `"an earlier stop"` event that names the cause. A stop's own `fallbacks` event names its cause (`Cause::reason`), and the glyph of a primitive whose call no rule covers (`Stop::refusing`). Code with no rule for batches that reads a batch's items gets item carriers, item i of every cell, and records an `itemwise` row, route `"batched items"`. `explain::itemwise` is the one helper for routes that handle items one at a time, and the innermost call claims its counts (`Function::reported`), as `forced` does. A kernel that then reads a number meets the stop that `Carrier::computed` gives a batch. A missed reader therefore costs speed or a fallback, never a wrong result. A batched run can also start inside a `∂` call. The run's level is newer than the `∂` tag, so the batch rules take each call first, and their calls on whole arrays reach the derivative rules. A batch's whole can then carry a dual, whose kind batch checks read through `Value::template_dtype`. Stacks of matrices whose wholes carry a dual take the derivative rules through `Pairing::Matrices` (`eval::whole_cells`), because the stacked kernels read compact storage. A `∂` call inside the run differentiates with respect to batches of atoms or of arrays. `derivative::numbers` counts a cell's numbers from the batch's template, every cell shares each direction's seed, and the Jacobian joins into one batch (`batch::joined`). A move with no plan on a dual whose primal is a batch runs on the primal and the tangent apart (`derivative::apart`). Adjoints that a transpose adds into a batch add as one sum on its whole (`batch::scatter_add`). An attached rule runs on the whole batch at its argument's `∂` tag (`batch::call`), and `batch::split_whole` and `batch::dual_of_wholes` keep the newest level outermost. A roll draws once, on its argument laid over the frame (`distribution::drawn_items`), and deals and samples draw for each cell in turn (`distribution::each_cell`), all from one stream in cell order. Where each cell draws once, seeded draws match a run cell by cell, except under a guard that splits the cells, where each side draws for its own cells in turn. A try that falls back puts back the state of each generator it drew from (`distribution::settle`). The map's result must be a batch at its level, a strand of batches whose kinds join (`joined`), or an atom or compact array with no carrier, as every cell's result. Any other result falls back. A pervasive call stops where its result's kind differs from the kind that one route gives every item (`pervasive::expected`). Each cell then keeps the kind that a run cell by cell gives it. `reference::check` runs each reference case with the `batch` pref off, then on, then on under fusion's small sizes (`fusion::Sizes::SMALL`), and compares the storage kinds of the later runs' values with the first's.
|
|
212
224
|
|
|
213
|
-
Rustymath owns numeric folds, scans, adjacent pairs, grouped reductions and integer bounds. Basedpl selects kernels, tolerance, seeds, storage widths and exact fallbacks. Folds by algebraic float operations can regroup. Contiguous subtraction/division folds use `Alternating`; quotients fall back to item-by-item folding if their products leave the normal range. Boolean scans compose truth-table maps; comparison scans compute both possible totals in bulk and use `reduce::chosen`. Seeds, axis lanes and scalar fallback preserve the language's accumulation direction. Generic reductions stay right-associated and preserve operand call order/effects. Monadic `f.g` is the exception: it memoizes each minor's expansion, and a cached minor does not repeat operand calls or their effects. Determinant/permanent fast paths use the appropriate rustymath backend.
|
|
225
|
+
Rustymath owns numeric folds, scans, adjacent pairs, grouped reductions and integer bounds. Basedpl selects kernels, tolerance, seeds, storage widths and exact fallbacks. Which reduction folds each primitive comes from rustymath's `facts!` table, through `pervasive::folds` and `truth_fold`, and so does the object by whose rule each takes characters. Folds by algebraic float operations can regroup. Contiguous subtraction/division folds use `Alternating`; quotients fall back to item-by-item folding if their products leave the normal range. Boolean scans compose truth-table maps; comparison scans compute both possible totals in bulk and use `reduce::chosen`. Seeds, axis lanes and scalar fallback preserve the language's accumulation direction. Generic reductions stay right-associated and preserve operand call order/effects. Monadic `f.g` is the exception: it memoizes each minor's expansion, and a cached minor does not repeat operand calls or their effects. Determinant/permanent fast paths use the appropriate rustymath backend.
|
|
214
226
|
|
|
215
227
|
The automatic Rayon scheduler serves rustymath elementwise `many` and `pairs`, broadcasts through `agreement::blocks`, folds through `reduce::along`, fused graphs and matrix products. Scans don't split. Decompositions split in the products of their blocked updates, the passes of their Hermitian and bidiagonal reductions, and their divide-and-conquer merges. `rank` sends dyadic `+.×` and `⌹`, monadic `⌹` and `-.×`, and `•decompose` over the 2-cells of an unkeyed stack with compact storage to `primitive::stacked` and `stacked_decompositions`. They run each cell through the rustymath function it uses alone. A pervasive operand, or Rank nested down to one, runs as one call: each argument gets length-1 axes after each level's frame, so leading-axis agreement pairs frames with frames and cells with cells. Arguments with axis names still go cell by cell. Rustymath's `parallel::stack_with` splits whole cells across threads in rounds, with `check_now` between rounds. A caller whose checks run far apart, such as a round or a rustymath `_with` callback, calls `check_now`, because `Context::check` reads the clock only on every 64th call. The scheduler adapts to call cost, uses `RAYON_NUM_THREADS` by default and accepts one override for the whole process through `parallel::set_threads` (0 default, 1 serial), which `•prefs ["threads":n]` writes directly. The timing harness sets one thread after each reset of the settings. Nested Rayon work does not split again; wasm is serial. A fused graph splits in pieces of whole blocks: an elementwise graph through `parallel::extended`, and a folded one through `reduce::fold_pieces`. On one thread an elementwise graph appends straight to its result, because copying each block into a piece's slots cost up to 1.2 copies there. Small converted chunks limit the work available to the scheduler. Don't infer multicore execution from a large array alone.
|
|
216
228
|
|
|
217
|
-
|
|
229
|
+
A pair that rustymath has a product kernel for, such as `+.×`, `⌈.+`, `∨.∧` or `+.=`, runs through `linalg::Product::run`, which Python's `inner` also takes (`pervasive::known_product`). Other native pairs use its bounded `inner_with` runner and `reduce::right_fold`, carrying the right tail across blocks. Basedpl supplies its primitive kernels, tolerance and exact-widening fallback. An integer product that doesn't fit 64 bits gives way to the exact path. `pervasive::inner` takes each operand's `Orientation`. Its float and complex products read a transposed operand in place, as reverse mode's `product_transpose` needs. A float `+.×` whose operand is a pending copy, or a view of one, hands rustymath's `Inner::inner_mapped` the copy's source and map (`fusion::source`, `pervasive::mapped_product`). Rustymath gives gemm an operand that its map reads at strides, such as a transpose, where it lies (`Mapped::matrix`). It reads any other copy a block of rows at a time, except in a product with one column, where the copy's rows are adjacent in storage, as for a vector or a single-channel image. It then adds each column of the copy where it lies (`linalg::by_columns`). Neither builds the copy. A copy that a name holds is read again for each product rather than cached. Reverse mode transposes a product whose operand is windows that move by 1 as one product: the windows of the zero-padded cotangent with the kernel reversed (`linear::convolved_back`, rustymath's `signal::correlation`). Structural gather/compress and interval index also reuse rustymath. Measure changes to generic or backend code in both projects. The callers' codegen and layout decide costs that a kernel measured alone misses.
|
|
218
230
|
|
|
219
231
|
## Evaluation and frontend boundaries
|
|
220
232
|
|
|
@@ -226,7 +238,7 @@ Packed numeric, Boolean and equality-count inner products use `rustymath::linalg
|
|
|
226
238
|
|
|
227
239
|
### Python
|
|
228
240
|
|
|
229
|
-
`python/basedpl/__init__.py` owns the shared `bpl` workspace and `Array`/result/error wrappers. `fn` aliases `bpl.fn`; builtins and magics share that workspace. Registering the magics gives it the REPL's display defaults, through `Session::make_interactive`. Plain calls print explicit output and return Array, Function or Operator values. Capturing calls return `Result`. Capture mode is positional-only because keywords bind BPL names. `_Session.eval` and `.call` are the PyO3 entry points; `request` is their internal Rust helper.
|
|
241
|
+
`python/basedpl/__init__.py` owns the shared `bpl` workspace and `Array`/result/error wrappers. An `Array` whose value holds a function as an item is a `FunctionArray`, which `Array._classify` chooses in `__init__` and after `__setitem__`, so `callable()` is false for every other array. `fn` aliases `bpl.fn`; builtins and magics share that workspace. Registering the magics gives it the REPL's display defaults, through `Session::make_interactive`. Plain calls print explicit output and return Array, Function or Operator values. Capturing calls return `Result`. Capture mode is positional-only because keywords bind BPL names. `_Session.eval` and `.call` are the PyO3 entry points; `request` is their internal Rust helper.
|
|
230
242
|
|
|
231
243
|
`functions.py` constructs native nodes and lazy exports from Rust metadata. Builtins win name collisions with workspace names; operation names choose valence/currying. `__all__` omits Python-builtin collisions but leaves explicit imports available. Function calls with keywords use a keyed left argument. A single positional argument stays the right argument unchanged; zero or multiple positional arguments form a vector. Operator properties and `_Pending` assemble native nodes, never generated BPL source. `printing.py` reads node parts without evaluating or resolving names.
|
|
232
244
|
|
|
@@ -258,7 +270,7 @@ The playground and gallery load released assets from jsDelivr, or local `nbs/pla
|
|
|
258
270
|
|
|
259
271
|
## System functions and rendering
|
|
260
272
|
|
|
261
|
-
`system.rs` owns case-insensitive
|
|
273
|
+
`system.rs` owns the system table: one `SystemFunction` for each system function, holding its case-insensitive name, call, valence, item mapping, result prototype and inverse. A function that acts asks the running levels where it acts (`Context::acts`), as output and input do: where it reads or writes files, the network, the clock or the terminal, or makes something new on each call, as `•index` and `•rand` do. Any other system function asks nothing, and a batched run calls it once for each cell. The parser resolves a known system name to its table entry (`system::Entry`), which `primitive::Builtin` holds as it holds a glyph's primitive. A system name is therefore a `NodeKind::Function` node, compiles to a constant and resolves to the function that one process-wide table holds for each builtin (`Builtin::function`), as a glyph does. An unknown system name stays a `NodeKind::System` node, which is a VALUE error when evaluated. Code identifies a table function by the `Entry` that its `SystemFunction` records, as in `Entry::PREFS`, never by its name. A function that a factory made, such as `•element "div"`, has no entry, although it shares its factory's name. Native records use ordinary function nodes and calls. Empty native item mapping returns its declared prototype without calling the function. `data::Options` is the shared keyed-option decoder; formats don't invent separate option parsers.
|
|
262
274
|
|
|
263
275
|
`optimize.rs` implements `⇄` on `rustymath::optimize`. The left argument holds the options. When the method can use a derivative (none named, L-BFGS, Levenberg–Marquardt, CG or MINRES), one linearisation at the start (`derivative::linearized`) finds whether `∂` differentiates the function, and gives its value there. `Goal` evaluates the function at points in the start's layout for `minimize`. When the search runs L-BFGS, each value comes from a linearisation that `gradient` then transposes at the same point (`linearized_at`), so a value and its gradient run the function once. With `"solve":$t`, `Residual` is the `Mapping` that `solve` takes, or that `solve_affine` takes with `"linear":$t` as well. Where `∂` differentiates the function, `Residual` gives JVPs and vector–Jacobian products from one record at each point, or from the start's record for an affine function. At a later point where `∂` gives an UNSUPPORTED error, `Residual::jvp` declines, and rustymath takes forward differences for that Jacobian and later ones. A square linear system takes no products with the transpose, so it runs GMRES on A, not the normal equations. The function in option `precondition` gives the preconditioner.
|
|
264
276
|
|
|
@@ -272,7 +284,7 @@ CSV columns, JSON arrays and Python lists share `data::imported`: a non-fill fin
|
|
|
272
284
|
|
|
273
285
|
`tests/core.rs` checks public storage/layout/API behaviour, ownership, parser diagnostics and recovery. Use `equiv_in!` for session workflows and `fails_in` for errors; each expected expression runs in a fresh session after its code, under the settings that the code leaves. `tests/core.rs` never changes settings. The settings are one store for the whole process, so the checks that change them live in `tests/settings.rs`, which runs them in turn in one test, each from the defaults. Both binaries share the helpers in `tests/common/mod.rs`. Keep constructors for representation/prototype/buffer checks. Self-contained language cases belong in `tests/reference/core.bpl`. `cli/tests/cli.rs` and Python's pseudo-terminal tests exercise the installed process/editor boundary.
|
|
274
286
|
|
|
275
|
-
`reference.rs` serves Rust tests and worker requests. Every reference case uses a fresh session; documentation examples share a session within each BPL code block, which starts from the default settings. A reference file's leading `•prefs` line sets the settings of all its cases. Each case runs
|
|
287
|
+
`reference.rs` serves Rust tests and worker requests. Every reference case uses a fresh session; documentation examples share a session within each BPL code block, which starts from the default settings. A reference file's leading `•prefs` line sets the settings of all its cases. Each case runs four times, with the `batch` pref off, then on, then on with fusion's small sizes, then on with its code as the body of a dfn that one session calls twice (`twice`), and each run starts from the defaults and the file's header. The fourth run checks that a dfn's second call, which runs the statements its first call recorded, gives the first call's value, storage kind, error and output. Code that can't be a dfn's body skips it. The cases of a file run in parallel, one run at a time. A case whose code calls `•prefs`, such as a seeded draw, carries `serial` and runs alone after them, and the harness rejects a `•prefs` call in a case without it. `batched` leaves out the run with the `batch` pref off, and `unfused` the run with the small sizes. Each expectation evaluates after its code, under the settings that the code leaves. `.bpl` files define active coverage. Captured foreign expectations have no exactness; local expectations compare exactness and structural values independently. A local expectation also fixes where storage is mixed: the result must be held in mixed storage exactly where the expectation is, at each level of nesting (`kind_difference`), unless the case's header carries `mixed`. Pending gaps belong in inventory JSONL, not passing error tests. See `tests/reference/README.md` for format and review/activation workflow. `python/basedpl/reference.py`, `bpltests.py` and `scripts/reference.py` own import, capture, inventory and worker checks. `lib/*.bpl` are readable dfn examples; modules import other library files with private relative names.
|
|
276
288
|
|
|
277
289
|
`tests/scaling.rs` measures time/allocation growth and result-size allocation budgets. `tests/speed.rs` reads native/browser budgets from `speed.txt` through `timing.rs`; the worker and Python measurement tools reuse it. `tests/units.rs` reads existing incremental object files and checks unit size without building. Python tests cover conversion/cancellation/frontend behaviour, not a second Rust semantic suite. Combine related checks into readable tests.
|
|
278
290
|
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"match": "[•][A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*",
|
|
53
|
-
"name": "support.function.
|
|
53
|
+
"name": "support.function.bpl"
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
"match": "[¯]?[∞]|[¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?([jJⱼ][¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?|ₓ|[rᵣ][¯]?\\d+)?|[ₑⱼᵣ]",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"match": "[•系][A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*",
|
|
27
|
-
"name": "support.function.
|
|
27
|
+
"name": "support.function.bpl"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"match": "[¯负負]?[∞永]|[¯负負]?(\\d+([.内內]\\d+)?|[.内內]\\d+)([eEₑ][¯负負]?\\d+)?([jJⱼ][¯负負]?(\\d+([.内內]\\d+)?|[.内內]\\d+)([eEₑ][¯负負]?\\d+)?|ₓ|[rᵣ][¯负負]?\\d+)?|[ₑⱼᵣ]",
|
|
@@ -19,7 +19,7 @@ syntax match bplComment /\v⍝.*$/
|
|
|
19
19
|
syntax match bplComment /\%^#!.*/
|
|
20
20
|
|
|
21
21
|
highlight default link bplName Identifier
|
|
22
|
-
highlight default link bplSystem
|
|
22
|
+
highlight default link bplSystem Function
|
|
23
23
|
highlight default link bplNumber Number
|
|
24
24
|
highlight default link bplFunction Function
|
|
25
25
|
highlight default link bplMonadicOperator Operator
|