Compare commits

..

86 Commits

Author SHA1 Message Date
Vyacheslav Matyukhin
9e2eace05e
Merge pull request #1231 from quantified-uncertainty/project-in-editors
Project in editors and remove warnings
2022-10-14 18:06:49 +03:00
Vyacheslav Matyukhin
a0000cd179
Merge branch 'develop' into project-in-editors 2022-10-13 03:36:08 +04:00
Vyacheslav Matyukhin
56771820aa
Merge pull request #965 from quantified-uncertainty/experiment-10.0rc1
bump `rescript` and `@rescript/std` to `10.0.1`
2022-10-13 02:25:23 +03:00
Vyacheslav Matyukhin
33f0647be8
Merge pull request #1260 from quantified-uncertainty/drop-bisect-ppx
remove bisect_ppx
2022-10-13 02:24:53 +03:00
cab
878c6f3d4b
Removed nixos.sh
Also added a note in README.md for NixOS users
2022-10-13 01:03:16 +04:00
Vyacheslav Matyukhin
4cd045b9c8
format rescript 2022-10-12 20:11:28 +04:00
Vyacheslav Matyukhin
a617ec0436
update coverage name in prettierignore 2022-10-12 20:00:27 +04:00
Vyacheslav Matyukhin
80cc20ac72
fix tests 2022-10-12 19:49:14 +04:00
Vyacheslav Matyukhin
666524a36a
Merge branch 'drop-bisect-ppx' into experiment-10.0rc1 2022-10-12 19:36:23 +04:00
Vyacheslav Matyukhin
2ed3633fe5
coverage:local echo note 2022-10-12 19:31:44 +04:00
Vyacheslav Matyukhin
deb88c60fb
Merge branch 'develop' into drop-bisect-ppx 2022-10-12 19:12:25 +04:00
Vyacheslav Matyukhin
838d13086a
remove nyc dependency, jest is enough for coverage 2022-10-12 19:09:17 +04:00
cab
11e80941bc
nix: remove bisect_ppx from build 2022-10-12 18:32:08 +04:00
dependabot[bot]
e11cca658e
Merge pull request #1248 from quantified-uncertainty/dependabot/npm_and_yarn/jest-environment-jsdom-29.1.2 2022-10-12 12:38:35 +00:00
dependabot[bot]
2d0949c3f6
⬆️ Bump jest-environment-jsdom from 29.0.3 to 29.1.2
Bumps [jest-environment-jsdom](https://github.com/facebook/jest/tree/HEAD/packages/jest-environment-jsdom) from 29.0.3 to 29.1.2.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.1.2/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-12 12:30:46 +00:00
Vyacheslav Matyukhin
8dac70082c
remove bisect_ppx 2022-10-12 16:21:07 +04:00
Vyacheslav Matyukhin
d7e548d84e
Merge pull request #1259 from quantified-uncertainty/fetch-depth-for-coverage
fetch-depth for coverage job
2022-10-12 15:00:30 +03:00
dependabot[bot]
2cd22fa8e5
Merge pull request #1245 from quantified-uncertainty/dependabot/npm_and_yarn/framer-motion-7.5.3 2022-10-12 11:48:03 +00:00
dependabot[bot]
21e4908fbf
Merge pull request #1247 from quantified-uncertainty/dependabot/npm_and_yarn/web-vitals-3.0.3 2022-10-12 11:40:54 +00:00
dependabot[bot]
07802ff151
Merge pull request #1252 from quantified-uncertainty/dependabot/npm_and_yarn/react-hook-form-7.37.0 2022-10-12 11:40:33 +00:00
dependabot[bot]
f079c1f6ef
Merge pull request #1249 from quantified-uncertainty/dependabot/npm_and_yarn/ts-jest-29.0.3 2022-10-12 11:40:25 +00:00
dependabot[bot]
91a3a066c2
Merge pull request #1251 from quantified-uncertainty/dependabot/npm_and_yarn/chalk-5.1.0 2022-10-12 11:40:24 +00:00
dependabot[bot]
8608faa79b
Merge pull request #1250 from quantified-uncertainty/dependabot/npm_and_yarn/types/node-18.8.3 2022-10-12 11:39:53 +00:00
Vyacheslav Matyukhin
e076bd935f
fetch-depth for coverage job 2022-10-12 15:35:42 +04:00
dependabot[bot]
fdcdf2fa3d
Merge pull request #1253 from quantified-uncertainty/dependabot/npm_and_yarn/jsdom-20.0.1 2022-10-12 11:34:14 +00:00
Vyacheslav Matyukhin
2d9fea4f21
Merge pull request #1244 from quantified-uncertainty/squiggle-cli-docs-2022-10-10
tweak: Add more verbose documentation to the cli README
2022-10-12 10:59:50 +03:00
Vyacheslav Matyukhin
f6322fad13
Merge pull request #1255 from quantified-uncertainty/fix-docs-truncate-right
Should be truncateRight
2022-10-12 10:36:50 +03:00
Sam Nolan
699960d220 Should be truncateRight 2022-10-12 14:30:38 +11:00
Ozzie Gooen
ac0cc01852 Ran formatting 2022-10-11 18:58:35 -07:00
Ozzie Gooen
c65a9d3ae6
Merge pull request #1238 from quantified-uncertainty/fix-manual-run
Fix manual run
2022-10-11 14:20:34 -07:00
dependabot[bot]
113be7d8cb
⬆️ Bump jsdom from 20.0.0 to 20.0.1
Bumps [jsdom](https://github.com/jsdom/jsdom) from 20.0.0 to 20.0.1.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/master/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/20.0.0...20.0.1)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:37:48 +00:00
dependabot[bot]
2596d1a695
⬆️ Bump react-hook-form from 7.36.1 to 7.37.0
Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.36.1 to 7.37.0.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.36.1...v7.37.0)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:34:57 +00:00
dependabot[bot]
41153988d8
⬆️ Bump chalk from 5.0.1 to 5.1.0
Bumps [chalk](https://github.com/chalk/chalk) from 5.0.1 to 5.1.0.
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/compare/v5.0.1...v5.1.0)

---
updated-dependencies:
- dependency-name: chalk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:34:54 +00:00
dependabot[bot]
8c7340185c
⬆️ Bump @types/node from 18.8.0 to 18.8.3
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.8.0 to 18.8.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:34:12 +00:00
dependabot[bot]
bd4250c793
⬆️ Bump ts-jest from 29.0.2 to 29.0.3
Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 29.0.2 to 29.0.3.
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.0.2...v29.0.3)

---
updated-dependencies:
- dependency-name: ts-jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:33:01 +00:00
dependabot[bot]
c204ce37ad
⬆️ Bump web-vitals from 3.0.2 to 3.0.3
Bumps [web-vitals](https://github.com/GoogleChrome/web-vitals) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/GoogleChrome/web-vitals/releases)
- [Changelog](https://github.com/GoogleChrome/web-vitals/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GoogleChrome/web-vitals/compare/v3.0.2...v3.0.3)

---
updated-dependencies:
- dependency-name: web-vitals
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:31:36 +00:00
dependabot[bot]
344ee0ce17
⬆️ Bump framer-motion from 7.5.1 to 7.5.3
Bumps [framer-motion](https://github.com/framer/motion) from 7.5.1 to 7.5.3.
- [Release notes](https://github.com/framer/motion/releases)
- [Changelog](https://github.com/framer/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/framer/motion/compare/v7.5.1...v7.5.3)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 15:28:06 +00:00
71db023f0c tweak: Add more verbose documentation to the cli README 2022-10-10 14:24:42 +01:00
Vyacheslav Matyukhin
bd94e51b31
Merge pull request #1240 from quantified-uncertainty/1109-fix
note that SquiggleEditorWithImportedBindings is broken (fixes #1109)
2022-10-10 12:35:36 +03:00
Vyacheslav Matyukhin
964e95f598
Merge pull request #1242 from quantified-uncertainty/changelog
Changelog page
2022-10-10 12:35:24 +03:00
Sam Nolan
98454a87b5 Get projects working in Playgrounds 2022-10-10 14:23:04 +11:00
Vyacheslav Matyukhin
5efb66c3e5
changelog page 2022-10-09 15:27:47 +04:00
Vyacheslav Matyukhin
2389dff69a
note that SquiggleEditorWithImportedBindings is broken (fixes #1109) 2022-10-09 15:04:45 +04:00
Vyacheslav Matyukhin
1ea3c975d5
Merge pull request #1233 from quantified-uncertainty/turborepo
Turborepo
2022-10-09 13:03:20 +03:00
Vyacheslav Matyukhin
1e13dc71f1
Merge branch 'develop' into turborepo 2022-10-09 13:47:41 +04:00
Vyacheslav Matyukhin
a515d9560c
Merge pull request #1232 from cab404/cab/esbuild-vsix
vscode-ext: move to esbuild bundling, cleanup
2022-10-09 12:42:38 +03:00
cab
9582be7331
lint 2022-10-09 13:28:59 +04:00
Vyacheslav Matyukhin
827bb43354
fix #1236 2022-10-09 13:15:51 +04:00
Vyacheslav Matyukhin
27c4c9acf2
playground and autorun tests (incomplete) 2022-10-09 13:15:26 +04:00
cab
28e944dd04
tsconfig: switch includes 2022-10-08 22:06:26 +04:00
Vyacheslav Matyukhin
9992d7da1a
empty outputs of lint and test 2022-10-08 21:34:31 +04:00
Vyacheslav Matyukhin
de532c72d6
custom squiggle-components outputs; never cache coverage 2022-10-08 21:15:37 +04:00
Vyacheslav Matyukhin
fd6c4ae1de
yarn in CI tuning 2022-10-08 19:55:57 +04:00
Vyacheslav Matyukhin
5621567af2
nudge CI to check caching 2022-10-08 19:55:33 +04:00
Vyacheslav Matyukhin
000b7a6248
change coverage:local order too 2022-10-08 19:46:59 +04:00
cab
13a54f3e3d
vscode-ext: move to esbuild bundling, cleanup
This removes node_modules from dependencies all together fixing long
time issue with yarn putting only a subset of dependencies in the
extension source tree.

It as well makes extension footprint 15x smaller. (down to 2.3Mb)

Kinda fixes #1162? It actually un-patches vsce though — it really is not
an issue it should be solving :D
2022-10-08 19:24:30 +04:00
Vyacheslav Matyukhin
4abdb69f23
fix coverage? 2022-10-08 19:24:12 +04:00
Vyacheslav Matyukhin
ed86fd9f77
separate job for coverage, fix infinite loop 2022-10-08 19:13:44 +04:00
Vyacheslav Matyukhin
bcc5b5846f
list all turbo outputs for squiggle-lang 2022-10-08 19:02:31 +04:00
Vyacheslav Matyukhin
da8db5db9c
call yarn 2022-10-08 18:37:34 +04:00
Vyacheslav Matyukhin
d7c6996284
vscode-ext depends on old 0.2.11 lang again for parsing; more turbo tuning 2022-10-08 18:16:54 +04:00
Vyacheslav Matyukhin
b7d56a3f1f
turbo tuning 2022-10-08 18:03:47 +04:00
Vyacheslav Matyukhin
d037913e7c
npx turbo 2022-10-08 17:45:59 +04:00
Vyacheslav Matyukhin
2c01c77646
Merge branch 'develop' into turborepo 2022-10-08 17:44:52 +04:00
Vyacheslav Matyukhin
7493f2e2e5
update vercel configs to use turbo 2022-10-08 17:41:58 +04:00
Vyacheslav Matyukhin
07fcbeb568
more turbo; rewrite and simplify github CI 2022-10-08 17:28:43 +04:00
Sam Nolan
0f8e7ce6b6 Project in editors and remove warnings 2022-10-08 16:23:58 +11:00
Vyacheslav Matyukhin
cc846aa74c
turborepo 2022-10-08 05:19:15 +04:00
Vyacheslav Matyukhin
214a54e57e
prettierignore generated files 2022-10-08 05:18:44 +04:00
Vyacheslav Matyukhin
eaa7d38428
Merge pull request #1230 from quantified-uncertainty/merge-master-to-develop
Merge master to develop
2022-10-08 04:07:54 +03:00
Vyacheslav Matyukhin
96e0418f60
Merge branch 'master' into remerge-develop-from-master 2022-10-08 04:45:30 +04:00
Vyacheslav Matyukhin
2bb9622edd
Merge pull request #1172 from quantified-uncertainty/error-locations
Error locations and stacktraces
2022-10-08 03:41:55 +03:00
Vyacheslav Matyukhin
7bfe52c2d3
Merge pull request #1228 from quantified-uncertainty/vercel-on-master
Vercel on master
2022-10-07 15:45:04 +03:00
Vyacheslav Matyukhin
d6a48d9cb9
disable ignoreCommand in vercel.json for now 2022-10-07 16:23:28 +04:00
Vyacheslav Matyukhin
4efd2c9e05
remove special dependabot case from ignoreCommand 2022-10-07 16:09:37 +04:00
Vyacheslav Matyukhin
0ab03eca96
fix broken link in docs 2022-10-07 16:09:35 +04:00
Vyacheslav Matyukhin
9107b241f5
replace netlify with vercel; update CONTRIBUTING.md 2022-10-07 16:09:32 +04:00
Vyacheslav Matyukhin
c1e67066aa
vercel.json configs 2022-10-07 16:09:30 +04:00
Vyacheslav Matyukhin
54d52e4d91
Merge pull request #1193 from quantified-uncertainty/develop
Disable algolia search on master
2022-10-02 17:02:18 +03:00
Vyacheslav Matyukhin
b1639bf62c
Merge pull request #1190 from quantified-uncertainty/develop
0.5.0
2022-10-02 14:39:11 +03:00
Ozzie Gooen
36f7f00fc3
Merge pull request #1137 from quantified-uncertainty/develop
0.4.2 release
2022-09-14 13:44:31 -07:00
Ozzie Gooen
45dd199925
Merge pull request #1102 from quantified-uncertainty/develop
V0.4.1
2022-09-07 09:44:37 -07:00
Ozzie Gooen
4ecb692e80
Merge pull request #1057 from quantified-uncertainty/develop
V0.3.1
2022-09-01 11:23:27 -07:00
Quinn Dougherty
36c3a93d08 10.0.0 2022-08-27 10:37:01 +08:00
Quinn Dougherty
f67abe55a8 Merge remote-tracking branch 'origin/develop' into experiment-10.0rc1 2022-08-27 10:33:48 +08:00
Quinn
07af79adc8
bump rescript and @rescript/std to 10.0.0-rc.1 2022-08-08 14:54:57 -04:00
89 changed files with 1750 additions and 1678 deletions

View File

@ -1,4 +1,4 @@
name: Squiggle packages check
name: Squiggle packages checks
on:
push:
@ -9,217 +9,40 @@ on:
branches:
- master
- develop
- reducer-dev
- epic-reducer-project
- epic-0.5.0
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: quantified-uncertainty
jobs:
pre_check:
name: Precheck for skipping redundant jobs
build-test-lint:
name: Build, test, lint
runs-on: ubuntu-latest
outputs:
should_skip_lang: ${{ steps.skip_lang_check.outputs.should_skip }}
should_skip_components: ${{ steps.skip_components_check.outputs.should_skip }}
should_skip_website: ${{ steps.skip_website_check.outputs.should_skip }}
should_skip_vscodeext: ${{ steps.skip_vscodeext_check.outputs.should_skip }}
should_skip_cli: ${{ steps.skip_cli_check.outputs.should_skip }}
steps:
- id: skip_lang_check
name: Check if the changes are about squiggle-lang src files
uses: fkirc/skip-duplicate-actions@v5.2.0
with:
paths: '["packages/squiggle-lang/**"]'
- id: skip_components_check
name: Check if the changes are about components src files
uses: fkirc/skip-duplicate-actions@v5.2.0
with:
paths: '["packages/components/**"]'
- id: skip_website_check
name: Check if the changes are about website src files
uses: fkirc/skip-duplicate-actions@v5.2.0
with:
paths: '["packages/website/**"]'
- id: skip_vscodeext_check
name: Check if the changes are about vscode extension src files
uses: fkirc/skip-duplicate-actions@v5.2.0
with:
paths: '["packages/vscode-ext/**"]'
- id: skip_cli_check
name: Check if the changes are about cli src files
uses: fkirc/skip-duplicate-actions@v5.2.0
with:
paths: '["packages/cli/**"]'
lang-lint:
name: Language lint
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/squiggle-lang
steps:
- uses: actions/checkout@v3
- name: Install Dependencies
run: cd ../../ && yarn
- name: Check rescript lint
run: yarn lint:rescript
- name: Check javascript, typescript, and markdown lint
uses: creyD/prettier_action@v4.2
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
dry: true
prettier_options: --check packages/squiggle-lang
node-version: 16
cache: 'yarn'
- name: Install dependencies
run: yarn --frozen-lockfile
- name: Turbo run
run: npx turbo run build test lint bundle
lang-build-test-bundle:
name: Language build, test, and bundle
coverage:
name: Coverage
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/squiggle-lang
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript codebase
run: yarn build
- name: Run rescript tests
run: yarn test:rescript
- name: Run typescript tests
run: yarn test:ts
- name: Run webpack
run: yarn bundle
- name: Upload rescript coverage report
run: yarn coverage:rescript:ci
- name: Upload typescript coverage report
run: yarn coverage:ts:ci
components-lint:
name: Components lint
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_components != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/components
steps:
- uses: actions/checkout@v3
- name: Check javascript, typescript, and markdown lint
uses: creyD/prettier_action@v4.2
- name: Setup Node.js environment
uses: actions/setup-node@v2
with:
dry: true
prettier_options: --check packages/components --ignore-path packages/components/.prettierignore
components-bundle-build-test:
name: Components bundle, build and test
runs-on: ubuntu-latest
needs: pre_check
if: ${{ (needs.pre_check.outputs.should_skip_components != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') }}
defaults:
run:
shell: bash
working-directory: packages/components
steps:
- uses: actions/checkout@v3
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript codebase in squiggle-lang
run: cd ../squiggle-lang && yarn build
- name: Run webpack
run: yarn bundle
- name: Build storybook
run: yarn build
- name: Test components
run: yarn test
website-lint:
name: Website lint
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_website != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/website
steps:
- uses: actions/checkout@v3
- name: Check javascript, typescript, and markdown lint
uses: creyD/prettier_action@v4.2
with:
dry: true
prettier_options: --check packages/website
website-build:
name: Website build
runs-on: ubuntu-latest
needs: pre_check
if: ${{ (needs.pre_check.outputs.should_skip_website != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') || (needs.pre_check.outputs.should_skip_components != 'true') }}
defaults:
run:
shell: bash
working-directory: packages/website
steps:
- uses: actions/checkout@v3
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build rescript in squiggle-lang
run: cd ../squiggle-lang && yarn build
- name: Build components
run: cd ../components && yarn build
- name: Build website assets
run: yarn build
vscode-ext-lint:
name: VS Code extension lint
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_vscodeext != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/vscode-ext
steps:
- uses: actions/checkout@v3
- name: Check javascript, typescript, and markdown lint
uses: creyD/prettier_action@v4.2
with:
dry: true
prettier_options: --check packages/vscode-ext
vscode-ext-build:
name: VS Code extension build
runs-on: ubuntu-latest
needs: pre_check
if: ${{ (needs.pre_check.outputs.should_skip_components != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') }} || (needs.pre_check.outputs.should_skip_vscodeext != 'true') }}
defaults:
run:
shell: bash
working-directory: packages/vscode-ext
steps:
- uses: actions/checkout@v3
- name: Install dependencies from monorepo level
run: cd ../../ && yarn
- name: Build
run: yarn compile
cli-lint:
name: CLI lint
runs-on: ubuntu-latest
needs: pre_check
if: ${{ needs.pre_check.outputs.should_skip_cli != 'true' }}
defaults:
run:
shell: bash
working-directory: packages/cli
steps:
- uses: actions/checkout@v3
- name: Check javascript, typescript, and markdown lint
uses: creyD/prettier_action@v4.2
with:
dry: true
prettier_options: --check packages/cli
node-version: 16
cache: 'yarn'
- name: Install dependencies
run: yarn
- name: Coverage
run: npx turbo run coverage

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ yarn-error.log
todo.txt
result
shell.nix
.turbo

1
CHANGELOG.md Normal file
View File

@ -0,0 +1 @@
See the [Changelog.mdx page](./packages/website/docs/Changelog.mdx) for the changelog.

View File

@ -51,7 +51,25 @@ For any project in the repo, begin by running `yarn` in the top level
yarn
```
See `packages/*/README.md` to work with whatever project you're interested in.
Then use `turbo` to build the specific packages or the entire monorepo:
```sh
turbo run build
```
Or:
```sh
turbo run build --filter=@quri/squiggle-components
```
You can also run specific npm scripts for the package you're working on. See `packages/*/README.md` for the details.
# NixOS users
This repository requires the use of bundled binaries from node_modules, which
are not linked statically. The easiest way to get them working is to enable
[nix-ld](https://github.com/Mic92/nix-ld).
# Contributing

View File

@ -30,16 +30,6 @@ rec {
patchelf --replace-needed libstdc++.so.6 $THE_SO linux/ninja.exe && echo "- replaced needed for linux/ninja.exe"
'';
};
bisect_ppx = {
buildInputs = common.which;
postInstall = ''
echo "PATCHELF'ING BISECT_PPX EXECUTABLE"
THE_LD=$(patchelf --print-interpreter $(which mkdir))
patchelf --set-interpreter $THE_LD bin/linux/ppx
patchelf --set-interpreter $THE_LD bin/linux/bisect-ppx-report
cp bin/linux/ppx ppx
'';
};
gentype = {
postInstall = ''
mv gentype.exe ELFLESS-gentype.exe

View File

@ -1,18 +0,0 @@
#!/usr/bin/env bash
# This script is only relevant if you're rolling nixos.
# Esy (a bisect_ppx dependency/build tool) is borked on nixos without using an FHS shell. https://github.com/esy/esy/issues/858
# We need to patchelf rescript executables. https://github.com/NixOS/nixpkgs/issues/107375
set -x
fhsShellName="squiggle-fhs-development"
fhsShellDotNix="{pkgs ? import <nixpkgs> {} }: (pkgs.buildFHSUserEnv { name = \"${fhsShellName}\"; targetPkgs = pkgs: [pkgs.yarn pkgs.glibc]; runScript = \"yarn\"; }).env"
nix-shell - <<<"$fhsShellDotNix"
theLd=$(patchelf --print-interpreter $(which mkdir))
patchelf --set-interpreter $theLd ./node_modules/gentype/gentype.exe
patchelf --set-interpreter $theLd ./node_modules/rescript/linux/*.exe
patchelf --set-interpreter $theLd ./node_modules/bisect_ppx/ppx
patchelf --set-interpreter $theLd ./node_modules/bisect_ppx/bisect-ppx-report
theSo=$(find /nix/store/*$fhsShellName*/lib64 -name libstdc++.so.6 | head -n 1)
patchelf --replace-needed libstdc++.so.6 $theSo ./node_modules/rescript/linux/ninja.exe

View File

@ -2,12 +2,11 @@
"private": true,
"name": "squiggle",
"scripts": {
"nodeclean": "rm -r node_modules && rm -r packages/*/node_modules",
"format:all": "prettier --write . && cd packages/squiggle-lang && yarn format",
"lint:all": "prettier --check . && cd packages/squiggle-lang && yarn lint:rescript"
"nodeclean": "rm -r node_modules && rm -r packages/*/node_modules"
},
"devDependencies": {
"prettier": "^2.7.1"
"prettier": "^2.7.1",
"turbo": "^1.5.5"
},
"workspaces": [
"packages/*"

View File

@ -20,3 +20,30 @@ Runs compilation in the current directory and all of its subdirectories.
### `npx squiggle-cli-experimental watch`
Watches `.squiggleU` files in the current directory (and subdirectories) and rebuilds them when they are saved. Note that this will _not_ rebuild files when their dependencies are changed, just when they are changed directly.
## Further instructions
The above requires having node, npm and npx. To install the first two, see [here](https://nodejs.org/en/), to install npx, run:
```
npm install -g npx
```
Alternatively, you can run the following without the need for npx:
```
npm install squiggle-cli-experimental
node node_modules/squiggle-cli-experimental/index.js compile
```
or you can add a script to your `package.json`, like:
```
...
scripts: {
"compile": "squiggle-cli-experimental compile"
}
...
```
This can be run with `npm run compile`. `npm` knows how to reach into the node_modules directly, so it's not necessary to specify that.

View File

@ -7,11 +7,13 @@
"bin": "index.js",
"type": "module",
"scripts": {
"start": "node ."
"start": "node .",
"lint": "prettier --check .",
"format": "prettier --write ."
},
"license": "MIT",
"dependencies": {
"chalk": "^5.0.1",
"chalk": "^5.1.0",
"chokidar": "^3.5.3",
"commander": "^9.4.1",
"fs": "^0.0.1-security",

View File

@ -12,11 +12,11 @@
"@react-hook/size": "^2.1.2",
"@types/uuid": "^8.3.4",
"clsx": "^1.2.1",
"framer-motion": "^7.5.1",
"framer-motion": "^7.5.3",
"lodash": "^4.17.21",
"react": "^18.1.0",
"react-ace": "^10.1.0",
"react-hook-form": "^7.36.1",
"react-hook-form": "^7.37.0",
"react-use": "^17.4.0",
"react-vega": "^7.6.0",
"uuid": "^9.0.0",
@ -41,7 +41,7 @@
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^27.5.0",
"@types/lodash": "^4.14.186",
"@types/node": "^18.8.0",
"@types/node": "^18.8.3",
"@types/react": "^18.0.21",
"@types/styled-components": "^5.1.26",
"@types/uuid": "^8.3.4",
@ -49,8 +49,8 @@
"canvas": "^2.10.1",
"cross-env": "^7.0.3",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"jsdom": "^20.0.0",
"jest-environment-jsdom": "^29.1.2",
"jsdom": "^20.0.1",
"mini-css-extract-plugin": "^2.6.1",
"postcss-cli": "^10.0.0",
"postcss-import": "^15.0.0",
@ -60,11 +60,11 @@
"react-scripts": "^5.0.1",
"style-loader": "^3.3.1",
"tailwindcss": "^3.1.8",
"ts-jest": "^29.0.2",
"ts-jest": "^29.0.3",
"ts-loader": "^9.4.1",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"typescript": "^4.8.4",
"web-vitals": "^3.0.2",
"web-vitals": "^3.0.3",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"

View File

@ -24,7 +24,7 @@ export const Alert: React.FC<{
children,
}) => {
return (
<div className={clsx("rounded-md p-4", backgroundColor)}>
<div className={clsx("rounded-md p-4", backgroundColor)} role="status">
<div className="flex">
<Icon
className={clsx("h-5 w-5 flex-shrink-0", iconColor)}

View File

@ -55,10 +55,7 @@ export const CodeEditor: FC<CodeEditorProps> = ({
editorProps={{
$blockScrolling: true,
}}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: false,
}}
setOptions={{}}
commands={[
{
name: "submit",

View File

@ -1,5 +1,10 @@
import * as React from "react";
import { SqValue, environment, SqProject } from "@quri/squiggle-lang";
import {
SqValue,
environment,
SqProject,
defaultEnvironment,
} from "@quri/squiggle-lang";
import { useSquiggle } from "../lib/hooks";
import { SquiggleViewer } from "./SquiggleViewer";
import { JsImports } from "../lib/jsImports";
@ -66,7 +71,6 @@ type ProjectExecutionProps = {
};
const defaultOnChange = () => {};
const defaultImports: JsImports = {};
const defaultContinues: string[] = [];
export const splitSquiggleChartSettings = (props: SquiggleChartProps) => {
const {
@ -120,24 +124,15 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
width,
height = 200,
enableLocalSettings = false,
continues = defaultContinues,
continues,
project,
environment,
} = props;
const p = React.useMemo(() => {
if (props.project) {
return props.project;
} else {
const p = SqProject.create();
if (props.environment) {
p.setEnvironment(props.environment);
}
return p;
}
}, [props.project, props.environment]);
const resultAndBindings = useSquiggle({
environment,
continues,
project: p,
project,
code,
jsImports,
onChange,
@ -153,7 +148,9 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
height={height}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={p.getEnvironment()}
environment={
project ? project.getEnvironment() : environment ?? defaultEnvironment
}
enableLocalSettings={enableLocalSettings}
/>
);

View File

@ -16,7 +16,7 @@ const WrappedCodeEditor: React.FC<{
setCode: (code: string) => void;
errorLocations?: SqLocation[];
}> = ({ code, setCode, errorLocations }) => (
<div className="border border-grey-200 p-2 m-4">
<div className="border border-grey-200 p-2 m-4" data-testid="squiggle-editor">
<CodeEditor
value={code}
onChange={setCode}
@ -54,17 +54,13 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
width,
height = 200,
enableLocalSettings = false,
continues,
project,
} = props;
const project = React.useMemo(() => {
const p = SqProject.create();
if (environment) {
p.setEnvironment(environment);
}
return p;
}, [environment]);
const resultAndBindings = useSquiggle({
environment,
continues,
code,
project,
jsImports,

View File

@ -182,7 +182,7 @@ const RunControls: React.FC<{
const CurrentPlayIcon = isRunning ? RefreshIcon : PlayIcon;
return (
<div className="flex space-x-1 items-center">
<div className="flex space-x-1 items-center" data-testid="autorun-controls">
{autorunMode ? null : (
<button onClick={run}>
<CurrentPlayIcon
@ -251,6 +251,8 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
onSettingsChange,
showEditor = true,
showShareButton = false,
continues,
project,
}) => {
const [code, setCode] = useMaybeControlledValue({
value: controlledCode,
@ -305,16 +307,10 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
executionId,
} = useRunnerState(code);
const project = React.useMemo(() => {
const p = SqProject.create();
if (environment) {
p.setEnvironment(environment);
}
return p;
}, [environment]);
const resultAndBindings = useSquiggle({
code,
environment,
continues,
code: renderedCode,
project,
jsImports: imports,
executionId,
@ -355,7 +351,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
const errorLocations = getErrorLocations(resultAndBindings.result);
const firstTab = vars.showEditor ? (
<div className="border border-slate-200">
<div className="border border-slate-200" data-testid="squiggle-editor">
<CodeEditor
errorLocations={errorLocations}
value={code}
@ -407,7 +403,9 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
>
{tabs}
</div>
<div className="w-1/2 p-2 pl-4">{squiggleChart}</div>
<div className="w-1/2 p-2 pl-4" data-testid="playground-result">
{squiggleChart}
</div>
</div>
);

View File

@ -45,7 +45,7 @@ export const VariableBox: React.FC<VariableBoxProps> = ({
: location.path.items[location.path.items.length - 1];
return (
<div>
<div role={isTopLevel ? "status" : undefined}>
<header className="inline-flex space-x-1">
<Tooltip text={heading}>
<span

View File

@ -4,16 +4,18 @@ import {
SqProject,
SqRecord,
SqValue,
environment,
} from "@quri/squiggle-lang";
import { useEffect, useMemo } from "react";
import { JsImports, jsImportsToSquiggleCode } from "../jsImports";
import * as uuid from "uuid";
type SquiggleArgs = {
environment?: environment;
code: string;
executionId?: number;
jsImports?: JsImports;
project: SqProject;
project?: SqProject;
continues?: string[];
onChange?: (expr: SqValue | undefined, sourceName: string) => void;
};
@ -27,15 +29,25 @@ const importSourceName = (sourceName: string) => "imports-" + sourceName;
const defaultContinues = [];
export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
const project = useMemo(() => {
if (args.project) {
return args.project;
} else {
const p = SqProject.create();
if (args.environment) {
p.setEnvironment(args.environment);
}
return p;
}
}, [args.project, args.environment]);
const sourceName = useMemo(() => uuid.v4(), []);
const env = args.project.getEnvironment();
const env = project.getEnvironment();
const continues = args.continues || defaultContinues;
const result = useMemo(
() => {
const project = args.project;
project.setSource(sourceName, args.code);
let fullContinues = continues;
if (args.jsImports && Object.keys(args.jsImports).length) {
@ -59,7 +71,7 @@ export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
args.executionId,
sourceName,
continues,
args.project,
project,
env,
]
);
@ -75,11 +87,11 @@ export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
useEffect(() => {
return () => {
args.project.removeSource(sourceName);
if (args.project.getSource(importSourceName(sourceName)))
args.project.removeSource(importSourceName(sourceName));
project.removeSource(sourceName);
if (project.getSource(importSourceName(sourceName)))
project.removeSource(importSourceName(sourceName));
};
}, [args.project, sourceName]);
}, [project, sourceName]);
return result;
};

View File

@ -0,0 +1,55 @@
import { render, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as React from "react";
import "@testing-library/jest-dom";
import { SquigglePlayground } from "../src/index";
test("Autorun is default", async () => {
render(<SquigglePlayground code="70*30" />);
await waitFor(() =>
expect(screen.getByTestId("playground-result")).toHaveTextContent("2100")
);
});
test("Autorun can be switched off", async () => {
const user = userEvent.setup();
render(<SquigglePlayground code="70*30" />);
expect(screen.getByTestId("autorun-controls")).toHaveTextContent("Autorun");
await waitFor(() =>
expect(screen.getByTestId("playground-result")).toHaveTextContent("2100")
);
await user.click(screen.getByText("Autorun")); // disable
expect(screen.getByTestId("autorun-controls")).toHaveTextContent("Paused");
expect(screen.getByTestId("autorun-controls")).not.toHaveTextContent(
"Autorun"
);
await user.click(screen.getByText("Paused")); // enable autorun again
expect(screen.getByTestId("autorun-controls")).toHaveTextContent("Autorun");
// we should replace the code here, but it's hard to update react-ace state via user events: https://github.com/securingsincity/react-ace/issues/923
// ...or replace react-ace with something else
// TODO:
/*
const editor = screen
.getByTestId("squiggle-editor")
.querySelector(".ace_editor") as HTMLElement;
editor.focus();
// await user.clear(editor);
await userEvent.paste("40*40"); // https://github.com/securingsincity/react-ace/issues/923#issuecomment-755502696
screen.debug(editor);
// this makes the tests slower, but it's hard to test otherwise that the code _didn't_ execute
await new Promise((r) => setTimeout(r, 300));
expect(screen.getByTestId("playground-result")).toHaveTextContent("2100"); // still the old value
await waitFor(() =>
expect(screen.getByTestId("playground-result")).toHaveTextContent("1600")
);
*/
});

View File

@ -1,9 +1,14 @@
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import React from "react";
import "@testing-library/jest-dom";
import { SquiggleChart } from "../src/index";
import {
SquiggleChart,
SquiggleEditor,
SquigglePlayground,
} from "../src/index";
import { SqProject } from "@quri/squiggle-lang";
test("Logs nothing on render", async () => {
test("Chart logs nothing on render", async () => {
const { unmount } = render(<SquiggleChart code={"normal(0, 1)"} />);
unmount();
@ -11,3 +16,38 @@ test("Logs nothing on render", async () => {
expect(console.warn).not.toBeCalled();
expect(console.error).not.toBeCalled();
});
test("Editor logs nothing on render", async () => {
const { unmount } = render(<SquiggleEditor code={"normal(0, 1)"} />);
unmount();
expect(console.log).not.toBeCalled();
expect(console.warn).not.toBeCalled();
expect(console.error).not.toBeCalled();
});
test("Project dependencies work in editors", async () => {
const project = SqProject.create();
render(<SquiggleEditor code={"x = 1"} project={project} />);
const source = project.getSourceIds()[0];
const { container } = render(
<SquiggleEditor code={"x + 1"} project={project} continues={[source]} />
);
expect(container).toHaveTextContent("2");
});
test("Project dependencies work in playgrounds", async () => {
const project = SqProject.create();
project.setSource("depend", "x = 1");
render(
<SquigglePlayground
code={"x + 1"}
project={project}
continues={["depend"]}
/>
);
// We must await here because SquigglePlayground loads results asynchronously
expect(await screen.findByRole("status")).toHaveTextContent("2");
});

View File

@ -1,6 +1,4 @@
{
"buildCommand": "cd ../squiggle-lang && yarn build && cd ../components && yarn build",
"outputDirectory": "storybook-static",
"installCommand": "cd ../../ && yarn",
"ignoreCommand": "git diff --quiet $VERCEL_GIT_PREVIOUS_SHA $VERCEL_GIT_COMMIT_SHA . ../squiggle-lang"
"buildCommand": "cd ../.. && npx turbo run build --filter=@quri/squiggle-components",
"outputDirectory": "storybook-static"
}

View File

@ -3,6 +3,8 @@ lib
*.bs.js
*.gen.tsx
.nyc_output/
_coverage/
coverage/
.cache/
Reducer_Peggy_GeneratedParser.js
ReducerProject_IncludeParser.js
src/rescript/Reducer/Reducer_Peggy/helpers.js

View File

@ -32,25 +32,29 @@ describe("dotSubtract", () => {
*/
Skip.test("mean of normal minus exponential (property)", () => {
assert_(
property2(float_(), floatRange(1e-5, 1e5), (mean, rate) => {
// We limit ourselves to stdev=1 so that the integral is trivial
let dotDifference = DistributionOperation.Constructors.pointwiseSubtract(
~env,
mkNormal(mean, 1.0),
mkExponential(rate),
)
let meanResult = E.R2.bind(DistributionOperation.Constructors.mean(~env), dotDifference)
// according to algebra or random variables,
let meanAnalytical =
mean -.
SymbolicDist.Exponential.mean({rate: rate})->E.R2.toExn(
"On trusted input this should never happen",
property2(
float_(),
floatRange(1e-5, 1e5),
(mean, rate) => {
// We limit ourselves to stdev=1 so that the integral is trivial
let dotDifference = DistributionOperation.Constructors.pointwiseSubtract(
~env,
mkNormal(mean, 1.0),
mkExponential(rate),
)
switch meanResult {
| Ok(meanValue) => abs_float(meanValue -. meanAnalytical) /. abs_float(meanValue) < 1e-2 // 1% relative error
| Error(err) => err === DistributionTypes.OperationError(DivisionByZeroError)
}
}),
let meanResult = E.R2.bind(DistributionOperation.Constructors.mean(~env), dotDifference)
// according to algebra or random variables,
let meanAnalytical =
mean -.
SymbolicDist.Exponential.mean({rate: rate})->E.R2.toExn(
"On trusted input this should never happen",
)
switch meanResult {
| Ok(meanValue) => abs_float(meanValue -. meanAnalytical) /. abs_float(meanValue) < 1e-2 // 1% relative error
| Error(err) => err === DistributionTypes.OperationError(DivisionByZeroError)
}
},
),
)
pass
})

View File

@ -40,51 +40,60 @@ let algebraicPower = algebraicPower(~env)
describe("(Algebraic) addition of distributions", () => {
describe("mean", () => {
test("normal(mean=5) + normal(mean=20)", () => {
normalDist5
->algebraicAdd(normalDist20)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
->expect
->toBe(Some(2.5e1))
})
test(
"normal(mean=5) + normal(mean=20)",
() => {
normalDist5
->algebraicAdd(normalDist20)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
->expect
->toBe(Some(2.5e1))
},
)
test("uniform(low=9, high=10) + beta(alpha=2, beta=5)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.786831807237022, ~digits=1) // (uniformMean +. betaMean)
}
})
test("beta(alpha=2, beta=5) + uniform(low=9, high=10)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.784290207736126, ~digits=1) // (uniformMean +. betaMean)
}
})
test(
"uniform(low=9, high=10) + beta(alpha=2, beta=5)",
() => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.786831807237022, ~digits=1) // (uniformMean +. betaMean)
}
},
)
test(
"beta(alpha=2, beta=5) + uniform(low=9, high=10)",
() => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.784290207736126, ~digits=1) // (uniformMean +. betaMean)
}
},
)
})
describe("pdf", () => {
// TEST IS WRONG. SEE STDEV ADDITION EXPRESSION.
@ -122,247 +131,282 @@ describe("(Algebraic) addition of distributions", () => {
}
},
)
test("(normal(mean=10) + normal(mean=10)).pdf(1.9e1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=1)
test(
"(normal(mean=10) + normal(mean=10)).pdf(1.9e1)",
() => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=1)
}
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
// This value was calculated by a python script
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic.
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
})
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)",
() => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
// This value was calculated by a python script
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)",
() => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic.
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
},
)
})
describe("cdf", () => {
testAll("(normal(mean=5) + normal(mean=5)).cdf (imprecise)", list{6e0, 8e0, 1e1, 1.2e1}, x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
testAll(
"(normal(mean=5) + normal(mean=5)).cdf (imprecise)",
list{6e0, 8e0, 1e1, 1.2e1},
x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=0)
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=0)
}
}
}
})
test("(normal(mean=10) + normal(mean=10)).cdf(1.25e1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=2)
},
)
test(
"(normal(mean=10) + normal(mean=10)).cdf(1.25e1)",
() => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=2)
}
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
})
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)",
() => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)",
() => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
},
)
})
describe("inv", () => {
testAll("(normal(mean=5) + normal(mean=5)).inv (imprecise)", list{5e-2, 4.2e-3, 9e-3}, x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
testAll(
"(normal(mean=5) + normal(mean=5)).inv (imprecise)",
list{5e-2, 4.2e-3, 9e-3},
x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
}
})
test("(normal(mean=10) + normal(mean=10)).inv(1e-1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
},
)
test(
"(normal(mean=10) + normal(mean=10)).inv(1e-1)",
() => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.179319623146968, ~digits=0)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.190872365862756, ~digits=0)
}
})
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)",
() => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.179319623146968, ~digits=0)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)",
() => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => DistributionTypes.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn("Expected float", _)
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.190872365862756, ~digits=0)
}
},
)
})
})

View File

@ -87,14 +87,22 @@ describe("Means are invariant", () => {
let testAddInvariant = (t1, t2) =>
E.R.liftM2(testAdditionMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll("with two of the same distribution", distributions, dist => {
testAddInvariant(dist, dist)
})
testAll(
"with two of the same distribution",
distributions,
dist => {
testAddInvariant(dist, dist)
},
)
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testAddInvariant(dist1, dist2)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
let (dist1, dist2) = dists
testAddInvariant(dist1, dist2)
},
)
testAll(
"with two different distributions in swapped order",
@ -116,14 +124,22 @@ describe("Means are invariant", () => {
let testSubtractInvariant = (t1, t2) =>
E.R.liftM2(testSubtractionMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll("with two of the same distribution", distributions, dist => {
testSubtractInvariant(dist, dist)
})
testAll(
"with two of the same distribution",
distributions,
dist => {
testSubtractInvariant(dist, dist)
},
)
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testSubtractInvariant(dist1, dist2)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
let (dist1, dist2) = dists
testSubtractInvariant(dist1, dist2)
},
)
testAll(
"with two different distributions in swapped order",
@ -145,14 +161,22 @@ describe("Means are invariant", () => {
let testMultiplicationInvariant = (t1, t2) =>
E.R.liftM2(testMultiplicationMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll("with two of the same distribution", distributions, dist => {
testMultiplicationInvariant(dist, dist)
})
testAll(
"with two of the same distribution",
distributions,
dist => {
testMultiplicationInvariant(dist, dist)
},
)
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testMultiplicationInvariant(dist1, dist2)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
let (dist1, dist2) = dists
testMultiplicationInvariant(dist1, dist2)
},
)
testAll(
"with two different distributions in swapped order",

View File

@ -17,10 +17,9 @@ describe("klDivergence: continuous -> continuous -> float", () => {
let answer =
uniformMakeR(lowAnswer, highAnswer)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
let prediction =
uniformMakeR(
lowPrediction,
highPrediction,
)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(
s => DistributionTypes.ArgumentError(s),
)
// integral along the support of the answer of answer.pdf(x) times log of prediction.pdf(x) divided by answer.pdf(x) dx
let analyticalKl = Js.Math.log((highPrediction -. lowPrediction) /. (highAnswer -. lowAnswer))
let kl = E.R.liftJoin2(klDivergence, prediction, answer)
@ -183,9 +182,9 @@ describe("combineAlongSupportOfSecondArgument0", () => {
let answer =
uniformMakeR(lowAnswer, highAnswer)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
let prediction =
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(s => DistributionTypes.ArgumentError(
s,
))
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(
s => DistributionTypes.ArgumentError(s),
)
let answerWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), answer)
let predictionWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), prediction)

View File

@ -3,7 +3,7 @@ open Expect
open TestHelpers
// TODO: use Normal.make (but preferably after teh new validation dispatch is in)
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev}))
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean, stdev}))
describe("(Symbolic) normalize", () => {
testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => {
@ -47,10 +47,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (low, medium, high) = tup
let meanValue = run(
FromDist(
#ToFloat(#Mean),
DistributionTypes.Symbolic(#Triangular({low: low, medium: medium, high: high})),
),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Triangular({low, medium, high}))),
)
meanValue->unpackFloat->expect->toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/
},
@ -63,7 +60,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (alpha, beta) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha, beta}))),
)
meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. (1.0 +. beta /. alpha)) // https://en.wikipedia.org/wiki/Beta_distribution#Mean
},
@ -84,8 +81,8 @@ describe("(Symbolic) mean", () => {
let (mean, stdev) = tup
let betaDistribution = SymbolicDist.Beta.fromMeanAndStdev(mean, stdev)
let meanValue =
betaDistribution->E.R2.fmap(d =>
run(FromDist(#ToFloat(#Mean), d->DistributionTypes.Symbolic))
betaDistribution->E.R2.fmap(
d => run(FromDist(#ToFloat(#Mean), d->DistributionTypes.Symbolic)),
)
switch meanValue {
| Ok(value) => value->unpackFloat->expect->toBeCloseTo(mean)
@ -100,7 +97,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (mu, sigma) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu, sigma}))),
)
meanValue->unpackFloat->expect->toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0)) // https://brilliant.org/wiki/log-normal-distribution/
},
@ -112,7 +109,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (low, high) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low: low, high: high}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low, high}))),
)
meanValue->unpackFloat->expect->toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments
},

View File

@ -33,12 +33,18 @@ describe("Bindings", () => {
let value2 = Reducer_T.IEvNumber(5.)
let extendedBindings = bindings->Bindings.extend->Bindings.set("value", value2)
test("get on extended", () => {
expect(extendedBindings->Bindings.get("value")) == Some(value2)
})
test(
"get on extended",
() => {
expect(extendedBindings->Bindings.get("value")) == Some(value2)
},
)
test("get on original", () => {
expect(bindings->Bindings.get("value")) == Some(value)
})
test(
"get on original",
() => {
expect(bindings->Bindings.get("value")) == Some(value)
},
)
})
})

View File

@ -40,14 +40,23 @@ describe("Namespace", () => {
let nsMerged = Namespace.mergeMany([ns, ns1, ns2])
test("merge many 1", () => {
expect(nsMerged->Namespace.get("x1")) == Some(x1)
})
test("merge many 2", () => {
expect(nsMerged->Namespace.get("x4")) == Some(x4)
})
test("merge many 3", () => {
expect(nsMerged->Namespace.get("value")) == Some(value)
})
test(
"merge many 1",
() => {
expect(nsMerged->Namespace.get("x1")) == Some(x1)
},
)
test(
"merge many 2",
() => {
expect(nsMerged->Namespace.get("x4")) == Some(x4)
},
)
test(
"merge many 3",
() => {
expect(nsMerged->Namespace.get("value")) == Some(value)
},
)
})
})

View File

@ -75,29 +75,32 @@ describe("Peggy to Expression", () => {
testToExpression("false ? 1 : 0", "false ? (1) : (0)", ~v="0", ())
testToExpression("true ? 1 : false ? 2 : 0", "true ? (1) : (false ? (2) : (0))", ~v="1", ()) // nested ternary
testToExpression("false ? 1 : false ? 2 : 0", "false ? (1) : (false ? (2) : (0))", ~v="0", ()) // nested ternary
describe("ternary bindings", () => {
testToExpression(
// expression binding
"f(a) = a > 5 ? 1 : 0; f(6)",
"f = {|a| {(larger)(a, 5) ? (1) : (0)}}; (f)(6)",
~v="1",
(),
)
testToExpression(
// when true binding
"f(a) = a > 5 ? a : 0; f(6)",
"f = {|a| {(larger)(a, 5) ? (a) : (0)}}; (f)(6)",
~v="6",
(),
)
testToExpression(
// when false binding
"f(a) = a < 5 ? 1 : a; f(6)",
"f = {|a| {(smaller)(a, 5) ? (1) : (a)}}; (f)(6)",
~v="6",
(),
)
})
describe(
"ternary bindings",
() => {
testToExpression(
// expression binding
"f(a) = a > 5 ? 1 : 0; f(6)",
"f = {|a| {(larger)(a, 5) ? (1) : (0)}}; (f)(6)",
~v="1",
(),
)
testToExpression(
// when true binding
"f(a) = a > 5 ? a : 0; f(6)",
"f = {|a| {(larger)(a, 5) ? (a) : (0)}}; (f)(6)",
~v="6",
(),
)
testToExpression(
// when false binding
"f(a) = a < 5 ? 1 : a; f(6)",
"f = {|a| {(smaller)(a, 5) ? (1) : (a)}}; (f)(6)",
~v="6",
(),
)
},
)
})
describe("if then else", () => {

View File

@ -22,7 +22,7 @@ let expectEvalError = (code: string) =>
Expression.BackCompatible.evaluateString(code)
->Reducer_Value.toStringResult
->expect
->toMatch("Error\(")
->toMatch("Error\\(")
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
let testDescriptionParseToBe = (desc, expr, answer) =>

View File

@ -37,14 +37,16 @@ describe("eval", () => {
test("index", () => expectEvalToBe("r = {a: 1}; r.a", "Ok(1)"))
test("index", () => expectEvalToBe("r = {a: 1}; r.b", "Error(Record property not found: b)"))
testEvalError("{a: 1}.b") // invalid syntax
test("always the same property ending", () =>
expectEvalToBe(
`{
test(
"always the same property ending",
() =>
expectEvalToBe(
`{
a: 1,
b: 2,
}`,
"Ok({a: 1,b: 2})",
)
"Ok({a: 1,b: 2})",
),
)
})

View File

@ -11,32 +11,34 @@ describe("ReducerProject Tutorial", () => {
/*
Case "Running a single source".
*/
test("run", () => {
/* Let's start with running a single source and getting Result as well as the Bindings
test(
"run",
() => {
/* Let's start with running a single source and getting Result as well as the Bindings
First you need to create a project. A project is a collection of sources.
Project takes care of the dependencies between the sources, correct compilation and run order.
You can run any source in the project. It will be compiled and run if it hasn't happened already; otherwise already existing results will be presented.
The dependencies will be automatically compiled and run. So you don't need to worry about that in a multi source project.
In summary you issue a run command on the whole project or on a specific source to ensure that there is a result for that source.
*/
let project = Project.createProject()
/* Every source has a name. This is used for debugging, dependencies and error messages. */
project->Project.setSource("main", "1 + 2")
/* Let's run "main" source. */
project->Project.run("main")
/* Now you have a result for "main" source.
let project = Project.createProject()
/* Every source has a name. This is used for debugging, dependencies and error messages. */
project->Project.setSource("main", "1 + 2")
/* Let's run "main" source. */
project->Project.run("main")
/* Now you have a result for "main" source.
Running one by one is necessary for UI to navigate among the sources and to see the results by source.
And you're free to run any source you want.
You will look at the results of this source and you don't want to run the others if not required.
*/
/* However, you could also run the whole project.
/* However, you could also run the whole project.
If you have all the sources, you can always run the whole project.
Dependencies and recompiling on demand will be taken care of by the project.
*/
project->Project.runAll
project->Project.runAll
/* Either with run or runAll you executed the project.
/* Either with run or runAll you executed the project.
You can get the result of a specific source by calling getResult for that source.
You can get the bindings of a specific source by calling getBindings for that source.
If there is any runtime error, getResult will return the error.
@ -44,49 +46,59 @@ Case "Running a single source".
Note that getResult returns None if the source has not been run.
Getting None means you have forgotten to run the source.
*/
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* Let's display the result and bindings */
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
/* You've got 3 with empty bindings. */
})
/* Let's display the result and bindings */
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
/* You've got 3 with empty bindings. */
},
)
test("run summary", () => {
let project = Project.createProject()
project->Project.setSource("main", "1 + 2")
project->Project.runAll
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* Now you have external bindings and external result. */
(
result->Reducer_Value.toStringResult,
bindings->Reducer_T.IEvRecord->Reducer_Value.toString,
)->expect == ("Ok(3)", "{}")
})
test(
"run summary",
() => {
let project = Project.createProject()
project->Project.setSource("main", "1 + 2")
project->Project.runAll
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* Now you have external bindings and external result. */
(
result->Reducer_Value.toStringResult,
bindings->Reducer_T.IEvRecord->Reducer_Value.toString,
)->expect == ("Ok(3)", "{}")
},
)
test("run with an environment", () => {
/* Running the source code like above allows you to set a custom environment */
let project = Project.createProject()
test(
"run with an environment",
() => {
/* Running the source code like above allows you to set a custom environment */
let project = Project.createProject()
/* Optional. Set your custom environment anytime before running */
project->Project.setEnvironment(Reducer_Context.defaultEnvironment)
/* Optional. Set your custom environment anytime before running */
project->Project.setEnvironment(Reducer_Context.defaultEnvironment)
project->Project.setSource("main", "1 + 2")
project->Project.runAll
let result = project->Project.getResult("main")
let _bindings = project->Project.getBindings("main")
result->Reducer_Value.toStringResult->expect == "Ok(3)"
})
project->Project.setSource("main", "1 + 2")
project->Project.runAll
let result = project->Project.getResult("main")
let _bindings = project->Project.getBindings("main")
result->Reducer_Value.toStringResult->expect == "Ok(3)"
},
)
test("shortcut", () => {
/* If you are running single source without includes and you don't need a custom environment, you can use the shortcut. */
/* Examples above was to prepare you for the multi source tutorial. */
let (result, bindings) = Project.evaluate("1+2")
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
})
test(
"shortcut",
() => {
/* If you are running single source without includes and you don't need a custom environment, you can use the shortcut. */
/* Examples above was to prepare you for the multi source tutorial. */
let (result, bindings) = Project.evaluate("1+2")
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
},
)
})
})

View File

@ -10,95 +10,104 @@ describe("ReducerProject Tutorial", () => {
describe("Multi source", () => {
/*
Case "Running multiple sources" */
test("Chaining", () => {
let project = Project.createProject()
/* This time let's add 3 sources and chain them together */
project->Project.setSource("source1", "x=1")
test(
"Chaining",
() => {
let project = Project.createProject()
/* This time let's add 3 sources and chain them together */
project->Project.setSource("source1", "x=1")
project->Project.setSource("source2", "y=x+1")
/* To run, source2 depends on source1 */
project->Project.setContinues("source2", ["source1"])
project->Project.setSource("source2", "y=x+1")
/* To run, source2 depends on source1 */
project->Project.setContinues("source2", ["source1"])
project->Project.setSource("source3", "z=y+1")
/* To run, source3 depends on source2 */
project->Project.setContinues("source3", ["source2"])
project->Project.setSource("source3", "z=y+1")
/* To run, source3 depends on source2 */
project->Project.setContinues("source3", ["source2"])
/* Now we can run the project */
project->Project.runAll
/* Now we can run the project */
project->Project.runAll
/* And let's check the result and bindings of source3 */
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
/* And let's check the result and bindings of source3 */
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
})
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
},
)
test("Depending", () => {
/* Instead of chaining the sources, we could have a dependency tree */
/* The point here is that any source can depend on multiple sources */
let project = Project.createProject()
test(
"Depending",
() => {
/* Instead of chaining the sources, we could have a dependency tree */
/* The point here is that any source can depend on multiple sources */
let project = Project.createProject()
/* This time source1 and source2 are not depending on anything */
project->Project.setSource("source1", "x=1")
project->Project.setSource("source2", "y=2")
/* This time source1 and source2 are not depending on anything */
project->Project.setSource("source1", "x=1")
project->Project.setSource("source2", "y=2")
project->Project.setSource("source3", "z=x+y")
/* To run, source3 depends on source1 and source3 together */
project->Project.setContinues("source3", ["source1", "source2"])
project->Project.setSource("source3", "z=x+y")
/* To run, source3 depends on source1 and source3 together */
project->Project.setContinues("source3", ["source1", "source2"])
/* Now we can run the project */
project->Project.runAll
/* Now we can run the project */
project->Project.runAll
/* And let's check the result and bindings of source3 */
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
/* And let's check the result and bindings of source3 */
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
})
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
},
)
test("Intro to including", () => {
/* Though it would not be practical for a storybook,
test(
"Intro to including",
() => {
/* Though it would not be practical for a storybook,
let's write the same project above with includes.
You will see that parsing includes is setting the dependencies the same way as before. */
let project = Project.createProject()
let project = Project.createProject()
/* This time source1 and source2 are not depending on anything */
project->Project.setSource("source1", "x=1")
project->Project.setSource("source2", "y=2")
/* This time source1 and source2 are not depending on anything */
project->Project.setSource("source1", "x=1")
project->Project.setSource("source2", "y=2")
project->Project.setSource(
"source3",
`
project->Project.setSource(
"source3",
`
#include "source1"
#include "source2"
z=x+y`,
)
/* We need to parse the includes to set the dependencies */
project->Project.parseIncludes("source3")
)
/* We need to parse the includes to set the dependencies */
project->Project.parseIncludes("source3")
/* Now we can run the project */
project->Project.runAll
/* Now we can run the project */
project->Project.runAll
/* And let's check the result and bindings of source3
/* And let's check the result and bindings of source3
This time you are getting all the variables because we are including the other sources
Behind the scenes parseIncludes is setting the dependencies */
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
let result3 = project->Project.getResult("source3")
let bindings3 = project->Project.getBindings("source3")
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
/*
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
/*
Doing it like this is too verbose for a storybook
But I hope you have seen the relation of setContinues and parseIncludes */
/*
/*
Dealing with includes needs more.
- There are parse errors
- There are cyclic includes
- And the depended source1 and source2 is not already there in the project
- If you knew the includes before hand there would not be point of the include directive.
More on those on the next section. */
})
},
)
})
})

View File

@ -24,93 +24,106 @@ Here we will finally proceed to a real life scenario. */
)
/* We need to parse includes after changing the source */
project->Project.parseIncludes("main")
test("getDependencies", () => {
/* Parse includes has set the dependencies */
project->Project.getDependencies("main")->expect == ["common"]
/* If there were no includes than there would be no dependencies */
/* However if there was a syntax error at includes then would be no dependencies also */
/* Therefore looking at dependencies is not the right way to load includes */
/* getDependencies does not distinguish between setContinues or parseIncludes */
})
test("getIncludes", () => {
/* Parse includes has set the includes */
switch project->Project.getIncludes("main") {
| Ok(includes) => includes->expect == ["common"]
| Error(err) => err->SqError.toString->fail
}
/* If the includes cannot be parsed then you get a syntax error.
test(
"getDependencies",
() => {
/* Parse includes has set the dependencies */
project->Project.getDependencies("main")->expect == ["common"]
/* If there were no includes than there would be no dependencies */
/* However if there was a syntax error at includes then would be no dependencies also */
/* Therefore looking at dependencies is not the right way to load includes */
/* getDependencies does not distinguish between setContinues or parseIncludes */
},
)
test(
"getIncludes",
() => {
/* Parse includes has set the includes */
switch project->Project.getIncludes("main") {
| Ok(includes) => includes->expect == ["common"]
| Error(err) => err->SqError.toString->fail
}
/* If the includes cannot be parsed then you get a syntax error.
Otherwise you get the includes.
If there is no syntax error then you can load that file and use setSource to add it to the project.
And so on recursively... */
})
test("getDependents", () => {
/* For any reason, you are able to query what other sources
},
)
test(
"getDependents",
() => {
/* For any reason, you are able to query what other sources
include or depend on the current source.
But you don't need to use this to execute the projects.
It is provided for completeness of information. */
project->Project.getDependents("main")->expect == []
/* Nothing is depending on or including main */
})
project->Project.getDependents("main")->expect == []
/* Nothing is depending on or including main */
},
)
describe("Real Like", () => {
/* Now let's look at recursive and possibly cyclic includes */
/* There is no function provided to load the include files.
describe(
"Real Like",
() => {
/* Now let's look at recursive and possibly cyclic includes */
/* There is no function provided to load the include files.
Because we have no idea if will it be an ordinary function or will it use promises.
Therefore one has to write a function to load sources recursively and and setSources
while checking for dependencies */
/* Let's make a dummy loader */
let loadSource = (sourceName: string) =>
switch sourceName {
| "source1" => "x=1"
| "source2" => `
/* Let's make a dummy loader */
let loadSource = (sourceName: string) =>
switch sourceName {
| "source1" => "x=1"
| "source2" => `
#include "source1"
y=2`
| "source3" => `
| "source3" => `
#include "source2"
z=3`
| _ => `source ${sourceName} not found`->Js.Exn.raiseError
}
| _ => `source ${sourceName} not found`->Js.Exn.raiseError
}
/* let's recursively load the sources */
let rec loadIncludesRecursively = (project, sourceName, visited) => {
if visited->Js.Array2.includes(sourceName) {
/* Oh we have already visited this source. There is an include cycle */
"Cyclic include ${sourceName}"->Js.Exn.raiseError
} else {
let newVisited = Js.Array2.copy(visited)
let _ = newVisited->Js.Array2.push(sourceName)
/* Let's parse the includes and dive into them */
Project.parseIncludes(project, sourceName)
let rIncludes = project->Project.getIncludes(sourceName)
switch rIncludes {
/* Maybe there is an include syntax error */
| Error(err) => err->SqError.toString->Js.Exn.raiseError
/* let's recursively load the sources */
let rec loadIncludesRecursively = (project, sourceName, visited) => {
if visited->Js.Array2.includes(sourceName) {
/* Oh we have already visited this source. There is an include cycle */
"Cyclic include ${sourceName}"->Js.Exn.raiseError
} else {
let newVisited = Js.Array2.copy(visited)
let _ = newVisited->Js.Array2.push(sourceName)
/* Let's parse the includes and dive into them */
Project.parseIncludes(project, sourceName)
let rIncludes = project->Project.getIncludes(sourceName)
switch rIncludes {
/* Maybe there is an include syntax error */
| Error(err) => err->SqError.toString->Js.Exn.raiseError
| Ok(includes) =>
includes->Belt.Array.forEach(newIncludeName => {
/* We have got one of the new includes.
Let's load it and add it to the project */
let newSource = loadSource(newIncludeName)
project->Project.setSource(newIncludeName, newSource)
/* The new source is loaded and added to the project. */
/* Of course the new source might have includes too. */
/* Let's recursively load them */
project->loadIncludesRecursively(newIncludeName, newVisited)
})
| Ok(includes) =>
includes->Belt.Array.forEach(
newIncludeName => {
/* We have got one of the new includes.
Let's load it and add it to the project */
let newSource = loadSource(newIncludeName)
project->Project.setSource(newIncludeName, newSource)
/* The new source is loaded and added to the project. */
/* Of course the new source might have includes too. */
/* Let's recursively load them */
project->loadIncludesRecursively(newIncludeName, newVisited)
},
)
}
}
}
}
/* As we have a fake source loader and a recursive include handler,
We can not set up a real project */
/* As we have a fake source loader and a recursive include handler,
We can not set up a real project */
/* * Here starts our real life project! * */
/* * Here starts our real life project! * */
let project = Project.createProject()
let project = Project.createProject()
project->Project.setSource(
"main",
`
project->Project.setSource(
"main",
`
#include "source1"
#include "source2"
#include "source3"
@ -118,37 +131,43 @@ Here we will finally proceed to a real life scenario. */
b = doubleX
a
`,
)
/* Setting source requires parsing and loading the includes recursively */
project->loadIncludesRecursively("main", []) // Not visited yet
)
/* Setting source requires parsing and loading the includes recursively */
project->loadIncludesRecursively("main", []) // Not visited yet
/* Let's salt it more. Let's have another source in the project which also has includes */
/* doubleX includes source1 which is eventually included by main as well */
project->Project.setSource(
"doubleX",
`
/* Let's salt it more. Let's have another source in the project which also has includes */
/* doubleX includes source1 which is eventually included by main as well */
project->Project.setSource(
"doubleX",
`
#include "source1"
doubleX = x * 2
`,
)
project->loadIncludesRecursively("doubleX", [])
/* Remember, any time you set a source, you need to load includes recursively */
)
project->loadIncludesRecursively("doubleX", [])
/* Remember, any time you set a source, you need to load includes recursively */
/* As doubleX is not included by main, it is not loaded recursively.
So we link it to the project as a dependency */
project->Project.setContinues("main", ["doubleX"])
/* As doubleX is not included by main, it is not loaded recursively.
So we link it to the project as a dependency */
project->Project.setContinues("main", ["doubleX"])
/* Let's run the project */
project->Project.runAll
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* And see the result and bindings.. */
test("recursive includes", () => {
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(6)", "{a: 6,b: 2}")
/* Everything as expected */
})
})
/* Let's run the project */
project->Project.runAll
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* And see the result and bindings.. */
test(
"recursive includes",
() => {
(
result->Reducer_Value.toStringResult,
bindings->Reducer_Value.toStringRecord,
)->expect == ("Ok(6)", "{a: 6,b: 2}")
/* Everything as expected */
},
)
},
)
})
describe("Includes myFile as myVariable", () => {
@ -163,14 +182,20 @@ Here we will finally proceed to a real life scenario. */
`,
)
Project.parseIncludes(project, "main")
test("getDependencies", () => {
Project.getDependencies(project, "main")->expect == ["common"]
})
test("getIncludes", () => {
switch Project.getIncludes(project, "main") {
| Ok(includes) => includes->expect == ["common"]
| Error(err) => err->SqError.toString->fail
}
})
test(
"getDependencies",
() => {
Project.getDependencies(project, "main")->expect == ["common"]
},
)
test(
"getIncludes",
() => {
switch Project.getIncludes(project, "main") {
| Ok(includes) => includes->expect == ["common"]
| Error(err) => err->SqError.toString->fail
}
},
)
})
})

View File

@ -30,8 +30,9 @@ describe("ReducerProject Tutorial", () => {
})
test("userResults", () => {
let userResultsAsString = Belt.Array.map(userResults, aResult =>
aResult->Reducer_Value.toStringResult
let userResultsAsString = Belt.Array.map(
userResults,
aResult => aResult->Reducer_Value.toStringResult,
)
userResultsAsString->expect == ["Ok(2)", "Ok(4)", "Ok(6)", "Ok(8)", "Ok(10)"]
})

View File

@ -99,15 +99,19 @@ describe("FunctionRegistry Library", () => {
})
describe("Fn auto-testing", () => {
testAll("tests of validity", examples, r => {
expectEvalToBeOk(r)
})
testAll(
"tests of validity",
examples,
r => {
expectEvalToBeOk(r)
},
)
testAll(
"tests of type",
E.A.to_list(
FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(((fn, _)) =>
E.O.isSome(fn.output)
FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(
((fn, _)) => E.O.isSome(fn.output),
),
),
((fn, example)) => {

View File

@ -45,12 +45,12 @@ let toExtDist: option<DistributionTypes.genericDist> => DistributionTypes.generi
let unpackFloat = x => x->toFloat->toExtFloat
let unpackDist = y => y->toDist->toExtDist
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev}))
let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean, stdev}))
let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha, beta}))
let mkExponential = rate => DistributionTypes.Symbolic(#Exponential({rate: rate}))
let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low: low, high: high}))
let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local: local, scale: scale}))
let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))
let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low, high}))
let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local, scale}))
let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu, sigma}))
let mkDelta = x => DistributionTypes.Symbolic(#Float(x))
let normalMake = SymbolicDist.Normal.make

View File

@ -25,7 +25,6 @@
],
"suffix": ".bs.js",
"namespace": true,
"bs-dependencies": ["bisect_ppx"],
"bs-dev-dependencies": [
"@glennsl/rescript-jest",
"rescript-fast-check",
@ -45,8 +44,5 @@
"refmt": 3,
"warnings": {
"number": "+A-42-48-9-30-4"
},
"ppx-flags": [
["../../node_modules/bisect_ppx/ppx", "--exclude-files", ".*_test\\.res$$"]
]
}
}

View File

@ -2,9 +2,6 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
setupFilesAfterEnv: [
"<rootdir>/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js",
],
testPathIgnorePatterns: [
".*Fixtures.bs.js",
"/node_modules/",

View File

@ -22,10 +22,8 @@
"test:rescript": "jest --modulePathIgnorePatterns=__tests__/TS/*",
"test:watch": "jest --watchAll",
"test:fnRegistry": "jest __tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.bs.js",
"coverage:rescript": "rm -f *.coverage && yarn clean && BISECT_ENABLE=yes yarn build && yarn test:rescript && bisect-ppx-report html",
"coverage:ts": "yarn clean && yarn build && nyc --reporter=lcov yarn test:ts",
"coverage:rescript:ci": "yarn clean && BISECT_ENABLE=yes yarn build:rescript && yarn test:rescript && bisect-ppx-report send-to Codecov",
"coverage:ts:ci": "yarn coverage:ts && codecov",
"coverage:local": "jest --coverage && echo && echo 'Open ./coverage/lcov-report/index.html to see the detailed report.'",
"coverage": "jest --coverage && codecov",
"lint:rescript": "./lint.sh",
"lint:prettier": "prettier --check .",
"lint": "yarn lint:rescript && yarn lint:prettier",
@ -41,7 +39,7 @@
],
"author": "Quantified Uncertainty Research Institute",
"dependencies": {
"@rescript/std": "^9.1.4",
"@rescript/std": "^10.0.0",
"@stdlib/stats": "^0.0.13",
"jstat": "^1.9.5",
"lodash": "^4.17.21",
@ -50,24 +48,20 @@
},
"devDependencies": {
"@glennsl/rescript-jest": "^0.9.2",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@types/jest": "^27.5.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"bisect_ppx": "^2.7.1",
"chalk": "^5.0.1",
"chalk": "^5.1.0",
"codecov": "^3.8.3",
"fast-check": "^3.1.4",
"gentype": "^4.5.0",
"jest": "^27.5.1",
"moduleserve": "^0.9.1",
"nyc": "^15.1.0",
"peggy": "^2.0.1",
"prettier": "^2.7.1",
"reanalyze": "^2.23.0",
"rescript": "^9.1.4",
"rescript": "^10.0.0",
"rescript-fast-check": "^1.1.1",
"rescript-js-map": "^1.1.0",
"ts-jest": "^27.1.4",
"ts-jest": "^29.0.3",
"ts-loader": "^9.4.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.4",

View File

@ -141,6 +141,7 @@ let rec run = (~env: env, functionCallInfo: functionCallInfo): outputType => {
Js.log2("Console log requested: ", dist)
Dist(dist)
}
| #ToDist(Normalize) => dist->GenericDist.normalize->Dist
| #ToScore(LogScore(answer, prior)) =>
GenericDist.Score.logScore(~estimate=dist, ~answer, ~prior, ~env)

View File

@ -99,6 +99,7 @@ let toFloatOperation = (
}
}
}
| (#Stdev | #Variance | #Mode) as op =>
switch t {
| SampleSet(s) =>
@ -129,7 +130,7 @@ let toPointSet = (
SampleSetDist.toPointSetDist(
~samples=r,
~samplingInputs={
sampleCount: sampleCount,
sampleCount,
outputXYPoints: xyPointLength,
pointSetDistLength: xyPointLength,
kernelWidth: None,
@ -427,6 +428,7 @@ module AlgebraicCombination = {
~toSampleSetFn,
)
}
| (None, AsMonteCarlo) =>
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
| (None, AsSymbolic) =>
@ -443,6 +445,7 @@ module AlgebraicCombination = {
)}`
Error(RequestedStrategyInvalidError(errString))
}
| Some(convOp) => StrategyCallOnValidatedInputs.convolution(toPointSetFn, convOp, t1, t2)
}
}

View File

@ -69,7 +69,7 @@ let toDiscretePointMassesFromTriangulars = (
()
}
{n: n - 2, masses: masses, means: means, variances: variances}
{n: n - 2, masses, means, variances}
} else {
for i in 1 to n - 2 {
// area of triangle = width * height / 2
@ -91,7 +91,7 @@ let toDiscretePointMassesFromTriangulars = (
) |> ignore
()
}
{n: n - 2, masses: masses, means: means, variances: variances}
{n: n - 2, masses, means, variances}
}
}
@ -184,7 +184,7 @@ let toDiscretePointMassesFromDiscrete = (s: PointSetTypes.xyShape): pointMassesW
let means: array<float> = Belt.Array.makeBy(n, i => xs[i])
let variances: array<float> = Belt.Array.makeBy(n, _ => 0.0)
{n: n, masses: masses, means: means, variances: variances}
{n, masses, means, variances}
}
type argumentPosition = First | Second

View File

@ -45,16 +45,16 @@ module Analysis = {
let getShape = (t: t) => t.xyShape
let interpolation = (t: t) => t.interpolation
let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
xyShape: xyShape,
interpolation: interpolation,
integralSumCache: integralSumCache,
integralCache: integralCache,
xyShape,
interpolation,
integralSumCache,
integralCache,
}
let shapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): t => {
xyShape: fn(xyShape),
interpolation: interpolation,
integralSumCache: integralSumCache,
integralCache: integralCache,
interpolation,
integralSumCache,
integralCache,
}
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY
let oShapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): option<
@ -135,10 +135,10 @@ let shapeFn = (fn, t: t) => t |> getShape |> fn
let updateIntegralSumCache = (integralSumCache, t: t): t => {
...t,
integralSumCache: integralSumCache,
integralSumCache,
}
let updateIntegralCache = (integralCache, t: t): t => {...t, integralCache: integralCache}
let updateIntegralCache = (integralCache, t: t): t => {...t, integralCache}
let sum = (
~integralSumCachesFn: (float, float) => option<float>=(_, _) => None,

View File

@ -4,14 +4,14 @@ open Distributions
type t = PointSetTypes.discreteShape
let make = (~integralSumCache=None, ~integralCache=None, xyShape): t => {
xyShape: xyShape,
integralSumCache: integralSumCache,
integralCache: integralCache,
xyShape,
integralSumCache,
integralCache,
}
let shapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): t => {
xyShape: fn(xyShape),
integralSumCache: integralSumCache,
integralCache: integralCache,
integralSumCache,
integralCache,
}
let getShape = (t: t) => t.xyShape
let oShapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): option<t> =>
@ -63,12 +63,12 @@ let reduce = (
let updateIntegralSumCache = (integralSumCache, t: t): t => {
...t,
integralSumCache: integralSumCache,
integralSumCache,
}
let updateIntegralCache = (integralCache, t: t): t => {
...t,
integralCache: integralCache,
integralCache,
}
/* This multiples all of the data points together and creates a new discrete distribution from the results.

View File

@ -4,10 +4,10 @@ open Distributions
type t = PointSetTypes.mixedShape
let make = (~integralSumCache=None, ~integralCache=None, ~continuous, ~discrete): t => {
continuous: continuous,
discrete: discrete,
integralSumCache: integralSumCache,
integralCache: integralCache,
continuous,
discrete,
integralSumCache,
integralCache,
}
let totalLength = (t: t): int => {
@ -35,7 +35,7 @@ let toDiscrete = ({discrete}: t) => Some(discrete)
let updateIntegralCache = (integralCache, t: t): t => {
...t,
integralCache: integralCache,
integralCache,
}
let combinePointwise = (

View File

@ -79,8 +79,8 @@ module MixedPoint = {
type t = mixedPoint
let toContinuousValue = (t: t) => t.continuous
let toDiscreteValue = (t: t) => t.discrete
let makeContinuous = (continuous: float): t => {continuous: continuous, discrete: 0.0}
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete: discrete}
let makeContinuous = (continuous: float): t => {continuous, discrete: 0.0}
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete}
let fmap = (fn: float => float, t: t) => {
continuous: fn(t.continuous),

View File

@ -7,7 +7,7 @@ module Normal = {
type t = normal
let make = (mean: float, stdev: float): result<symbolicDist, string> =>
stdev > 0.0
? Ok(#Normal({mean: mean, stdev: stdev}))
? Ok(#Normal({mean, stdev}))
: Error("Standard deviation of normal distribution must be larger than 0")
let pdf = (x, t: t) => Jstat.Normal.pdf(x, t.mean, t.stdev)
let cdf = (x, t: t) => Jstat.Normal.cdf(x, t.mean, t.stdev)
@ -15,7 +15,7 @@ module Normal = {
let from90PercentCI = (low, high) => {
let mean = E.A.Floats.mean([low, high])
let stdev = (high -. low) /. (2. *. normal95confidencePoint)
#Normal({mean: mean, stdev: stdev})
#Normal({mean, stdev})
}
let inv = (p, t: t) => Jstat.Normal.inv(p, t.mean, t.stdev)
let sample = (t: t) => Jstat.Normal.sample(t.mean, t.stdev)
@ -25,12 +25,12 @@ module Normal = {
let add = (n1: t, n2: t) => {
let mean = n1.mean +. n2.mean
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
#Normal({mean: mean, stdev: stdev})
#Normal({mean, stdev})
}
let subtract = (n1: t, n2: t) => {
let mean = n1.mean -. n2.mean
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
#Normal({mean: mean, stdev: stdev})
#Normal({mean, stdev})
}
// TODO: is this useful here at all? would need the integral as well ...
@ -38,7 +38,7 @@ module Normal = {
let mean =
(n1.mean *. n2.stdev ** 2. +. n2.mean *. n1.stdev ** 2.) /. (n1.stdev ** 2. +. n2.stdev ** 2.)
let stdev = 1. /. (1. /. n1.stdev ** 2. +. 1. /. n2.stdev ** 2.)
#Normal({mean: mean, stdev: stdev})
#Normal({mean, stdev})
}
let operate = (operation: Operation.Algebraic.t, n1: t, n2: t) =>
@ -88,7 +88,7 @@ module Cauchy = {
type t = cauchy
let make = (local, scale): result<symbolicDist, string> =>
scale > 0.0
? Ok(#Cauchy({local: local, scale: scale}))
? Ok(#Cauchy({local, scale}))
: Error("Cauchy distribution scale parameter must larger than 0.")
let pdf = (x, t: t) => Jstat.Cauchy.pdf(x, t.local, t.scale)
let cdf = (x, t: t) => Jstat.Cauchy.cdf(x, t.local, t.scale)
@ -102,7 +102,7 @@ module Triangular = {
type t = triangular
let make = (low, medium, high): result<symbolicDist, string> =>
low < medium && medium < high
? Ok(#Triangular({low: low, medium: medium, high: high}))
? Ok(#Triangular({low, medium, high}))
: Error("Triangular values must be increasing order.")
let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) // not obvious in jstat docs that high comes before medium?
let cdf = (x, t: t) => Jstat.Triangular.cdf(x, t.low, t.high, t.medium)
@ -116,7 +116,7 @@ module Beta = {
type t = beta
let make = (alpha, beta) =>
alpha > 0.0 && beta > 0.0
? Ok(#Beta({alpha: alpha, beta: beta}))
? Ok(#Beta({alpha, beta}))
: Error("Beta distribution parameters must be positive")
let pdf = (x, t: t) => Jstat.Beta.pdf(x, t.alpha, t.beta)
let cdf = (x, t: t) => Jstat.Beta.cdf(x, t.alpha, t.beta)
@ -150,7 +150,7 @@ module Lognormal = {
type t = lognormal
let make = (mu, sigma) =>
sigma > 0.0
? Ok(#Lognormal({mu: mu, sigma: sigma}))
? Ok(#Lognormal({mu, sigma}))
: Error("Lognormal standard deviation must be larger than 0")
let pdf = (x, t: t) => Jstat.Lognormal.pdf(x, t.mu, t.sigma)
let cdf = (x, t: t) => Jstat.Lognormal.cdf(x, t.mu, t.sigma)
@ -164,7 +164,7 @@ module Lognormal = {
let logHigh = Js.Math.log(high)
let mu = E.A.Floats.mean([logLow, logHigh])
let sigma = (logHigh -. logLow) /. (2.0 *. normal95confidencePoint)
#Lognormal({mu: mu, sigma: sigma})
#Lognormal({mu, sigma})
}
let fromMeanAndStdev = (mean, stdev) => {
// https://math.stackexchange.com/questions/2501783/parameters-of-a-lognormal-distribution
@ -174,7 +174,7 @@ module Lognormal = {
let meanSquared = mean ** 2.
let mu = 2. *. Js.Math.log(mean) -. 0.5 *. Js.Math.log(variance +. meanSquared)
let sigma = Js.Math.sqrt(Js.Math.log(variance /. meanSquared +. 1.))
Ok(#Lognormal({mu: mu, sigma: sigma}))
Ok(#Lognormal({mu, sigma}))
} else {
Error("Lognormal standard deviation must be larger than 0")
}
@ -184,14 +184,14 @@ module Lognormal = {
// https://wikiless.org/wiki/Log-normal_distribution?lang=en#Multiplication_and_division_of_independent,_log-normal_random_variables
let mu = l1.mu +. l2.mu
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
#Lognormal({mu: mu, sigma: sigma})
#Lognormal({mu, sigma})
}
let divide = (l1, l2) => {
let mu = l1.mu -. l2.mu
// We believe the ratiands will have covariance zero.
// See here https://stats.stackexchange.com/questions/21735/what-are-the-mean-and-variance-of-the-ratio-of-two-lognormal-variables for details
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
#Lognormal({mu: mu, sigma: sigma})
#Lognormal({mu, sigma})
}
let operate = (operation: Operation.Algebraic.t, n1: t, n2: t) =>
switch operation {
@ -220,7 +220,7 @@ module Lognormal = {
module Uniform = {
type t = uniform
let make = (low, high) =>
high > low ? Ok(#Uniform({low: low, high: high})) : Error("High must be larger than low")
high > low ? Ok(#Uniform({low, high})) : Error("High must be larger than low")
let pdf = (x, t: t) => Jstat.Uniform.pdf(x, t.low, t.high)
let cdf = (x, t: t) => Jstat.Uniform.cdf(x, t.low, t.high)
@ -239,9 +239,7 @@ module Uniform = {
module Logistic = {
type t = logistic
let make = (location, scale) =>
scale > 0.0
? Ok(#Logistic({location: location, scale: scale}))
: Error("Scale must be positive")
scale > 0.0 ? Ok(#Logistic({location, scale})) : Error("Scale must be positive")
let pdf = (x, t: t) => Stdlib.Logistic.pdf(x, t.location, t.scale)
let cdf = (x, t: t) => Stdlib.Logistic.cdf(x, t.location, t.scale)
@ -285,7 +283,7 @@ module Gamma = {
let make = (shape: float, scale: float) => {
if shape > 0. {
if scale > 0. {
Ok(#Gamma({shape: shape, scale: scale}))
Ok(#Gamma({shape, scale}))
} else {
Error("scale must be larger than 0")
}
@ -543,6 +541,6 @@ module T = {
| _ =>
let xs = interpolateXs(~xSelection, d, sampleCount)
let ys = xs |> E.A.fmap(x => pdf(x, d))
Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs: xs, ys: ys}))
Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs, ys}))
}
}

View File

@ -23,7 +23,7 @@ let makeFn = (
name: string,
inputs: array<frType>,
fn: array<Reducer_T.value> => result<Reducer_T.value, errorMessage>,
) => makeFnMany(name, [{inputs: inputs, fn: fn}])
) => makeFnMany(name, [{inputs, fn}])
let library = [
Make.ff2f(~name="add", ~fn=(x, y) => x +. y, ()), // infix + (see Reducer/Reducer_Peggy/helpers.ts)
@ -62,6 +62,7 @@ let library = [
let answer = Js.String2.concat(a, b)
answer->Reducer_T.IEvString->Ok
}
| _ => Error(impossibleError)
}
}),
@ -72,6 +73,7 @@ let library = [
let _ = Js.Array2.pushMany(a, b)
a->Reducer_T.IEvArray->Ok
}
| _ => Error(impossibleError)
}
}),
@ -81,6 +83,7 @@ let library = [
Js.log(value->Reducer_Value.toString)
value->Ok
}
| _ => Error(impossibleError)
}
}),
@ -90,6 +93,7 @@ let library = [
Js.log(`${label}: ${value->Reducer_Value.toString}`)
value->Ok
}
| _ => Error(impossibleError)
}
}),

View File

@ -135,11 +135,13 @@ module Integration = {
let wrappedResult = result->Reducer_T.IEvNumber->Ok
wrappedResult
}
| (Error(b), _) => Error(b)
| (_, Error(b)) => Error(b)
}
resultWithOuterPoints
}
| Error(b) =>
("Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
"Original error: " ++
@ -362,6 +364,7 @@ module DiminishingReturns = {
result[indexOfBiggestDMR] = value
Ok(result)
}
| Error(b) => Error(b)
}
@ -371,10 +374,12 @@ module DiminishingReturns = {
}
Ok(newAcc)
}
| Error(b) => Error(b)
}
newAccWrapped
}
| Error(b) => Error(b)
}
})
@ -427,10 +432,12 @@ module DiminishingReturns = {
)
result
}
| Error(b) => Error(b)
}
result
}
| _ =>
"Error in Danger.diminishingMarginalReturnsForTwoFunctions"
->SqError.Message.REOther

View File

@ -20,6 +20,7 @@ module Declaration = {
->E.A.R.firstErrorOrOpen
->E.R2.fmap(args => Reducer_T.IEvDeclaration(Declaration.make(lambda, args)))
}
| Error(r) => Error(r)
| Ok(_) => Error(impossibleErrorString)
}

View File

@ -140,6 +140,7 @@ module Old = {
| Error(err) => error(err)
}
}
| Some(IEvNumber(_))
| Some(IEvDistribution(_)) =>
switch parseDistributionArray(args) {
@ -192,6 +193,7 @@ module Old = {
}
Helpers.toFloatFn(fn, dist, ~env)
}
| ("integralSum", [IEvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env)
| ("toString", [IEvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env)
| ("sparkline", [IEvDistribution(dist)]) =>

View File

@ -19,6 +19,7 @@ let inputsToDist = (inputs: array<Reducer_T.value>, xyShapeToPointSetDist) => {
| _ => impossibleError->SqError.Message.throw
}
}
| _ => impossibleError->SqError.Message.throw
}
)

View File

@ -61,6 +61,7 @@ module FRType = {
let input = ((name, frType): frTypeRecordParam) => `${name}: ${toString(frType)}`
`{${r->E.A2.fmap(input)->E.A2.joinWith(", ")}}`
}
| FRTypeArray(r) => `list(${toString(r)})`
| FRTypeLambda => `lambda`
| FRTypeString => `string`
@ -132,9 +133,9 @@ module FnDefinition = {
}
let make = (~name, ~inputs, ~run, ()): t => {
name: name,
inputs: inputs,
run: run,
name,
inputs,
run,
}
}
@ -160,14 +161,14 @@ module Function = {
~isExperimental=false,
(),
): t => {
name: name,
nameSpace: nameSpace,
definitions: definitions,
output: output,
name,
nameSpace,
definitions,
output,
examples: examples->E.O2.default([]),
isExperimental: isExperimental,
requiresNamespace: requiresNamespace,
description: description,
isExperimental,
requiresNamespace,
description,
}
let toJson = (t: t): functionJson => {
@ -203,15 +204,19 @@ module Registry = {
fn.requiresNamespace ? [] : [def.name],
]->E.A.concatMany
names->Belt.Array.reduce(acc, (acc, name) => {
switch acc->Belt.Map.String.get(name) {
| Some(fns) => {
let _ = fns->Js.Array2.push(def) // mutates the array, no need to update acc
acc
names->Belt.Array.reduce(
acc,
(acc, name) => {
switch acc->Belt.Map.String.get(name) {
| Some(fns) => {
let _ = fns->Js.Array2.push(def) // mutates the array, no need to update acc
acc
}
| None => acc->Belt.Map.String.set(name, [def])
}
| None => acc->Belt.Map.String.set(name, [def])
}
})
},
)
})
)
}
@ -245,6 +250,7 @@ module Registry = {
| None => REOther(showNameMatchDefinitions())->Error
}
}
| None => RESymbolNotFound(fnName)->Error
}
}

View File

@ -34,6 +34,7 @@ module Prepare = {
let n2 = map->Belt.Map.String.getExn(arg2)
Ok([n1, n2])
}
| _ => Error(impossibleErrorString)
}
@ -45,6 +46,7 @@ module Prepare = {
let n3 = map->Belt.Map.String.getExn(arg3)
Ok([n1, n2, n3])
}
| _ => Error(impossibleErrorString)
}
}

View File

@ -44,4 +44,4 @@ let removeResult = ({namespace} as bindings: t): t => {
let locals = ({namespace}: t): Reducer_T.namespace => namespace
let fromNamespace = (namespace: Reducer_Namespace.t): t => {namespace: namespace, parent: None}
let fromNamespace = (namespace: Reducer_Namespace.t): t => {namespace, parent: None}

View File

@ -6,7 +6,7 @@ let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environ
{
frameStack: list{},
bindings: stdLib->Reducer_Bindings.fromNamespace->Reducer_Bindings.extend,
environment: environment,
environment,
inFunction: None,
}
}

View File

@ -123,6 +123,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
)
(result, context)
}
| _ => RENotAFunction(lambda->Reducer_Value.toString)->throwFrom(expression, context)
}
}

View File

@ -23,8 +23,8 @@ let make = (): t => list{}
let extend = (t: t, name: string, location: option<Reducer_Peggy_Parse.location>) =>
t->Belt.List.add({
name: name,
location: location,
name,
location,
})
// this is useful for SyntaxErrors

View File

@ -43,10 +43,10 @@ let makeLambda = (
FnLambda({
// context: bindings,
name: name,
name,
body: lambda,
parameters: parameters,
location: location,
parameters,
location,
})
}
@ -54,8 +54,8 @@ let makeLambda = (
let makeFFILambda = (name: string, body: Reducer_T.lambdaBody): t => FnBuiltin({
// Note: current bindings could be accidentally exposed here through context (compare with native lambda implementation above, where we override them with local bindings).
// But FunctionRegistry API is too limited for that to matter. Please take care not to violate that in the future by accident.
body: body,
name: name,
body,
name,
})
// this function doesn't scale to FunctionRegistry's polymorphic functions

View File

@ -113,7 +113,7 @@ let nodeToAST = (node: node) => {
| _ => raise(UnsupportedPeggyNodeType(node["type"]))
}
{location: node["location"], content: content}
{location: node["location"], content}
}
let nodeIdentifierToAST = (node: nodeIdentifier) => {

View File

@ -68,7 +68,7 @@ let rec fromNode = (node: Parse.node): expression => {
}
{
ast: ast,
content: content,
ast,
content,
}
}

View File

@ -216,6 +216,7 @@ let tryRunWithResult = (
project->setResult(sourceId, Error(error))
Error(error)
}
| Ok(_prevResult) => {
project->doLinkAndRun(sourceId)
project->getResultOption(sourceId)->Belt.Option.getWithDefault(rPrevResult)

View File

@ -6,7 +6,7 @@ type t = T.t
let emptyItem = (sourceId: string): projectItem => {
source: "",
sourceId: sourceId,
sourceId,
rawParse: None,
expression: None,
continuation: Reducer_Namespace.make(),
@ -76,7 +76,7 @@ let resetIncludes = (r: t): t => {
}
let setSource = (r: t, source: T.sourceArgumentType): t =>
{...r, source: source}->resetIncludes->touchSource
{...r, source}->resetIncludes->touchSource
let setRawParse = (r: t, rawParse: T.rawParseArgumentType): t =>
{...r, rawParse: Some(rawParse)}->touchRawParse
@ -86,7 +86,7 @@ let setExpression = (r: t, expression: T.expressionArgumentType): t =>
let setContinuation = (r: t, continuation: T.continuationArgumentType): t => {
...r,
continuation: continuation,
continuation,
}
let setResult = (r: t, result: T.resultArgumentType): t => {
@ -110,24 +110,23 @@ let getPastChain = (this: t): array<string> => {
Js.Array2.concat(getDirectIncludes(this), getContinues(this))
}
let setContinues = (this: t, continues: array<string>): t =>
{...this, continues: continues}->touchSource
let setContinues = (this: t, continues: array<string>): t => {...this, continues}->touchSource
let removeContinues = (this: t): t => {...this, continues: []}->touchSource
let setIncludes = (this: t, includes: T.includesType): t => {
...this,
includes: includes,
includes,
}
let setImportAsVariables = (this: t, includeAsVariables: T.importAsVariablesType): t => {
...this,
includeAsVariables: includeAsVariables,
includeAsVariables,
}
let setDirectImports = (this: t, directIncludes: array<string>): t => {
...this,
directIncludes: directIncludes,
directIncludes,
}
let parseIncludes = (this: t): t => {
@ -144,9 +143,9 @@ let parseIncludes = (this: t): t => {
->Belt.Array.map(((_variable, file)) => file)
{
...this,
includes: includes,
includeAsVariables: includeAsVariables,
directIncludes: directIncludes,
includes,
includeAsVariables,
directIncludes,
}
}
}

View File

@ -54,6 +54,7 @@ module Message = {
}
answer
}
| REMacroNotFound(macro) => `Macro not found: ${macro}`
| RENotAFunction(valueString) => `${valueString} is not a function`
| RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
@ -93,8 +94,8 @@ type t = {
exception SqException(t)
let fromMessageWithFrameStack = (message: Message.t, frameStack: Reducer_FrameStack.t): t => {
message: message,
frameStack: frameStack,
message,
frameStack,
}
// this shouldn't be used much, since frame stack will be empty

View File

@ -18,6 +18,7 @@ let stdLib: Reducer_T.namespace = {
| None => REArrayIndexNotFound("Array index not found", index)->SqError.Message.throw
}
}
| [IEvRecord(dict), IEvString(sIndex)] =>
switch Belt.Map.String.get(dict, sIndex) {
| Some(value) => value

View File

@ -9,13 +9,13 @@ type declaration<'a> = {
module ContinuousFloatArg = {
let make = (min: float, max: float): arg => {
Float({min: min, max: max})
Float({min, max})
}
}
module ContinuousTimeArg = {
let make = (min: Js.Date.t, max: Js.Date.t): arg => {
Date({min: min, max: max})
Date({min, max})
}
}
@ -33,7 +33,7 @@ module Arg = {
}
let make = (fn: 'a, args: array<arg>): declaration<'a> => {
{fn: fn, args: args}
{fn, args}
}
let toString = (r: declaration<'a>, fnToString): string => {

View File

@ -85,8 +85,8 @@ module T = {
}
let square = mapX(x => x ** 2.0)
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys)
let fromArray = ((xs, ys)): t => {xs: xs, ys: ys}
let fromArrays = (xs, ys): t => {xs: xs, ys: ys}
let fromArray = ((xs, ys)): t => {xs, ys}
let fromArrays = (xs, ys): t => {xs, ys}
let accumulateYs = (fn, p: t) => fromArray((p.xs, E.A.accumulate(fn, p.ys)))
let concat = (t1: t, t2: t) => {
let cxs = Array.concat(list{t1.xs, t2.xs})
@ -142,7 +142,7 @@ module T = {
}
let make = (~xs: array<float>, ~ys: array<float>) => {
let attempt: t = {xs: xs, ys: ys}
let attempt: t = {xs, ys}
switch Validator.validate(attempt) {
| Some(error) => Error(error)
| None => Ok(attempt)
@ -452,6 +452,7 @@ module PointwiseCombination = {
let _ = Js.Array.push(fn(y1, y2), newYs)
let _ = Js.Array.push(x, newXs)
}
| None => ()
}
}
@ -558,7 +559,7 @@ module Range = {
(xs[x + 1] -. xs[x]) *. ((ys[x] +. ys[x + 1]) /. 2.) +. cumulativeY[x], // dx // (1/2) * (avgY)
)
}
Some({xs: xs, ys: cumulativeY})
Some({xs, ys: cumulativeY})
}
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x)

View File

@ -3,3 +3,4 @@
/server/out
/*.vsix
/syntaxes/*.json
dist

View File

@ -1,7 +1,10 @@
.vscode/**
.vscode-test/**
src/**
client
server
.gitignore
node_modules
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json

View File

@ -1,12 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"lib": ["ES2020", "dom"],
"outDir": "out",
"rootDir": "src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", ".vscode-test"]
}

View File

@ -22,7 +22,7 @@
"onCustomEditor:squiggle.wysiwyg",
"onCommand:squiggle.preview"
],
"main": "./client/out/extension.js",
"main": "./dist/src/client/extension.js",
"contributes": {
"languages": [
{
@ -114,30 +114,32 @@
}
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile:tsc": "tsc -b",
"compile:grammar": "js-yaml syntaxes/squiggle.tmLanguage.yaml >syntaxes/squiggle.tmLanguage.json",
"compile:vendor": "(cd ../squiggle-lang && yarn run build) && (cd ../components && yarn run bundle && yarn run build:css) && mkdir -p media/vendor && cp ../components/dist/bundle.js media/vendor/components.js && cp ../components/dist/main.css media/vendor/components.css && cp ../../node_modules/react/umd/react.production.min.js media/vendor/react.js && cp ../../node_modules/react-dom/umd/react-dom.production.min.js media/vendor/react-dom.js && cp ../website/static/img/squiggle-logo.png media/vendor/icon.png",
"compile": "yarn run compile:vendor && yarn run compile:grammar && yarn run compile:tsc",
"watch": "tsc -b -watch",
"pretest": "yarn run compile && yarn run lint",
"lint": "prettier --check .",
"vscode:prepublish": "yarn run lint && yarn run build",
"build:grammar": "js-yaml syntaxes/squiggle.tmLanguage.yaml >syntaxes/squiggle.tmLanguage.json",
"build:vendor": "mkdir -p media/vendor && cp ../components/dist/bundle.js media/vendor/components.js && cp ../components/dist/main.css media/vendor/components.css && cp ../../node_modules/react/umd/react.production.min.js media/vendor/react.js && cp ../../node_modules/react-dom/umd/react-dom.production.min.js media/vendor/react-dom.js && cp ../website/static/img/squiggle-logo.png media/vendor/icon.png",
"build:bundle": "esbuild ./src/client/extension.ts ./src/server/server.ts --format=cjs --platform=node --sourcemap --minify --bundle --external:vscode --outdir=./dist",
"build": "yarn run build:vendor && yarn run build:grammar && yarn run build:bundle",
"watch": "yarn run compile:bundle --watch",
"pretest": "yarn run build && yarn run lint",
"lint": "tsc -noEmit && prettier --check .",
"format": "prettier --write .",
"package": "npx vsce package --yarn"
"package": "vsce package --yarn"
},
"devDependencies": {
"@types/glob": "^8.0.0",
"@types/node": "18.x",
"@types/vscode": "^1.70.0",
"esbuild": "^0.15.10",
"glob": "^8.0.3",
"js-yaml": "^4.1.0",
"typescript": "^4.8.4",
"vsce-yarn-patch": "^1.66.2"
"vsce": "^2.11.0"
},
"dependencies": {
"vscode-languageclient": "^8.0.2",
"vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7",
"@quri/squiggle-lang": "^0.2.11"
"@quri/squiggle-lang": "^0.2.11",
"@quri/squiggle-components": "*"
}
}

View File

@ -1,12 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"lib": ["ES2020", "dom"],
"outDir": "out",
"rootDir": "src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"]
}

View File

@ -13,7 +13,7 @@ let client: LanguageClient;
export const startClient = (context: vscode.ExtensionContext) => {
// The server is implemented in node
let serverModule = context.asAbsolutePath(
path.join("server", "out", "server.js")
path.join("dist", "src", "server", "server.js")
);
// The debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging

View File

@ -7,7 +7,6 @@
"rootDir": "src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", ".vscode-test"],
"references": [{ "path": "./client" }, { "path": "./server" }]
"include": ["src/**/*"],
"exclude": ["node_modules", ".vscode-test"]
}

View File

@ -332,7 +332,7 @@ truncateRight: (distribution, right: number) => distribution
**Examples**
```javascript
truncateLeft(normal(5, 2), 6);
truncateRight(normal(5, 2), 6);
```
### klDivergence

View File

@ -0,0 +1,20 @@
---
title: Changelog
---
## 0.5.0
- Performance improvements:
- Interpreter is now 5x-20x faster on code written in Squiggle
- SampleSet to PointSet conversions are 2x faster
- cdf function on SampleSets is 30x faster
- overall speedup is about 2x on average on real code written in Squiggle
- 50% smaller bundle size for [@quri/squiggle-lang](https://www.npmjs.com/package/@quri/squiggle-lang); 20% smaller bundle size for [@quri/squiggle-components](https://www.npmjs.com/package/@quri/squiggle-components).
### Breaking changes
Some rarely used math functions got removed or moved to the `Math` namespace.
For example, `cos(x)` is now `Math.cos(x)`, and `atanh(x)` doesn't exist.
If your code is now failing with `<function> is not defined` for anything from [this list](https://mathjs.org/docs/reference/functions.html), try adding `Math.` prefix first, and then complain on [Github issues](https://github.com/quantified-uncertainty/squiggle/issues).

View File

@ -3,9 +3,11 @@ title: How to import squiggle files into `.mdx` documents
sidebar_position: 5
---
import { SquiggleEditorWithImportedBindings } from "../../src/components/SquiggleEditor";
:::caution Proof of concept
_Proof of concept_
The following usage pattern is currently broken. We expect to bring it back in some form in 0.5.1 or 0.5.2 release.
:::
## Consider the following squiggle file
@ -30,10 +32,3 @@ import { SquiggleEditorWithImportedBindings } from "../../src/components/Squiggl
```
Notice, you need to wrap the export of `@quri/squiggle-components` in custom code for dynamicism, please view `packages/website/src/components/` in github for details.
Which would then look exactly like
<SquiggleEditorWithImportedBindings
defaultCode={"f(z)"}
bindingsImportUrl={"/estimates/demo.squiggle"}
/>

View File

@ -15,7 +15,7 @@
"@docusaurus/core": "2.1.0",
"@docusaurus/preset-classic": "2.1.0",
"@heroicons/react": "^1.0.6",
"@quri/squiggle-components": "^0.5.0",
"@quri/squiggle-components": "*",
"base64-js": "^1.5.1",
"clsx": "^1.2.1",
"hast-util-is-element": "2.1.2",

View File

@ -61,6 +61,11 @@ const sidebars = {
},
],
},
{
type: "doc",
id: "Changelog",
label: "Changelog",
},
],
// But you can create a sidebar manually

View File

@ -1,6 +1,4 @@
{
"buildCommand": "cd ../squiggle-lang && yarn build && cd ../components && yarn build && cd ../website && yarn build",
"framework": "docusaurus-2",
"installCommand": "cd ../../ && yarn",
"ignoreCommand": "git diff --quiet $VERCEL_GIT_PREVIOUS_SHA $VERCEL_GIT_COMMIT_SHA ../squiggle-lang ../components ."
"buildCommand": "cd ../.. && npx turbo run build --filter=squiggle-website",
"framework": "docusaurus-2"
}

39
turbo.json Normal file
View File

@ -0,0 +1,39 @@
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"lint": {
"outputs": []
},
"format": {},
"build": {
"dependsOn": ["^build"]
},
"vscode-squiggle#build": {
"dependsOn": ["^build", "@quri/squiggle-components#bundle"]
},
"@quri/squiggle-components#build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "storybook-static/**"]
},
"@quri/squiggle-lang#build": {
"dependsOn": ["^build"],
"outputs": [
"__tests__/**/*.bs.js",
"benchmark/**/*.bs.js",
"src/rescript/**/*.js",
"src/rescript/**/*.gen.tsx",
"dist/**"
]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"bundle": {
"dependsOn": ["build"]
},
"coverage": {
"dependsOn": ["build"]
}
}
}

1161
yarn.lock

File diff suppressed because it is too large Load Diff