basedpl 0.1.72__tar.gz → 0.1.73__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.72 → basedpl-0.1.73}/Cargo.lock +13 -13
- {basedpl-0.1.72 → basedpl-0.1.73}/Cargo.toml +3 -3
- {basedpl-0.1.72 → basedpl-0.1.73}/DEV.md +10 -16
- {basedpl-0.1.72 → basedpl-0.1.73}/PKG-INFO +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/evaluation.qmd +1 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/brackets.qmd +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/llms.txt +2 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/numbers.qmd +6 -3
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/python.ipynb +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/scripts.ipynb +70 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/01_basics.ipynb +3 -3
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/syntax.qmd +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/explain.qmd +7 -4
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/prefs.qmd +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/py/src/lib.rs +9 -3
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/bpltests.py +62 -13
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/functions.py +3 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/printing.py +2 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/worker.py +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/src/array/storage.rs +4 -12
- {basedpl-0.1.72 → basedpl-0.1.73}/src/array.rs +41 -15
- {basedpl-0.1.72 → basedpl-0.1.73}/src/batch.rs +228 -45
- {basedpl-0.1.72 → basedpl-0.1.73}/src/derivative.rs +24 -9
- {basedpl-0.1.72 → basedpl-0.1.73}/src/distribution.rs +13 -11
- {basedpl-0.1.72 → basedpl-0.1.73}/src/element.rs +6 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/assign.rs +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/binder.rs +6 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/idioms.rs +17 -25
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/operators.rs +52 -17
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/session.rs +33 -7
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/tree.rs +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval.rs +8 -4
- {basedpl-0.1.72 → basedpl-0.1.73}/src/fusion.rs +54 -27
- {basedpl-0.1.72 → basedpl-0.1.73}/src/linear.rs +48 -12
- {basedpl-0.1.72 → basedpl-0.1.73}/src/number.rs +57 -16
- {basedpl-0.1.72 → basedpl-0.1.73}/src/pervasive.rs +143 -67
- {basedpl-0.1.72 → basedpl-0.1.73}/src/primitive/indexing.rs +87 -21
- {basedpl-0.1.72 → basedpl-0.1.73}/src/primitive/numeric.rs +30 -80
- {basedpl-0.1.72 → basedpl-0.1.73}/src/primitive/search.rs +48 -3
- {basedpl-0.1.72 → basedpl-0.1.73}/src/primitive/structural.rs +5 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/primitive.rs +80 -21
- {basedpl-0.1.72 → basedpl-0.1.73}/src/search.rs +71 -12
- {basedpl-0.1.72 → basedpl-0.1.73}/src/selection.rs +1 -1
- {basedpl-0.1.72 → basedpl-0.1.73}/src/syntax.rs +16 -26
- {basedpl-0.1.72 → basedpl-0.1.73}/src/timing.rs +16 -16
- {basedpl-0.1.72 → basedpl-0.1.73}/src/transform.rs +18 -14
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/core.bpl +96 -12
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/distributions.bpl +2 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/settings.rs +1 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/speed.rs +2 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/speed.txt +85 -31
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_basic.py +4 -2
- {basedpl-0.1.72 → basedpl-0.1.73}/.cargo/config.toml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.gitattributes +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.github/workflows/ci.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.github/workflows/docs.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.github/workflows/speed.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.github/workflows/test.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/.gitignore +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/CONTRIBUTING.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/LICENSE +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/_config.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/_layouts/default.html +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/build.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/jetbrains/BPL.tmbundle/Syntaxes/bpl.tmLanguage.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/jetbrains/BPL.tmbundle/Syntaxes/hpl.tmLanguage.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/jetbrains/BPL.tmbundle/info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/jetbrains/BPL.xml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/jetbrains/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.icns +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.keylayout +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-de.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.icns +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.keylayout +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-es.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.icns +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.keylayout +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-fr.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.icns +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.keylayout +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-uk.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.bundle/Contents/Info.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.icns +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.keylayout +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.bundle/Contents/version.plist +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/macos/BasedPL-us.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/vim/ftdetect/bpl.vim +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/vim/syntax/bpl.vim +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/build.ps1 +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/install.ps1 +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/keyboard.c +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/keyboard.def +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/keyboard.rc +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/editors/windows/layout.h +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/index_files/figure-commonmark/cell-17-output-1.svg +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/index_files/figure-commonmark/cell-18-output-1.svg +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/index_files/figure-html/cell-17-output-1.svg +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/index_files/figure-html/cell-18-output-1.svg +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/LICENSE-april +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/array.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/dyalog.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/graph.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/numeric.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/power.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/regex.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/string.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/lib/tree.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/.gitignore +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/_quarto.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/arrays.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/assignment.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/bpl.xml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/bqn.xml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/bracket-types.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/cli.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/comparison.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/data.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/dfns.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/distributions.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/driver.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/dyalog.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/dyalog.xml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/fonts/LICENSE-SAX2 +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/fonts/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/fonts/SAX2B.ttf +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/fonts/SAX2B.woff2 +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/fonts.css +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/attractor.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/boids.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/dragon.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/flow.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/mandelbrot.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/mandelbrot32.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/orbits.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/phyllotaxis.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/prefs.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery/reaction.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/gallery.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/getting-started.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/_metadata.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/alpha-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/alpha.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/at.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/backslash-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/backslash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/braces.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/bullet.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-backslash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-divide.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-slash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-star.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-stile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle-times.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/circle.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/colon.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/comma-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/comma.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/del-diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/del-stile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/del.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/delta-stile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/diamond-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/diamond.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/domino.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/dot.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/down-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/down-shoe.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/down-tack.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/downstile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/epsilon-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/epsilon.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/equal-underbar-slash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/equal-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/equals.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/error-guard.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/exclamation.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/greater-than-or-equal.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/greater-than.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/hash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/hydrant.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/infinity.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/inverted-question.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/iota-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/iota.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/jot-diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/jot.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/lamp.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/left-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/left-shoe-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/left-shoe.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/left-tack.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/left-tail-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/less-than-or-equal.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/less-than.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/minus.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/not-equals.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/obelus.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/omega-underbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/omega.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/overbar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/parentheses.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/partial.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/pi.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/plus.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quad-colon.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quad-diamond.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quad-equal.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quad-jot.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quad.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/question.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/quote.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/radical.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/rho.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/right-arrow-from-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/right-left-arrows.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/right-shoe.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/right-tack.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/right-tail-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/slash-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/slash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/squad.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/star-diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/star.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/stile-tilde.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/stile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/superscript-b.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/thorn.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/tilde-diaeresis.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/tilde.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/times.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/up-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/up-down-arrow.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/up-shoe.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/up-tack.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/upstile.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/vee-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/vee.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/wedge-bar.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/wedge.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs/zilde.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs-study.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/glyphs.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/hanzi-notation-zh.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/hanzi-notation.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/hpl.xml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/index.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/indexing.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/introspection.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/keyboard.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/keyed.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/magics.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/modules.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/nbdev.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/notebooks.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/overview.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/papers/aplwiki-arrays.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/papers/brickman-depth-1-scalars.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/papers/mercer-based-system.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/bpl.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/gallery.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/hpl.tmLanguage.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/monaco-worker.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/page.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground/worker.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/playground.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/plot.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/principles.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/processes.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/puppy.jpg +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/regex.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/repl.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/sidebar.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/strings.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/02_functions.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/03_operators.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/04_nested-arrays.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/05_searching-indexing.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/06_rearranging-arrays.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/study/07_numerical-tools.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/style.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/styles.css +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/_metadata.yml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/c.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/canvas.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/constants.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/copy.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/csv.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/date.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/decompose.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/deflate.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/delay.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/detach.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/distribution.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/edge.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/element.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/ex.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/fetch.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/float.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/hash.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/host.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/image.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/index.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/js.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/json.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/literal.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/load.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/memory.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/metadata.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/mime.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/mkdir.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/nc.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/nget.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/nl.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/normalize.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/nput.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/path.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/plot.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/r.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/rand.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/readdir.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/remove.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/rename.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/signal.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/src.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/storage.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/svg.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/time.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/ucs.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/uuid.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/vfi.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system/xml.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/system-functions.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/terms.qmd +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/web.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/nbs/xml.ipynb +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/package-lock.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/package.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/aplcart.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/april.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/bqn.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/core.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/dyalog.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/provenance/ngn.jsonl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/py/Cargo.toml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/py/build.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/pyproject.toml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/__init__.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/_modidx.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/bpl.tmLanguage.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/dyalog.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/editors.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/font.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/fonts.css +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/hpl.tmLanguage.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/input.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/ipython.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/keyboards.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/keyboards.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/layout.json +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/lb.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/notebook_runner.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/notebooks.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/reference.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/syntax.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/python/basedpl/windows_keyboard.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/rustfmt.toml +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/scripts/install-macos.sh +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/scripts/prep.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/agreement.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/array/text.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/canvas.js +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/canvas.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/csv.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/data.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/date.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/display.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/error.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/bindings.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/eval/dissect.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/execution.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/explain.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/files.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/fusion/blocks.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/host.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/host_web.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/image/codecs.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/image/imageio.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/image.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/inspection.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/js.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/json.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/keyed.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/lib.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/name.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/number_theory.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/optimize.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/plot.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/polynomial.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/protocol.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/reference.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/regex.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/settings.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/symbols.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/system.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/src/xml.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/common/mod.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/conftest.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/core.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/derivatives.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/explain.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/highlighting.mjs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/input.mjs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/instructions.txt +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-aplcart +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-april +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-bqn +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-bqncrate +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-dyalog +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/LICENSE-ngn +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/README.md +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/aplcart.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/april.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/bqn.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/dyalog.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/graphics.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/lib.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/ngn.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/regex.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/static-int32.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/static.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/support/april.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/support/avl.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/support/redblack.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/support/sbst.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference/support/splay.bpl +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/reference.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/scaling.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_api.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_bpltests.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_glyphs.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_graphics.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_instructions.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_ipython.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_kernel.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_keylayout.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_notebooks.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_reference.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_repl.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_windows_keyboard.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/test_worker.py +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/units.rs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/wasm-pkg.mjs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/wasm-speed.mjs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/wasm.mjs +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/tests/windows_keyboard.c +0 -0
- {basedpl-0.1.72 → basedpl-0.1.73}/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.73"
|
|
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.73"
|
|
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.73"
|
|
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.73"
|
|
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.48"
|
|
1417
1417
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1418
|
-
checksum = "
|
|
1418
|
+
checksum = "3ed381a5dbc0b48b7077c4d510027b240e1067af82bcc5c964ade2c319839499"
|
|
1419
1419
|
dependencies = [
|
|
1420
1420
|
"foldhash",
|
|
1421
1421
|
"half",
|
|
@@ -1434,9 +1434,9 @@ dependencies = [
|
|
|
1434
1434
|
|
|
1435
1435
|
[[package]]
|
|
1436
1436
|
name = "rustymath-buffer"
|
|
1437
|
-
version = "0.1.
|
|
1437
|
+
version = "0.1.48"
|
|
1438
1438
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1439
|
-
checksum = "
|
|
1439
|
+
checksum = "8614c8bc25045617899784d0fa952f3137835030bcbb9f77359e1c530fd75c4b"
|
|
1440
1440
|
dependencies = [
|
|
1441
1441
|
"pyo3",
|
|
1442
1442
|
"rustymath",
|
|
@@ -1581,9 +1581,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|
|
1581
1581
|
|
|
1582
1582
|
[[package]]
|
|
1583
1583
|
name = "smallvec"
|
|
1584
|
-
version = "1.16.
|
|
1584
|
+
version = "1.16.4"
|
|
1585
1585
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1586
|
-
checksum = "
|
|
1586
|
+
checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8"
|
|
1587
1587
|
|
|
1588
1588
|
[[package]]
|
|
1589
1589
|
name = "socket2"
|
|
@@ -1814,9 +1814,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|
|
1814
1814
|
|
|
1815
1815
|
[[package]]
|
|
1816
1816
|
name = "uuid"
|
|
1817
|
-
version = "1.
|
|
1817
|
+
version = "1.29.0"
|
|
1818
1818
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1819
|
-
checksum = "
|
|
1819
|
+
checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514"
|
|
1820
1820
|
dependencies = [
|
|
1821
1821
|
"atomic",
|
|
1822
1822
|
"getrandom",
|
|
@@ -2086,7 +2086,7 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
|
|
2086
2086
|
|
|
2087
2087
|
[[package]]
|
|
2088
2088
|
name = "xtask"
|
|
2089
|
-
version = "0.1.
|
|
2089
|
+
version = "0.1.73"
|
|
2090
2090
|
dependencies = [
|
|
2091
2091
|
"anyhow",
|
|
2092
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.73"
|
|
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.48, <1", default-features = false }
|
|
15
|
+
rustymath-buffer = ">=0.1.48, <1"
|
|
16
16
|
pyo3 = ">=0.29.2, <1"
|
|
17
17
|
pyo3-build-config = ">=0.29.2, <1"
|
|
18
18
|
|
|
@@ -18,7 +18,7 @@ cargo test
|
|
|
18
18
|
pytest -q
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Use `cargo develop` to rebuild and install the native extension and `bpl` after Rust changes. It uses the `test` profile shared with `cargo test`. Cargo tests compile missing code but don't install it. Run plain `cargo test` while you work; use one test binary for a focused check. Run `pytest -q` at the end of a piece of work. Before you report a `pytest` failure in code you didn't touch, run `cargo develop` and rerun it. Give builds three minutes and test runs one minute; Cargo serializes builds in the same target directory.
|
|
21
|
+
Use `cargo develop` to rebuild and install the native extension and `bpl` after Rust changes. It uses the `test` profile shared with `cargo test`. Cargo tests compile missing code but don't install it. Run plain `cargo test` while you work; use one test binary for a focused check. From a kernel, `fastws.cargo.run_tests(root, *args)` runs `cargo test` and returns the build's compiler messages and each test binary's results. Run `pytest -q` at the end of a piece of work. Before you report a `pytest` failure in code you didn't touch, run `cargo develop` and rerun it. Give builds three minutes and test runs one minute; Cargo serializes builds in the same target directory.
|
|
22
22
|
|
|
23
23
|
Build nothing else without discussion: no scratch crates, alternate target directories, `--release`, `-p` or other-target builds. The documented build diagnostics, browser work and x86-64 inspection below are exceptions. Don't use `maturin develop`; its configuration does not reuse the normal local build.
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ When another agent's unfinished edits stop the shared tree compiling, run `cargo
|
|
|
26
26
|
|
|
27
27
|
An already-running Python process retains its loaded extension. In a kernel, use `from basedpl.worker import fresh; fresh(code)` to check the installed `bpl` in a fresh worker instead of restarting the kernel. A BPL error raises `BplError`. `fresh(code, bpl=PATH)` runs a saved copy of `bpl`, such as the baseline described below. Check one expression and read its result before building on it. `basedpl.bpltests.check_file` and `check_page` check reference files and documentation through the worker without building Rust. With `bpl=PATH`, they check a saved copy without installing it.
|
|
28
28
|
|
|
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. `rustymath::timing::COPIES` stores the copy time of each machine that runs the speed tests, by its CPU, the item's size and the number of items, at the slower end of what that copy normally takes, for copies whose source and destination fit in cache, 64 MiB together (`CACHED_BYTES`). A copy timed beside each case varied more than 3 times on CI's runner, where the functions' own times didn't, so stored times keep that noise out of every cost. A larger copy runs at the speed of memory, which a shared runner varies by up to 2 times between runs, and the cases of that size vary with it. The test measures such a copy once in each run. It also measures a cached size with no entry once, and prints a line to add to `COPIES`. The browser build has entries of its own, for its copy under the JavaScript engine. It can't read the CPU's name, and `tests/wasm-pkg.mjs` passes it the name that Node reads. Each case's line in a log ends with its time for each item, which `logged_costs` keeps in each row, and the log has a copy line for each size of data, which it reads into its result's `copies`. Budgets are single-thread measurements. `thread_scaling()` checks multithreaded speed: it times a large product, a 512×512 SVD and Hermitian eigendecomposition, a stack of QR decompositions and a large elementwise function on one thread and on the machine's cores, and fails when one speeds up less than 1.5 times. Accelerate's GESDD and SYEVD run on one thread whatever its threading setting. On macOS, where Accelerate computes the product, the SVD and the Hermitian eigendecomposition, those three cases need only the speedups in `_ACCELERATED_LEAST`. The manual `Speed` workflow runs it. `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,
|
|
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. `rustymath::timing::COPIES` stores the copy time of each machine that runs the speed tests, by its CPU, the item's size and the number of items, at the slower end of what that copy normally takes, for copies whose source and destination fit in cache, 64 MiB together (`CACHED_BYTES`). A copy timed beside each case varied more than 3 times on CI's runner, where the functions' own times didn't, so stored times keep that noise out of every cost. A larger copy runs at the speed of memory, which a shared runner varies by up to 2 times between runs, and the cases of that size vary with it. The test measures such a copy once in each run. It also measures a cached size with no entry once, and prints a line to add to `COPIES`. The browser build has entries of its own, for its copy under the JavaScript engine. It can't read the CPU's name, and `tests/wasm-pkg.mjs` passes it the name that Node reads. Each case's line in a log ends with its time for each item, which `logged_costs` keeps in each row, and the log has a copy line for each size of data, which it reads into its result's `copies`. Budgets are single-thread measurements. `thread_scaling()` checks multithreaded speed: it times a large product, a 512×512 SVD and Hermitian eigendecomposition, a stack of QR decompositions and a large elementwise function on one thread and on the machine's cores, and fails when one speeds up less than 1.5 times. Accelerate's GESDD and SYEVD run on one thread whatever its threading setting. On macOS, where Accelerate computes the product, the SVD and the Hermitian eigendecomposition, those three cases need only the speedups in `_ACCELERATED_LEAST`. The manual `Speed` workflow runs it. `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, `native=True` times rustymath's own linear algebra, which dev builds compile in, and `prefs=` runs BPL before each section's header, such as `•prefs ["kinds":"static"]`. `logged_costs(log)` reads CI output from its text or a file. `cargo_costs(path)` runs either project's Rust speed test, and `pytest_costs(path)` runs rustymath's Python speed test.
|
|
30
30
|
|
|
31
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 an expression, such as `k(⌈/⊢)⌸a`, run once per step inside `{case ⋄ ⍵}⍣N⊢0`. That dfn's own call adds about 1,900 instructions a step. A case that names `N` makes its own calls instead, such as `{⍵}⍣N⊢0`, which makes one dfn call a step. Such a case must make one call per step: 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. A case whose result stays pending, such as large windows or a transpose, counts making the pending copy, not the copy: `3↕v` retires about 12,000 instructions a step. `force=True` computes each step's result in full, through an indexed write, for any result of rank 1 or more: `3↕v` then counts the copy itself, about 9 million instructions a step. A join computes at once and needs no `force`.
|
|
32
32
|
|
|
@@ -34,7 +34,7 @@ Costs in copies can't show a per-call change of a few percent, because code layo
|
|
|
34
34
|
|
|
35
35
|
`profile(case)` shows where a case's instructions go, by function, on macOS. It takes a case, and `force=`, as `instructions` does. 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. When a count moves, `profile_diff(case, base)` shows which functions moved it, from those estimates for both builds. A function that one build inlines and the other calls out of line appears under one build alone. Run them before reading machine code. `base` is a saved copy, and `bpl=PATH` sets the build to profile, the installed one by default.
|
|
36
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`, `profile_diff`, `speed_costs`, `thread_scaling`, `cargo_costs`, `pytest_costs`, `compare_costs` or `wasm_test`.
|
|
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`, `profile_diff`, `disasm`, `speed_costs`, `thread_scaling`, `cargo_costs`, `pytest_costs`, `compare_costs` or `wasm_test`. 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. Called in a kernel, the same functions return Python objects, such as the rows that `compare_costs` reads.
|
|
38
38
|
|
|
39
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% since the run before. `compare_costs(before, after)` lists both, from two runs' logs or from the rows that `speed_costs` and the other timing functions give. It measures each change on times per item where both runs give them, so a change to `COPIES` doesn't show as one. Every log names its CPU in its copy lines. 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.
|
|
40
40
|
|
|
@@ -44,23 +44,17 @@ An initial budget is twice what a first-principles analysis says the case should
|
|
|
44
44
|
|
|
45
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.
|
|
46
46
|
|
|
47
|
-
For a change meant to make something faster, or a change to code that every call goes through, time the cases it affects before and after the change. Before your first `cargo develop`, copy the installed `bpl
|
|
47
|
+
For a change meant to make something faster, or a change to code that every call goes through, time the cases it affects before and after the change. Before your first `cargo develop`, copy the installed `bpl`. In a kernel, run `shutil.copy(basedpl.worker.INSTALLED_BPL, '/tmp/<prefix>_bpl')`. In the shell, run `cp "$(command -v bpl)" /tmp/<prefix>_bpl`: the installed `bpl` is the one on the venv's `PATH`. Time that copy with `bpl='/tmp/<prefix>_bpl'`, and your build with the default. Another agent's `cargo develop` can replace the installed `bpl` at any time. The copy keeps your baseline fixed while agents build in parallel. Compare the two builds' times per item, which `time_cases` prints in picoseconds. A build from before a change to `rustymath::timing::COPIES` divides its costs by a different copy. On this Mac, a fused case over a large input can cost up to about 15% more in one process than in another, depending on whether `malloc` starts the input on a 32 KB boundary, where every one of a graph's blocks then ends. Time both builds the same way, each alone in a fresh process or at the same place in one run, and alternate them before you read a lone difference of that size as a regression. The speed test fails a case only past its budget. It misses any smaller slowdown. Other changes need only the speed test. Don't restore old code in the shared tree to get a baseline. On macOS, native timings of matrix products and decompositions mostly measure Accelerate. Rustymath's DEV.md says how to time rustymath's own kernels.
|
|
48
48
|
|
|
49
|
-
Cooperating tools share the machine's timing lock, `/tmp/aai-ws-timing.lock`. Timings take it exclusively. `cargo develop`, `cargo wait`, `cargo wasm`, the reference test, pytest, `check_file`, `check_page`, `bpl-nb` and `wasm_test` without `speed` take it shared. Rust code takes it through `rustymath::timing`. Python code takes it with `fastws.cargo.timing_lock`. Node can't lock a file. `wasm_test` and `speed_costs(wasm=DIR)` hold the lock in Python while Node runs. Other Rust tests and bare Cargo commands do not all take it. After five minutes a timing fails. A build or test run then goes ahead without the lock. After 30 seconds, an exclusive wait prints the processes with the lock file open. The list can include processes that are only waiting for the lock. Never take the lock yourself in
|
|
49
|
+
Cooperating tools share the machine's timing lock, `/tmp/aai-ws-timing.lock`. Timings take it exclusively. `cargo develop`, `cargo wait`, `cargo wasm`, the reference test, pytest, `check_file`, `check_page`, `bpl-nb` and `wasm_test` without `speed` take it shared. Rust code takes it through `rustymath::timing`. Python code takes it with `fastws.cargo.timing_lock`. Node can't lock a file. `wasm_test` and `speed_costs(wasm=DIR)` hold the lock in Python while Node runs. Other Rust tests and bare Cargo commands do not all take it. After five minutes a timing fails. A build or test run then goes ahead without the lock. After 30 seconds, an exclusive wait prints the processes with the lock file open. The list can include processes that are only waiting for the lock. Never take the lock yourself in a kernel process. Never coordinate timings by hand. A hold that outlasts its call blocks the timings that later calls launch. Native timings run on one thread and request user-interactive macOS QoS, which favours the performance cores. QoS is not CPU affinity.
|
|
50
50
|
|
|
51
51
|
Run `cargo wasm` during development only for browser work. Agents use `cargo wasm --out DIR`, then run the browser tests against that build with `basedpl.bpltests.wasm_test(DIR)` for `tests/wasm.mjs` and `wasm_test(DIR, speed=True)` for `tests/wasm-speed.mjs`. That speed test fails on a wasm budget only on Linux x86-64, CI's platform. On any other host it prints every cost and marks each case still over its budget after the retries, as `bpl --costs` does. This avoids replacing a module another agent is using. For other edits under `cfg(web)` or `host_web.rs`, check compilation with `cargo cs -p basedpl-wasm --target wasm32-unknown-unknown`, which checks the browser wrapper crate together with basedpl's browser code. `cargo cs` alone compiles neither.
|
|
52
52
|
|
|
53
|
-
###
|
|
53
|
+
### Machine code
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
`bpl-tests disasm PATTERN` shows the machine code of the function whose demangled name matches the regex `PATTERN`, read from the installed `bpl` with `objdump`. `--bpl PATH` reads a saved copy instead. Where several functions match, it lists their names. A function that is always inlined has no code of its own. Read its callers instead.
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
CARGO_INCREMENTAL=0 CC_x86_64_unknown_linux_gnu=clang cargo build --lib --release --target x86_64-unknown-linux-gnu --target-dir /tmp/aai-ws-x86 -p basedpl
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
In rustymath, use `-p rustymath`. The target is Linux because macOS builds leave out rustymath's native linear algebra kernels. That target is installed here. `-p` builds only the library, because the Python extension crates can't be built for Linux on this Mac. `CC_x86_64_unknown_linux_gnu=clang` lets Apple's `clang` assemble the x86-64 source in basedpl's `psm` dependency, because this Mac has no `x86_64-linux-gnu-gcc`. Don't move that setting into `.cargo/config.toml`. CI's Linux release builds also read that file, and their manylinux container has no `clang`. The build matches CI's `test` profile in its x86-64 flags and optimization settings. CI turns off the profile's incremental compilation with `CARGO_INCREMENTAL=0`. The command does the same, to split code into compilation units as CI does. Run it only to answer an x86-code question. It doesn't take the timing lock and can disturb timings running alongside it.
|
|
62
|
-
|
|
63
|
-
Read the newest `lib<crate>-<hash>.rlib` under `/tmp/aai-ws-x86/x86_64-unknown-linux-gnu/release/deps` with `objdump -d -r --no-show-raw-insn --disassemble-symbols=NAME`. `-r` identifies called functions. `objdump` warns for each archive object without that symbol. `-C` matches demangled names but splits them at commas; for a generic name containing a comma, get its mangled name from `nm` and omit `-C`. Generic code belongs to the crate that instantiates it. Don't use `--emit asm`: the resulting codegen-unit arrangement can inline differently from the build being inspected.
|
|
57
|
+
`--x86` shows the x86-64 code that CI and Linux run. It first builds basedpl's library and the rustymath library it links for Linux x86-64, into `/tmp/aai-ws-x86`, holding the timing lock shared. Where an unfinished edit stops basedpl compiling, it reads rustymath's library alone, and its output says so first. After a change, that build takes minutes. Use it only to answer an x86-code question. The target is Linux because macOS builds leave out rustymath's native linear algebra kernels. Only the libraries build, because the Python extension crates can't be built for Linux on this Mac. Their `release` profile matches CI's `test` profile in its x86-64 flags and optimization settings. The build sets `CC_x86_64_unknown_linux_gnu=clang` for itself. Don't move that setting into `.cargo/config.toml`. CI's Linux release builds also read that file, in a manylinux container that has no `clang`. Don't use `--emit asm`. A build with it splits code into other codegen units and inlines differently.
|
|
64
58
|
|
|
65
59
|
## Workspace, builds and CI
|
|
66
60
|
|
|
@@ -186,7 +180,7 @@ Float operations compute at the wider operand width. Exact operands round to the
|
|
|
186
180
|
|
|
187
181
|
Floats use IEEE NaN, infinity and signed zero. Comparison treats NaN as unequal; match/search treat it as one value, and grade puts it last. Exact arithmetic involving division by zero can produce those float values. Floor/ceiling retain an exact operand beside infinity. Beside NaN the language leaves their result open: NaN or the other argument, varying by platform. Their folds, scans, windows, products and repeated writes give NaN or the maximum or minimum of the items that aren't NaN, never another number, by the rule in rustymath's `Folds` doc. A loop that folds by them either passes its running result as the right argument, which `rustymath::reduce::maximum` keeps beside NaN, or folds through rustymath's `Max` and `Min`, as `Dyad::extremum` does. Monadic floor/ceiling/sign turn whole finite results into exact integers, including big integers; nonfinite results remain floats. Use `Number::float(value, width)` and explicit-width array construction outside `number.rs` instead of implicit f64 conversion.
|
|
188
182
|
|
|
189
|
-
Under `•prefs ["kinds":"static"]`, a result's kind follows from its arguments' kinds alone, as `meta/kinds.md` describes. `Numeric` carries `kinds` and `int`. `pervasive::map` chooses a dyadic call's kind through `joined`, which applies rustymath's `DType::common` after `Numeric::kind`. Atoms promote as arrays do. Python's API makes its scalar arguments weak through `Value::weakened`. The loops keep the failed results that `keeps` names: floats' NaNs, and the wrapped integers of objects that report `WRAPS`. The kernel tables choose float `⌊ ⌈ ×` and wrapping negation from `run.numeric()`. `Stored::build_at` keeps complex results complex. `Primitive::number` gives every pervasive result on numbers, as well as each step of the fold of numbers, and `statically` adjusts it. `Number::parse` keeps complex literals and checks integer literals against the `int` width.
|
|
183
|
+
Under `•prefs ["kinds":"static"]`, a result's kind follows from its arguments' kinds alone, as `meta/kinds.md` describes. `Numeric` carries `kinds` and `int`. `pervasive::map` chooses a dyadic call's kind through `joined`, which applies rustymath's `DType::common` after `Numeric::kind`. Comparisons, `⌈ ⌊` and bitwise functions compute at their arguments' storage width instead, where their results are the same at every width (`pervasive::first_kind`). Atoms promote as arrays do. Python's API makes its scalar arguments weak through `Value::weakened`. The loops keep the failed results that `keeps` names: floats' NaNs, and the wrapped integers of objects that report `WRAPS`. The kernel tables choose float `⌊ ⌈ ×` and wrapping negation from `run.numeric()`. `Stored::build_at` keeps complex results complex. `Primitive::number` gives every pervasive result on numbers, as well as each step of the fold of numbers, and `statically` adjusts it. `Number::parse` keeps complex literals and checks integer literals against the `int` width.
|
|
190
184
|
|
|
191
185
|
Settings live once for the whole process, in `settings.rs`, and are read from there, not passed through functions, except where a read is slow and on a hot path. Each setting that calls and scalar operations read is an atomic: the numeric settings, the hanzi aliases, the `batch` pref, the fusion report flag and fusion's small sizes. The display settings sit behind one lock. `•prefs` writes them, the lexer writes a source's leading `•prefs` header as it reads it, and `settings::reset` restores the defaults, as `]clear` and the test harnesses do. Nothing copies, captures or restores a setting. A pending array computes under the settings in force when it computes, and a module that `•load` runs changes the settings for the whole process. Rustymath holds the thread count, the one setting that it reads itself, and `•prefs` writes it there. Each call reads the store once where it starts: `pervasive::halves`, which every `pervasive` entry point goes through, `fusion::defers` and `defer`, `Domain::of`, the lexer and `Storage::item`'s complex items. Values derived from the settings within a call stay explicit arguments. `halves` passes 16-bit floats' widened settings to its inner call. The loop structs keep them because their closures run on rustymath's worker threads. A fused graph reads the settings once when it's built at forcing, for the same reason. `Number`'s tolerance methods and `Primitive::number` take them because they run once per item. The parser's leaves take a width marker's width, and `matches_within` takes `⍣∞`'s convergence tolerance. Imports build complex numbers with `Number::complex_in_session`: Python's `_Session.array` and the JSON protocol's `request`. JavaScript values hold no complex numbers.
|
|
192
186
|
|
|
@@ -222,7 +216,7 @@ Ordinary pervasive kernels also read pending copies through their maps. `fusion:
|
|
|
222
216
|
|
|
223
217
|
`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.
|
|
224
218
|
|
|
225
|
-
`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.
|
|
219
|
+
`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 map inside the run widens the run instead of beginning another, where the run is the innermost level (`batch::Entry::Widen`). The widening is a case with no definition, whose frame is the run's frame followed by the map's. The run's batches among the map's arguments lay over that frame (`batch::laid_over`), and a binding made before the widening lays over it when code reads it (`Session::read_binding`). A widened run that stops, or an Each whose results are arrays, falls back to calling the map's operand once for each of its cells inside 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.
|
|
226
220
|
|
|
227
221
|
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 do the object by whose rule each takes characters and the comparison objects that `with_comparison!` makes. 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.
|
|
228
222
|
|
|
@@ -176,6 +176,7 @@ The map calls its operand once for each cell instead where the operand:
|
|
|
176
176
|
- writes output, reads input, or formats a cell's value with `⍕`
|
|
177
177
|
- calls a system function that acts: one that reads or writes files, the network, the clock or the terminal, or that makes something new on each call, such as `•nget`, `•time` or `•uuid`
|
|
178
178
|
- writes to a name outside the map
|
|
179
|
+
- appends to a value that differs from cell to cell, or writes into one so that it would be held in mixed storage
|
|
179
180
|
- has a guard that catches an error
|
|
180
181
|
- gives a result that holds arrays as items
|
|
181
182
|
- calls a primitive that can't run on all the cells at once
|
|
@@ -29,7 +29,7 @@ x←2 4 9
|
|
|
29
29
|
⍴[[1]⋄[2]] ⍝ [2 1]ₓ
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Around literals, `[…]ₓ` makes every number exact, at any depth. Each number must be whole. After a list that holds anything else, `ₓ`
|
|
32
|
+
Around literals, `[…]ₓ` makes every number exact, at any depth. Each number must be whole. After a list that holds anything else, `ₓ` floors its numbers to exact integers, as [Superscripts and subscripts](../scripts.ipynb) describes.
|
|
33
33
|
|
|
34
34
|
```bpl
|
|
35
35
|
[1 0 1]ₓ≡1ₓ 0ₓ 1ₓ ⍝ $t
|
|
@@ -22,8 +22,8 @@ Each entry below names a difference from Dyalog APL, gives a short example, and
|
|
|
22
22
|
- [Brackets](glyphs/brackets.html.md): `[a b]` is a vector, even `[a]`. Inside brackets, spaces separate items. `;` separates items, each read as if parenthesised: `[1 2;3 4]` is `[(1 2) (3 4)]`, two items. `⋄` separates rows: `[1 2⋄3 4]` is a matrix. `"k":v` items make a record: `["a":1 "b":2]`.
|
|
23
23
|
- [Characters and strings](strings.html.md): `"abc"` is a character vector. `'a'` is one character atom. A single-quoted string such as `'abc'` is an error.
|
|
24
24
|
- [Indexing](indexing.html.md): `Y[I]` isn't BPL. `I⌷A` takes a cross product, while `A.[I J]` pairs its index arrays as NumPy does: with `i←⍳3`, `m.[i i]` is the diagonal. Positions count from 0. Negative positions count from the end.
|
|
25
|
-
- [Numbers](numbers.html.md): bare
|
|
26
|
-
- [Superscripts and subscripts](scripts.html.md): `x²` is `x*2`, `f⁻¹` is the inverse of `f`, `v₁` is `1⌷v`, and `nₓ` is
|
|
25
|
+
- [Numbers](numbers.html.md): a bare number is a float, as Python's `1.` is, and behaves as in Dyalog. BPL adds exact integers, as in `3ₓ`, which is Python's `3`. It also adds exact rationals, as in `1r3`. Arithmetic on exact numbers stays exact.
|
|
26
|
+
- [Superscripts and subscripts](scripts.html.md): `x²` is `x*2`, `f⁻¹` is the inverse of `f`, `v₁` is `1⌷v`, and `nₓ` is `⌊ₓn`. After a function, `ₓ` floors its results to exact integers: `7÷ₓ2` is `3ₓ`. Between names, `xⱼy` is `x+y×0ⱼ1`, `xₑy` is `x×10*y` and `xᵣy` is the exact quotient of `xₓ` by `yₓ`.
|
|
27
27
|
- [Keyed arrays](keyed.html.md): axes can have names and keys. `T.a` reads field `a` of a record, and `⊢.a` is `{⍵.a}`. Arithmetic pairs axes by name: with `i←⍳["i":3]` and `j←⍳["j":3]`, `i+j` is a 3×3 table.
|
|
28
28
|
- [Dfns](dfns.html.md): BPL has only dfns, with no tradfns and no control structures such as `:If`. A dfn returns its last statement. A predicate picks a body, as in BQN: `{⍵<0?-⍵;⍵} ¯3` is `3`. An absent `⍺` drops out of expressions, as BQN's `𝕨` does. A dfn operator's operands are `⍶` and `⍹`, not `⍺⍺` and `⍵⍵`. `⍢` calls the operator recursively. An error guard names its kinds as text, as in `"DOMAIN"::`.
|
|
29
29
|
- [Assignment](assignment.html.md): `←` is local. Modified and selective updates change the nearest binding. `[a b]←Y` destructures the items of `Y` by position. A space before `←` makes the whole run the target: `[[0 2]]⌷v ←0`.
|
|
@@ -19,7 +19,7 @@ BPL has two kinds of number. A bare number such as `0.5` is approximate: a float
|
|
|
19
19
|
| `⍬`, `⍬ₓ`, `⍬ₕ`, `⍬ₛ`, `⍬ₚ` | The approximate, the exact, and the 16-bit, 32-bit and 64-bit [empty vector](glyphs/zilde.qmd) |
|
|
20
20
|
| `[…]ₓ`, `(…)ₓ` | A list, or rows, in which every number is exact |
|
|
21
21
|
| `[…]ₕ`, `[…]ₛ`, `[…]ₚ` | A list, or rows, in which every real number is a 16-bit, 32-bit or 64-bit float, and every complex number has parts of that width, or 32-bit parts after `ₕ` |
|
|
22
|
-
| `xⱼy`, `xₑy`, `xᵣy` | Between two items, such as names: `x+y×0ⱼ1`, `x×10*y` and `x
|
|
22
|
+
| `xⱼy`, `xₑy`, `xᵣy` | Between two items, such as names: `x+y×0ⱼ1`, `x×10*y` and the exact quotient of `xₓ` by `yₓ`, as one term |
|
|
23
23
|
|
|
24
24
|
A plain `e`, `j` or `r` starts a name unless the rest of a number follows it, as in `1e5`, `1r3` and `2j3`. Results display with the subscript forms, as in `1ᵣ3`, `2ⱼ3` and `1ₑ20`. A subscript form that the rest of a number doesn't follow, or one between two other items such as names, joins the items on each side into one term, as a literal is one, with the value the table gives. A literal on the left gives what the all-literal form gives: with `n←3`, `2ₑn` is `2ₑ3`.
|
|
25
25
|
|
|
@@ -96,7 +96,7 @@ m.[[1]]←1
|
|
|
96
96
|
m ⍝ $f 1 $f
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
Around literals, `[…]ₓ` and `(…)ₓ` make every number exact, at any depth. Each number must be whole. After a list or group that holds anything else, as after a name, `ₓ`
|
|
99
|
+
Around literals, `[…]ₓ` and `(…)ₓ` make every number exact, at any depth. Each number must be whole. After a list or group that holds anything else, as after a name, `ₓ` floors to exact integers, as [Superscripts and subscripts](scripts.ipynb) describes. A vector of exact integers displays as `[…]ₓ`, and rows of them as `(…)ₓ`. `⍕` writes them the same way:
|
|
100
100
|
|
|
101
101
|
```bpl
|
|
102
102
|
[1 0 1]ₓ≡1ₓ 0ₓ 1ₓ ⍝ $t
|
|
@@ -209,7 +209,7 @@ The [`⌈`](glyphs/upstile.qmd) and [`⌊`](glyphs/downstile.qmd) pages give the
|
|
|
209
209
|
|
|
210
210
|
## Static kinds
|
|
211
211
|
|
|
212
|
-
Some functions choose a result's kind from their arguments' values. `√¯4` is complex because the argument is negative, `1j0` is a float because its imaginary part is zero, and an exact integer that overflows grows. Under [`•prefs`](system/prefs.qmd) `["kinds":"static"]`, a result's kind follows from the function and its arguments' kinds alone. A fused computation needs that, because it decides each result's kind before it runs. Real arguments give real results, with NaN outside a function's domain, and complex results stay complex. `⌊`, `⌈` and monadic `×` of floats give floats, and integer `÷` gives floats:
|
|
212
|
+
Some functions choose a result's kind from their arguments' values. `√¯4` is complex because the argument is negative, `1j0` is a float because its imaginary part is zero, and an exact integer that overflows grows. Under [`•prefs`](system/prefs.qmd) `["kinds":"static"]`, a result's kind follows from the function and its arguments' kinds alone. A fused computation needs that, because it decides each result's kind before it runs. Real arguments give real results, with NaN outside a function's domain, and complex results stay complex. `⌊`, `⌈` and monadic `×` of floats give floats, and integer `÷` gives floats. With `ₓ` after them they give integers, as Rust's `as` converts a float: NaN gives 0, and a value past the `int` width's range gives its largest or smallest integer:
|
|
213
213
|
|
|
214
214
|
```bpl
|
|
215
215
|
•prefs ["kinds":"static"]
|
|
@@ -217,6 +217,9 @@ Some functions choose a result's kind from their arguments' values. `√¯4` is
|
|
|
217
217
|
0j1×0j1 ⍝ ¯1ⱼ0
|
|
218
218
|
⌊2.5 ∞ ⍝ 2 ∞
|
|
219
219
|
7ₓ÷2ₓ ⍝ 3.5
|
|
220
|
+
⌊ₓ2.5 ¯2.5 ⍝ [2 ¯3]ₓ
|
|
221
|
+
7ₓ÷ₓ2ₓ ⍝ 3ₓ
|
|
222
|
+
⌊ₓ $n ∞ ⍝ [0 9223372036854775807]ₓ
|
|
220
223
|
•prefs ["kinds":"dynamic"]
|
|
221
224
|
```
|
|
222
225
|
|
|
@@ -999,7 +999,7 @@
|
|
|
999
999
|
"\n",
|
|
1000
1000
|
"NumPy float and complex scalars keep their explicit widths, including inside sequences. A list's items combine under BPL's usual joining rules: `[1, 2.5]` gives two floats. A dict's values each keep their own kind, as a record's fields do. In `{\"name\": \"x\", \"age\": 3, \"score\": 2.5}`, `age` stays exact beside the float `score`. Its `name` is the character atom `'x'`.\n",
|
|
1001
1001
|
"\n",
|
|
1002
|
-
"`.np` or `np.asarray(a)` always produces an ndarray. Booleans use `bool`. Integers use the width BPL stores them at
|
|
1002
|
+
"`.np` or `np.asarray(a)` always produces an ndarray. Booleans use `bool`. Integers use the width BPL stores them at, `uint8`, `int16`, `int32` or `int64`, under dynamic kinds. Under static kinds they use the width they compute at, which is at least the `int` pref, so NumPy arithmetic on them wraps where BPL's does. Floats use the width BPL stores them at, `float16`, `float32` or `float64`. A NumPy `float16` or `float32` array keeps its width in BPL. Complex arrays use `complex64` or `complex128`, preserving the stored width. Fractions, large integers, nested arrays and mixed exact and approximate values use `object`. Character arrays use `U1`. The arrays inside a `.py` result, and the columns of a `.df` result, use the same dtypes."
|
|
1003
1003
|
]
|
|
1004
1004
|
},
|
|
1005
1005
|
{
|
|
@@ -962,7 +962,7 @@
|
|
|
962
962
|
"id": "a2e00b5b",
|
|
963
963
|
"metadata": {},
|
|
964
964
|
"source": [
|
|
965
|
-
"The subscript letters `ₓ`, `ⱼ`, `ₑ` and `ᵣ` are parts of numbers, as in `3ₓ` and `1ᵣ3`. [Numbers](numbers.qmd) covers them. Between two other items, such as names, `ⱼ`, `ₑ` and `ᵣ` join the items into one [number](numbers.qmd#writing-numbers): `xⱼy` is `x+y×0ⱼ1
|
|
965
|
+
"The subscript letters `ₓ`, `ⱼ`, `ₑ` and `ᵣ` are parts of numbers, as in `3ₓ` and `1ᵣ3`. [Numbers](numbers.qmd) covers them. Between two other items, such as names, `ⱼ`, `ₑ` and `ᵣ` join the items into one [number](numbers.qmd#writing-numbers): `xⱼy` is `x+y×0ⱼ1`, and `xᵣy` is the exact quotient of `xₓ` by `yₓ`, under static kinds too. After a name, or any item but a number or a list of literals, `ₓ` floors the item's numbers to exact integers. `xₓ` is `⌊ₓx`:"
|
|
966
966
|
]
|
|
967
967
|
},
|
|
968
968
|
{
|
|
@@ -986,6 +986,74 @@
|
|
|
986
986
|
"xₓ"
|
|
987
987
|
]
|
|
988
988
|
},
|
|
989
|
+
{
|
|
990
|
+
"cell_type": "markdown",
|
|
991
|
+
"id": "f58b3b2a",
|
|
992
|
+
"metadata": {},
|
|
993
|
+
"source": [
|
|
994
|
+
"After a function, `ₓ` floors the function's results to exact integers, under either kinds. Under static kinds, which keep a failed result, it converts as Rust's `as` converts a float, into the `int` width: NaN gives `0`, and a value past the width's range, `∞` included, gives its largest or smallest integer.\n",
|
|
995
|
+
"\n",
|
|
996
|
+
"`⌊ₓ`, `⌈ₓ` and dyadic `÷ₓ`, which divides and floors as Python's `//` does, each compute their integers in one pass:"
|
|
997
|
+
]
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
"cell_type": "code",
|
|
1001
|
+
"execution_count": null,
|
|
1002
|
+
"id": "fb125557",
|
|
1003
|
+
"metadata": {},
|
|
1004
|
+
"outputs": [
|
|
1005
|
+
{
|
|
1006
|
+
"data": {
|
|
1007
|
+
"text/plain": [
|
|
1008
|
+
"[3 ¯4 3]ₓ"
|
|
1009
|
+
]
|
|
1010
|
+
},
|
|
1011
|
+
"metadata": {},
|
|
1012
|
+
"output_type": "display_data"
|
|
1013
|
+
}
|
|
1014
|
+
],
|
|
1015
|
+
"source": [
|
|
1016
|
+
"7 ¯7 7.5÷ₓ2"
|
|
1017
|
+
]
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
"cell_type": "markdown",
|
|
1021
|
+
"id": "255c7890",
|
|
1022
|
+
"metadata": {},
|
|
1023
|
+
"source": [
|
|
1024
|
+
"A float width's marker, `ₕ`, `ₛ` or `ₚ`, works the same way. After a function it makes the function's results floats of that width, and after an array it converts the array, as [`•float`](system/float.qmd) does:"
|
|
1025
|
+
]
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
"cell_type": "code",
|
|
1029
|
+
"execution_count": null,
|
|
1030
|
+
"id": "04c3990d",
|
|
1031
|
+
"metadata": {},
|
|
1032
|
+
"outputs": [
|
|
1033
|
+
{
|
|
1034
|
+
"data": {
|
|
1035
|
+
"text/plain": [
|
|
1036
|
+
"¯3ₛ"
|
|
1037
|
+
]
|
|
1038
|
+
},
|
|
1039
|
+
"metadata": {},
|
|
1040
|
+
"output_type": "display_data"
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
"data": {
|
|
1044
|
+
"text/plain": [
|
|
1045
|
+
"[3.7 ¯2.5]ₛ"
|
|
1046
|
+
]
|
|
1047
|
+
},
|
|
1048
|
+
"metadata": {},
|
|
1049
|
+
"output_type": "display_data"
|
|
1050
|
+
}
|
|
1051
|
+
],
|
|
1052
|
+
"source": [
|
|
1053
|
+
"-ₛ 3\n",
|
|
1054
|
+
"xₛ"
|
|
1055
|
+
]
|
|
1056
|
+
},
|
|
989
1057
|
{
|
|
990
1058
|
"cell_type": "markdown",
|
|
991
1059
|
"id": "0181955a",
|
|
@@ -998,7 +1066,7 @@
|
|
|
998
1066
|
"- `SYNTAX`: `ⱼ`, `ₑ` or `ᵣ` beside a function or a space, as in `f←- ⋄ fⱼ1`\n",
|
|
999
1067
|
"- `INDEX`: the position is outside the leading axis\n",
|
|
1000
1068
|
"- `LENGTH`: the item is a unit, which has no axis to select from\n",
|
|
1001
|
-
"- `DOMAIN`: `ₓ`
|
|
1069
|
+
"- `DOMAIN`: `ₓ` on a complex number, or under dynamic kinds on an infinity or NaN, as in `1÷ₓ0`"
|
|
1002
1070
|
]
|
|
1003
1071
|
},
|
|
1004
1072
|
{
|
|
@@ -2618,7 +2618,7 @@
|
|
|
2618
2618
|
{
|
|
2619
2619
|
"data": {
|
|
2620
2620
|
"text/plain": [
|
|
2621
|
-
"
|
|
2621
|
+
"3 4 5 2 4"
|
|
2622
2622
|
]
|
|
2623
2623
|
},
|
|
2624
2624
|
"metadata": {},
|
|
@@ -2638,7 +2638,7 @@
|
|
|
2638
2638
|
{
|
|
2639
2639
|
"data": {
|
|
2640
2640
|
"text/plain": [
|
|
2641
|
-
"0.
|
|
2641
|
+
"0.6628167745 0.8427274246"
|
|
2642
2642
|
]
|
|
2643
2643
|
},
|
|
2644
2644
|
"metadata": {},
|
|
@@ -2674,7 +2674,7 @@
|
|
|
2674
2674
|
{
|
|
2675
2675
|
"data": {
|
|
2676
2676
|
"text/plain": [
|
|
2677
|
-
"
|
|
2677
|
+
"3 20 28 11 1 42 4 36 10 15 39 38 7"
|
|
2678
2678
|
]
|
|
2679
2679
|
},
|
|
2680
2680
|
"metadata": {},
|
|
@@ -37,7 +37,7 @@ Numbers, `∞`, `¯∞`, `⍬`, characters, strings and the constants `$t`, `$f`
|
|
|
37
37
|
|
|
38
38
|
`''` and `""` are the same empty character vector. A double-quoted string can span lines. Every line ending inside it reads as one newline, and its indentation stays as written.
|
|
39
39
|
|
|
40
|
-
`ₓ` straight after a number, `⍬`, or a `]` or `)` that closes literals makes every number it covers exact, as in `5ₓ`, `[1 2]ₓ` and `(0 1⋄2 3)ₓ`. After anything else,
|
|
40
|
+
`ₓ` straight after a number, `⍬`, or a `]` or `)` that closes literals makes every number it covers exact, as in `5ₓ`, `[1 2]ₓ` and `(0 1⋄2 3)ₓ`. After anything else, `ₓ` floors to exact integers: `nₓ` is `⌊ₓn`, and `÷ₓ` divides and floors, as [Superscripts and subscripts](scripts.ipynb) describes.
|
|
41
41
|
|
|
42
42
|
After a number, `e`, `j` or `r`, or its subscript `ₑ`, `ⱼ` or `ᵣ`, continues the number only when the rest of a number follows it, as in `1e5`, `2ⱼ3` and `1r3`. Otherwise a plain letter starts a name: `2edges` is `2` beside the name `edges`. A subscript there, or between any two items, joins the items on each side into one term, as [Numbers](numbers.qmd#writing-numbers) describes: `2ₑn` is `2×10*n`.
|
|
43
43
|
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
- `"one call"` makes one call for targets at distinct positions.
|
|
21
21
|
- `"item by item"` calls the function once for each target, as a dfn does.
|
|
22
22
|
- `fallbacks` has a row for each [map](../terms.qmd#term-map) that called its operand once for each cell after its [batched call](../evaluation.qmd#functions-and-effects) fell back, or without a batched call because an earlier one stopped. `items` is the number of cells, and `reason` says why:
|
|
23
|
-
- `"an effect"`: the operand writes output, reads input, formats a cell's value with `⍕`, or runs a system function that acts, such as `•nget` or `•time`. A batched call would do each of these once for all the cells.
|
|
24
|
-
- `"a write"`: the operand writes to a name outside the map, or a side of a guard on a cell's value writes to a name outside its dfn.
|
|
23
|
+
- `"an effect"`: the operand writes output, reads input, formats a cell's value with `⍕`, or runs a system function that acts, such as `•nget` or `•time`. A batched call would do each of these once for all the cells.
|
|
24
|
+
- `"a write"`: the operand writes to a name outside the map, or a side of a guard on a cell's value writes to a name outside its dfn, or the operand appends to a value that differs from cell to cell, or writes into one so that it would be held in mixed storage.
|
|
25
25
|
- `"a cell's value"`: the operand reads a cell's value to give a count or a position, as `2×⍣⍵` does. A predicate on a cell's value doesn't stop the batched call: each side of the guard runs once, on the cells that take it, as [Evaluation](../evaluation.qmd#functions-and-effects) describes.
|
|
26
|
-
- `"no batch rule"`: the operand calls a function with no rule for batches of these arguments, such as
|
|
26
|
+
- `"no batch rule"`: the operand calls a function with no rule for batches of these arguments, such as `∪`, or the two sides of a guard on a cell's value give results of different kinds or shapes. Where the stop comes from a primitive's call, the primitive's glyph follows, as in `"no batch rule for ∪"`. A kernel that reads a cell's number directly gives no glyph.
|
|
27
27
|
- `"too many items"`: a call would repeat an array that every cell shares into far more items than its arguments hold, and the array is too large for the map to run on chunks of cells instead, as [Evaluation](../evaluation.qmd#functions-and-effects) describes.
|
|
28
28
|
- `"a caught error"`: a guard would catch an error.
|
|
29
29
|
- `"a recursive call"`: a guard on a cell's value runs in a recursive call of a dfn whose guard already split the cells, as in `{⍵<2?⍵;(∇⍵-1)+∇⍵-2}¨v`.
|
|
@@ -39,11 +39,14 @@
|
|
|
39
39
|
- `"item lanes"`: a fold or scan by a function with no kernel for its arguments, such as a primitive on mixed storage or a dfn on a lane that no batched map took, called the function on each pair of items in turn.
|
|
40
40
|
- `"number parts"`: monadic [`∨`](../glyphs/vee.qmd) or [`∧`](../glyphs/wedge.qmd) took the parts of integers or exact numbers one at a time, where floats and complex numbers take one pass.
|
|
41
41
|
- `"nested labels"`, `"label ids"` and `"label offsets"`: a selection from a nested array labelled or placed its items one at a time, or read positions that had no plan.
|
|
42
|
+
- `"key groups"`: [Key](../glyphs/quad-equal.qmd) called its operand once for each group, where no fast combination covered it.
|
|
43
|
+
- `"batch cells"`: a batched map ran a system function, or a deal by [`¿`](../glyphs/inverted-question.qmd), once for each cell in turn.
|
|
44
|
+
- `"inverse scan"`: the inverse of a scan by a function with no kernel called the function's inverse on each pair of neighbouring items in turn.
|
|
42
45
|
- `declined` has a row for each faster route that code considered and didn't take. A decline explains why a slower route ran. `route` names the route, `reason` says why code didn't take it, and `items` counts the items that its declines concerned, summed for each route and reason. The routes are:
|
|
43
46
|
- `"fusion"`: a call that could have joined a fused group ran on its own, because of `"16-bit floats"`, `"no float array"`, `"an exact argument"`, `"a result at another width"`, `"keys, names or a renderer"` or `"an argument of another kind or width, or with keys"`. A pending array also ran without a group where its call reads `"a comparison computed outside the graph"`.
|
|
44
47
|
- `"fused fold"`: a fold computed its argument instead of reading through its group, because `"another array holds the array"`, as a name does, because the argument is `"a copy that no call moves under"` or reads `"a comparison computed outside the graph"`, or because of `"a fold that its graph can't run"`.
|
|
45
48
|
- A fast combination's name, as in `"partial grade"`, with `"arguments that don't suit it"`: the general path ran instead.
|
|
46
|
-
- `"batching"`: a map didn't try a batched call, because `"the batch pref is off"`, because of `"a label level or
|
|
49
|
+
- `"batching"`: a map didn't try a batched call, because `"the batch pref is off"`, because of `"a label level, or a ∂ call inside a batched run"` or `"named axes"`, or because of `"an argument too large to lay over the frame"` or `"an argument that isn't compact or has a named axis"`.
|
|
47
50
|
- `"in place"`: a kernel copied an argument's items into a buffer instead of reading them where they are, because of `"repeats of each item"`, `"a cycle that wraps"`, `"steps other than a forward run"` or `"a repeated item"`.
|
|
48
51
|
|
|
49
52
|
Each of `fused`, `stored`, `forced`, `fast`, `accumulations`, `fallbacks`, `mixed`, `itemwise` and `declined` is a record of columns, as `•csv` gives a table, so `(•explain t).fast.combination` lists the combinations taken. `•prefs ["fusion":$t]` writes each forcing call and assignment as it happens. Nothing is recorded outside `•explain`.
|
|
@@ -33,7 +33,7 @@ Display shows part of an array of more than `limit` items: the first and last `e
|
|
|
33
33
|
|
|
34
34
|
`float` sets the default width of floats, in bits: the width of bare numbers in code parsed after the change, of numbers that `•csv`, `•json`, `•vfi` and `•image` read, of random numbers, and of floats that a function gives from exact arguments. Code already parsed keeps its numbers. A change partway through some code therefore applies from the next input, or from text that [`⍎`](../glyphs/hydrant.qmd) parses later. Leading `•prefs` calls on a literal record are the exception. They run before the rest of their code is parsed, as in the examples below. A script, a notebook cell, a line typed at the REPL, a module that [`•load`](load.qmd) runs and text that `⍎` runs can each set its own width this way. See [Numbers](../numbers.qmd#float-widths).
|
|
35
35
|
|
|
36
|
-
`kinds` sets whether a result's kind can depend on its arguments' values. Under the default, `"dynamic"`, `√¯4` gives `0ⱼ2`, `1j0` reads as the float `1`, `⌊2.5` gives the exact integer `2`, `7ₓ÷2ₓ` gives `7ᵣ2`, and exact integers grow without limit. Under `"static"`, each result's kind follows from the function, its arguments' kinds and these settings. Real arguments give real results, with NaN outside a function's domain. Complex results stay complex. `⌊`, `⌈` and monadic `×` of floats give floats, and integer `÷` gives floats. Integers compute at the `int` width, or at a wider integer's width, and wrap where a result doesn't fit. Exact fractions stay exact. An integer beside a float takes the float's width. An atom promotes as an array does. Fused computations and a GPU need each result's kind before they run, and under static kinds more calls fuse, as the examples under `fusion` show. A literal reads under the settings in force when its code is parsed, as with `float`. See [Numbers](../numbers.qmd#static-kinds).
|
|
36
|
+
`kinds` sets whether a result's kind can depend on its arguments' values. Under the default, `"dynamic"`, `√¯4` gives `0ⱼ2`, `1j0` reads as the float `1`, `⌊2.5` gives the exact integer `2`, `7ₓ÷2ₓ` gives `7ᵣ2`, and exact integers grow without limit. Under `"static"`, each result's kind follows from the function, its arguments' kinds and these settings. Real arguments give real results, with NaN outside a function's domain. Complex results stay complex. `⌊`, `⌈` and monadic `×` of floats give floats, and integer `÷` gives floats, where `⌊ₓ`, `⌈ₓ`, `×ₓ` and `÷ₓ` give integers, converting as Rust's `as` does. Integers compute at the `int` width, or at a wider integer's width, and wrap where a result doesn't fit. Exact fractions stay exact. An integer beside a float takes the float's width. An atom promotes as an array does. Fused computations and a GPU need each result's kind before they run, and under static kinds more calls fuse, as the examples under `fusion` show. A literal reads under the settings in force when its code is parsed, as with `float`. See [Numbers](../numbers.qmd#static-kinds).
|
|
37
37
|
|
|
38
38
|
`threads` sets how many threads large calls split across. A call splits only when it has enough work to repay the extra threads. Float results can differ in their last bits between thread counts. The default, 0, uses the number in the `RAYON_NUM_THREADS` environment variable where it's set, and one thread for each core otherwise. 1 runs every call on the thread that evaluates the code. When several BPL processes run at once, such as a pool of Python workers, set 1 in each of them to keep them from competing for the cores. The browser build runs every call on one thread, whatever the setting.
|
|
39
39
|
|
|
@@ -309,20 +309,26 @@ impl PyArray {
|
|
|
309
309
|
/// Whether NumPy can read the items through the buffer protocol: compact storage, or a structural copy that reads compact items through an affine map.
|
|
310
310
|
#[getter]
|
|
311
311
|
fn exports(&self) -> PyResult<bool> { Ok(lendable(self.value()?).is_some()) }
|
|
312
|
-
/// Exports the items read-only and without a copy, so that NumPy can't change a BPL value through them. An unbuilt structural copy with an affine read, such as windows or a reversal, lends its source's items with strides, without being built.
|
|
312
|
+
/// Exports the items read-only and without a copy, so that NumPy can't change a BPL value through them. An unbuilt structural copy with an affine read, such as windows or a reversal, lends its source's items with strides, without being built. Integers that static kinds store narrower than their kind export as a copy at the kind's width (`Value::widened_for_export`), so NumPy and rustymath compute at that width.
|
|
313
313
|
unsafe fn __getbuffer__(slf: Bound<'_, Self>, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
|
|
314
314
|
let value = slf.borrow().value()?.clone();
|
|
315
|
+
if let Some(items) = value.widened_for_export() {
|
|
316
|
+
let dtype = items.dtype();
|
|
317
|
+
// SAFETY: `items` holds every item of `value` in row-major order, and the export holds `items`.
|
|
318
|
+
return unsafe { rustymath_buffer::lend(view, flags, slf.py(), items, |b| b.view().as_ptr(), dtype, value.shape(), None) };
|
|
319
|
+
}
|
|
315
320
|
let (items, offset, strides) = lendable(&value).ok_or_else(|| PyBufferError::new_err("an array of mixed or exact items has no buffer"))?;
|
|
316
321
|
let dtype = items.view().expect("lendable items are compact").dtype();
|
|
317
322
|
// SAFETY: the offset and strides reach only items of `items`, as the copy's map does. An atom holds its items inline, so the pointer comes from the copy that the export holds.
|
|
318
323
|
unsafe { rustymath_buffer::lend(view, flags, slf.py(), items, |v| v.view().expect("the items are compact").as_ptr().add(offset * dtype.bytes()), dtype, value.shape(), strides.as_deref()) }
|
|
319
324
|
}
|
|
320
|
-
/// The items for NumPy to view writably: moved with no copy where nothing else holds them, and copied otherwise. For items it can't move, such as exact numbers, it still empties the array and returns `None`, so the caller copies them first.
|
|
325
|
+
/// The items for NumPy to view writably: moved with no copy where nothing else holds them, and copied otherwise. Integers that static kinds store narrower than their kind come widened to it (`Value::widened_for_export`). For items it can't move, such as exact numbers, it still empties the array and returns `None`, so the caller copies them first.
|
|
321
326
|
fn own(&mut self) -> PyResult<Option<Owned>> {
|
|
322
327
|
self.value()?;
|
|
323
328
|
let value = self.inner.take().expect("checked above");
|
|
324
329
|
let shape = value.shape().to_vec();
|
|
325
|
-
|
|
330
|
+
let items = match value.widened_for_export() { Some(items) => Some(items), None => value.into_buffer().ok() };
|
|
331
|
+
Ok(items.map(|items| Owned::new(items, &shape)))
|
|
326
332
|
}
|
|
327
333
|
fn __repr__(&self) -> PyResult<String> { Ok(self.value()?.to_string()) }
|
|
328
334
|
fn literal(&self) -> PyResult<String> { Ok(self.value()?.literal()) }
|