commit
4ecb692e80
87
.github/workflows/ci-cachix.yml
vendored
Normal file
87
.github/workflows/ci-cachix.yml
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
name: Nix build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- reducer-dev
|
||||
- epic-reducer-project
|
||||
|
||||
jobs:
|
||||
flake-lints:
|
||||
name: All lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Check that lang lints
|
||||
run: nix build .#lang-lint
|
||||
- name: Check that components lints
|
||||
run: nix build .#components-lint
|
||||
- name: Check that website lints
|
||||
run: nix build .#docusaurus-lint
|
||||
- name: Check that vscode extension lints
|
||||
run: nix build .#vscode-lint
|
||||
- name: Check that cli lints
|
||||
run: nix build .#cli-lint
|
||||
|
||||
flake-packages:
|
||||
name: Builds, tests, and bundles
|
||||
runs-on: ubuntu-latest
|
||||
needs: flake-lints
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Check all lang tests
|
||||
run: nix build .#lang-test
|
||||
- name: Check that lang bundles
|
||||
run: nix build .#lang-bundle
|
||||
- name: Check that components builds
|
||||
run: nix build .#components
|
||||
- name: Check that components bundles
|
||||
run: nix build .#components-bundle
|
||||
|
||||
flake-devshells:
|
||||
name: Development shell environment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
- name: Build js devshell
|
||||
run: nix develop .#js --profile just-js
|
||||
- name: Build js & wasm devshell
|
||||
run: nix develop --profile full-shell
|
251
.github/workflows/ci.yml
vendored
251
.github/workflows/ci.yml
vendored
|
@ -10,6 +10,7 @@ on:
|
|||
- master
|
||||
- develop
|
||||
- reducer-dev
|
||||
- epic-reducer-project
|
||||
|
||||
jobs:
|
||||
pre_check:
|
||||
|
@ -48,26 +49,26 @@ jobs:
|
|||
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
|
||||
with:
|
||||
dry: true
|
||||
prettier_options: --check packages/squiggle-lang
|
||||
# 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
|
||||
# with:
|
||||
# dry: true
|
||||
# prettier_options: --check packages/squiggle-lang
|
||||
|
||||
lang-build-test-bundle:
|
||||
name: Language build, test, and bundle
|
||||
|
@ -97,95 +98,96 @@ jobs:
|
|||
- 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
|
||||
with:
|
||||
dry: true
|
||||
prettier_options: --check packages/components --ignore-path packages/components/.prettierignore
|
||||
# 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
|
||||
# with:
|
||||
# dry: true
|
||||
# prettier_options: --check packages/components --ignore-path packages/components/.prettierignore
|
||||
#
|
||||
# components-bundle-build:
|
||||
# name: Components bundle and 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') }}
|
||||
# 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
|
||||
|
||||
components-bundle-build:
|
||||
name: Components bundle and 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') }}
|
||||
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
|
||||
|
||||
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: Install dependencies from monorepo level
|
||||
run: cd ../../ && yarn
|
||||
- name: Lint the VSCode Extension source code
|
||||
run: yarn lint
|
||||
# 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
|
||||
|
@ -202,20 +204,19 @@ jobs:
|
|||
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
|
||||
# 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
|
||||
|
|
61
.github/workflows/release-please.yml
vendored
61
.github/workflows/release-please.yml
vendored
|
@ -3,7 +3,7 @@ name: Run Release Please
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
|
||||
jobs:
|
||||
pre_check:
|
||||
|
@ -55,21 +55,22 @@ jobs:
|
|||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/squiggle-lang
|
||||
bump-patch-for-minor-pre-major: true
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
# - name: Publish: Checkout source
|
||||
# uses: actions/checkout@v2
|
||||
# # these if statements ensure that a publication only occurs when
|
||||
# # a new release is created:
|
||||
# if: ${{ steps.release.outputs.release_created }}
|
||||
# - name: Publish: Install dependencies
|
||||
# run: yarn
|
||||
# if: ${{ steps.release.outputs.release_created }}
|
||||
# - name: Publish
|
||||
# run: cd packages/squiggle-lang && yarn publish
|
||||
# env:
|
||||
# NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
# if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish- Checkout source
|
||||
uses: actions/checkout@v3
|
||||
# these if statements ensure that a publication only occurs when
|
||||
# a new release is created:
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish- Install dependencies
|
||||
run: yarn
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish
|
||||
run: cd packages/squiggle-lang && yarn publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
|
||||
relplz-components:
|
||||
name: for components
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -82,20 +83,20 @@ jobs:
|
|||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/components
|
||||
bump-patch-for-minor-pre-major: true
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
# - name: Publish: Checkout source
|
||||
# uses: actions/checkout@v2
|
||||
# # these if statements ensure that a publication only occurs when
|
||||
# # a new release is created:
|
||||
# if: ${{ steps.release.outputs.release_created }}
|
||||
# - name: Publish: Install dependencies
|
||||
# run: yarn
|
||||
# if: ${{ steps.release.outputs.release_created }}
|
||||
# - name: Publish
|
||||
# run: cd packages/components && yarn publish
|
||||
# env:
|
||||
# NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
- name: Publish- Checkout source
|
||||
uses: actions/checkout@v3
|
||||
# these if statements ensure that a publication only occurs when
|
||||
# a new release is created:
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish- Install dependencies
|
||||
run: yarn
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish
|
||||
run: cd packages/components && yarn publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
relplz-website:
|
||||
name: for website
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -108,7 +109,7 @@ jobs:
|
|||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/website
|
||||
bump-patch-for-minor-pre-major: true
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
relplz-vscodeext:
|
||||
name: for vscode-ext
|
||||
|
@ -122,7 +123,7 @@ jobs:
|
|||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/vscode-ext
|
||||
bump-patch-for-minor-pre-major: true
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
relplz-cl:
|
||||
name: for cli
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ yarn-error.log
|
|||
**/.sync.ffs_db
|
||||
.direnv
|
||||
.log
|
||||
result
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
.direnv
|
||||
*.bs.js
|
||||
*.gen.tsx
|
||||
packages/*/dist
|
||||
packages/components/storybook-static
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
packages/website/.docusaurus
|
||||
packages/squiggle-lang/lib
|
||||
packages/squiggle-lang/.nyc_output/
|
||||
packages/squiggle-lang/coverage/
|
||||
packages/squiggle-lang/.cache/
|
||||
packages/website/build/
|
||||
packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
||||
packages/vscode-ext/media/vendor/
|
||||
packages/squiggle-lang/.nyc_output/
|
||||
packages/*/dist
|
||||
result
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"packages/cli": "0.0.3",
|
||||
"packages/components": "0.2.24",
|
||||
"packages/squiggle-lang": "0.2.11",
|
||||
"packages/components": "0.3.1",
|
||||
"packages/squiggle-lang": "0.3.0",
|
||||
"packages/vscode-ext": "0.3.1",
|
||||
"packages/website": "0.2.1"
|
||||
"packages/website": "0.3.0"
|
||||
}
|
||||
|
|
79
flake.lock
Normal file
79
flake.lock
Normal file
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gentype": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1661855866,
|
||||
"narHash": "sha256-+q0OOTyaq8eOn9BOWdPOCtSDOISW4A59v3mq3JOZyug=",
|
||||
"owner": "rescript-association",
|
||||
"repo": "genType",
|
||||
"rev": "6b5f164b4f6ced456019b7579a0ab7e0a86518ad",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rescript-association",
|
||||
"repo": "genType",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1661617163,
|
||||
"narHash": "sha256-NN9Ky47j8ohgPhA9JZyfkYIbbAo6RJkGz+7h8/exVpE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0ba2543f8c855d7be8e90ef6c8dc89c1617e8a08",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-22.05",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"gentype": "gentype",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
99
flake.nix
Normal file
99
flake.nix
Normal file
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
description = "Squiggle packages";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-22.05";
|
||||
gentype = {
|
||||
url = "github:rescript-association/genType";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, gentype, flake-utils }:
|
||||
let
|
||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||
overlays = [
|
||||
(final: prev: {
|
||||
# set the node version here
|
||||
nodejs = prev.nodejs-18_x;
|
||||
# The override is the only way to get it into mkYarnModules
|
||||
})
|
||||
];
|
||||
|
||||
commonFn = pkgs: {
|
||||
buildInputs = with pkgs; [ nodejs yarn ];
|
||||
prettier = with pkgs.nodePackages; [ prettier ];
|
||||
which = [ pkgs.which ];
|
||||
};
|
||||
gentypeOutputFn = pkgs: gentype.outputs.packages.${pkgs.system}.default;
|
||||
langFn = { pkgs, ... }:
|
||||
# Probably doesn't work on i686-linux
|
||||
import ./nix/squiggle-lang.nix {
|
||||
inherit pkgs commonFn gentypeOutputFn;
|
||||
};
|
||||
componentsFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-components.nix { inherit pkgs commonFn langFn; };
|
||||
websiteFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-website.nix {
|
||||
inherit pkgs commonFn langFn componentsFn;
|
||||
};
|
||||
vscodeextFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-vscode.nix {
|
||||
inherit pkgs commonFn langFn componentsFn;
|
||||
};
|
||||
cliFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-cli.nix {
|
||||
inherit pkgs commonFn;
|
||||
};
|
||||
|
||||
# local machines
|
||||
localFlakeOutputs = { pkgs, ... }:
|
||||
let
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
website = websiteFn pkgs;
|
||||
vscodeext = vscodeextFn pkgs;
|
||||
cli = cliFn pkgs;
|
||||
in {
|
||||
# validating
|
||||
checks = flake-utils.lib.flattenTree {
|
||||
lang-lint = lang.lint;
|
||||
lang-test = lang.test;
|
||||
components-lint = components.lint;
|
||||
docusaurus-lint = website.lint;
|
||||
cli-lint = cli.lint;
|
||||
};
|
||||
# building
|
||||
packages = flake-utils.lib.flattenTree {
|
||||
default = components.build;
|
||||
lang = lang.build;
|
||||
lang-bundle = lang.bundle;
|
||||
lang-test = lang.test;
|
||||
components = components.build;
|
||||
components-bundle = components.bundle;
|
||||
|
||||
# Lint
|
||||
lang-lint = lang.lint;
|
||||
components-lint = components.lint;
|
||||
docusaurus-lint = website.lint;
|
||||
vscode-lint = vscodeext.lint;
|
||||
cli-lint = cli.lint;
|
||||
};
|
||||
|
||||
# developing
|
||||
devShells = let shellNix = import ./nix/shell.nix { inherit pkgs; };
|
||||
in flake-utils.lib.flattenTree {
|
||||
default = shellNix.all;
|
||||
js = shellNix.just-js;
|
||||
};
|
||||
};
|
||||
in flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = overlays;
|
||||
};
|
||||
|
||||
in localFlakeOutputs pkgs);
|
||||
}
|
1
nix/README.md
Normal file
1
nix/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Visit `quantified-uncertainty.cachix.org` for information about how to add our binary cache to your local dev environment.
|
25
nix/shell.nix
Normal file
25
nix/shell.nix
Normal file
|
@ -0,0 +1,25 @@
|
|||
{ pkgs }:
|
||||
with pkgs;
|
||||
let
|
||||
js = [ yarn nodejs nodePackages.ts-node ];
|
||||
rust = [
|
||||
wasm-pack
|
||||
cargo
|
||||
rustup
|
||||
pkg-config
|
||||
libressl
|
||||
rustfmt
|
||||
wasmtime
|
||||
binaryen
|
||||
wasm-bindgen-cli
|
||||
];
|
||||
in {
|
||||
all = mkShell {
|
||||
name = "squiggle_yarn-wasm-devshell";
|
||||
buildInputs = builtins.concatLists [ js rust [ nixfmt ] ];
|
||||
};
|
||||
just-js = mkShell {
|
||||
name = "squiggle_yarn-devshell";
|
||||
buildInputs = js ++ [ nixfmt ];
|
||||
};
|
||||
}
|
13
nix/squiggle-cli.nix
Normal file
13
nix/squiggle-cli.nix
Normal file
|
@ -0,0 +1,13 @@
|
|||
{ pkgs, commonFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-cli-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src = ../packages/cli;
|
||||
buildPhase = "prettier --check .";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
75
nix/squiggle-components.nix
Normal file
75
nix/squiggle-components.nix
Normal file
|
@ -0,0 +1,75 @@
|
|||
{ pkgs, commonFn, langFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
componentsPackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/components/package.json;
|
||||
modified =
|
||||
pkgs.lib.recursiveUpdate raw { dependencies.react-dom = "^18.2.0"; };
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/components/patched-package.json"
|
||||
packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-components_yarnsource";
|
||||
buildInputs = common.buildInputs;
|
||||
src = ../packages/components;
|
||||
packageJSON = componentsPackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-lint";
|
||||
src = ../packages/components;
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
buildPhase = "yarn lint";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
build = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-build";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-components";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
cp -r node_modules/@quri/squiggle-lang deps/@quri
|
||||
pushd deps/@quri/squiggle-components
|
||||
|
||||
yarn --offline build:cjs
|
||||
yarn --offline build:css
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-components/node_modules deps/@quri/squiggle-components/NODE_MODULES
|
||||
mv node_modules deps/@quri/squiggle-components
|
||||
|
||||
# patching .gitignore so flake keeps build artefacts
|
||||
sed -i /dist/d deps/@quri/squiggle-components/.gitignore
|
||||
cp -r deps/@quri/squiggle-components/. $out
|
||||
'';
|
||||
};
|
||||
bundle = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-bundle";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-components";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
cp -r node_modules/@quri/squiggle-lang deps/@quri
|
||||
pushd deps/@quri/squiggle-components
|
||||
|
||||
yarn --offline bundle
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-components/node_modules deps/@quri/squiggle-components/NODE_MODULES
|
||||
mv node_modules deps/@quri/squiggle-components
|
||||
|
||||
# patching .gitignore so flake keeps build artefacts
|
||||
sed -i /dist/d deps/@quri/squiggle-components/.gitignore
|
||||
cp -r deps/@quri/squiggle-components/. $out
|
||||
'';
|
||||
};
|
||||
}
|
125
nix/squiggle-lang.nix
Normal file
125
nix/squiggle-lang.nix
Normal file
|
@ -0,0 +1,125 @@
|
|||
{ pkgs, commonFn, gentypeOutputFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
langPackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/squiggle-lang/package.json;
|
||||
modified = pkgs.lib.recursiveUpdate raw {
|
||||
devDependencies."@types/lodash" = "^4.14.167";
|
||||
};
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/squiggle-lang/patched-package.json"
|
||||
packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-lang_yarnsource";
|
||||
src = ../packages/squiggle-lang;
|
||||
packageJSON = langPackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
pkgConfig = {
|
||||
rescript = {
|
||||
buildInputs = common.which
|
||||
++ (if pkgs.system != "i686-linux" then [ pkgs.gcc_multi ] else [ ]);
|
||||
postInstall = ''
|
||||
echo "PATCHELF'ING RESCRIPT EXECUTABLES (INCL NINJA)"
|
||||
# Patching interpreter for linux/*.exe's
|
||||
THE_LD=$(patchelf --print-interpreter $(which mkdir))
|
||||
patchelf --set-interpreter $THE_LD linux/*.exe && echo "- patched interpreter for linux/*.exe's"
|
||||
|
||||
# Replacing needed shared library for linux/ninja.exe
|
||||
THE_SO=$(find /nix/store/*/lib64 -name libstdc++.so.6 | head -n 1)
|
||||
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
|
||||
cp ${gentypeOutputFn pkgs}/src/GenType.exe gentype.exe
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-lint";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-lang/deps/@quri/squiggle-lang";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
buildPhase = ''
|
||||
yarn lint:prettier
|
||||
yarn lint:rescript
|
||||
'';
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
build = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-build";
|
||||
# `peggy` is in the `node_modules` that's adjacent to `deps`.
|
||||
src = yarn-source + "/libexec/@quri/squiggle-lang";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
# so that the path to ppx doesn't need to be patched.
|
||||
mv node_modules deps
|
||||
|
||||
pushd deps/@quri/squiggle-lang
|
||||
yarn --offline build:peggy
|
||||
yarn --offline build:rescript
|
||||
yarn --offline build:typescript
|
||||
|
||||
# custom gitignore so that the flake keeps build artefacts
|
||||
mv .gitignore GITIGNORE
|
||||
sed -i /Reducer_Peggy_GeneratedParser.js/d GITIGNORE
|
||||
sed -i /\*.bs.js/d GITIGNORE
|
||||
sed -i /\*.gen.ts/d GITIGNORE
|
||||
sed -i /\*.gen.tsx/d GITIGNORE
|
||||
sed -i /\*.gen.js/d GITIGNORE
|
||||
sed -i /helpers.js/d GITIGNORE
|
||||
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
# mkdir -p $out/node_modules
|
||||
mv deps/@quri/squiggle-lang/GITIGNORE deps/@quri/squiggle-lang/.gitignore
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-lang/node_modules deps/@quri/squiggle-lang/NODE_MODULES
|
||||
mv deps/node_modules deps/@quri/squiggle-lang
|
||||
|
||||
# the proper install phase
|
||||
cp -r deps/@quri/squiggle-lang/. $out
|
||||
'';
|
||||
};
|
||||
test = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-test";
|
||||
src = build;
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
yarn --offline test
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r . $out
|
||||
'';
|
||||
};
|
||||
bundle = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-bundle";
|
||||
src = test;
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
yarn --offline bundle
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r dist $out
|
||||
cp *.json $out/dist
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
24
nix/squiggle-vscode.nix
Normal file
24
nix/squiggle-vscode.nix
Normal file
|
@ -0,0 +1,24 @@
|
|||
{ pkgs, commonFn, langFn, componentsFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-vscodeext_yarnsource";
|
||||
src = ../packages/vscode-ext;
|
||||
packageJson = ../packages/vscode-ext/package.json;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
packageResolutions."@quri/squiggle-components" = components.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-vscode-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src =
|
||||
../packages/vscode-ext; # yarn-source + "/libexec/vscode-squiggle/deps/vscode-squiggle";
|
||||
buildPhase = "prettier --check .";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
30
nix/squiggle-website.nix
Normal file
30
nix/squiggle-website.nix
Normal file
|
@ -0,0 +1,30 @@
|
|||
{ pkgs, commonFn, langFn, componentsFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
websitePackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/website/package.json;
|
||||
modified = pkgs.lib.recursiveUpdate raw {
|
||||
dependencies.postcss-import = "^14.1.0";
|
||||
dependencies.tailwindcss = "^3.1.8";
|
||||
};
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/website/patched-package.json" packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-website_yarnsource";
|
||||
src = ../packages/website;
|
||||
packageJSON = websitePackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
packageResolutions."@quri/squiggle-components" = components.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-website-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src = ../packages/website;
|
||||
buildPhase = "yarn lint";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
8
nixos.sh
8
nixos.sh
|
@ -5,14 +5,14 @@
|
|||
# We need to patchelf rescript executables. https://github.com/NixOS/nixpkgs/issues/107375
|
||||
set -x
|
||||
|
||||
fhsShellName="squiggle-development"
|
||||
fhsShellDotNix="{pkgs ? import <nixpkgs> {} }: (pkgs.buildFHSUserEnv { name = \"${fhsShellName}\"; targetPkgs = pkgs: [pkgs.yarn]; runScript = \"yarn\"; }).env"
|
||||
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_moduels/bisect_ppx/bisect-ppx-report
|
||||
theSo=$(find /nix/store/*$fhsShellName*/lib64 -name libstdc++.so.6 | grep $fhsShellName | head -n 1)
|
||||
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
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
{
|
||||
"name": "@quri/squiggle-components",
|
||||
"version": "0.2.24",
|
||||
"version": "0.3.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^1.0.0",
|
||||
"@floating-ui/react-dom-interactions": "^0.9.1",
|
||||
"@floating-ui/react-dom-interactions": "^0.9.3",
|
||||
"@headlessui/react": "^1.6.6",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@hookform/resolvers": "^2.9.7",
|
||||
"@quri/squiggle-lang": "^0.2.8",
|
||||
"@quri/squiggle-lang": "^0.3.0",
|
||||
"@react-hook/size": "^2.1.2",
|
||||
"clsx": "^1.2.1",
|
||||
"framer-motion": "^7.0.0",
|
||||
"framer-motion": "^7.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.1.0",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-hook-form": "^7.34.0",
|
||||
"react-hook-form": "^7.34.2",
|
||||
"react-use": "^17.4.0",
|
||||
"react-vega": "^7.6.0",
|
||||
"vega": "^5.22.1",
|
||||
"vega-embed": "^6.21.0",
|
||||
"vega-lite": "^5.4.0",
|
||||
"vega-lite": "^5.5.0",
|
||||
"vscode-uri": "^3.0.3",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
|
@ -36,12 +36,12 @@
|
|||
"@storybook/react": "^6.5.10",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/user-event": "^14.4.2",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^27.5.0",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "^18.6.4",
|
||||
"@types/lodash": "^4.14.184",
|
||||
"@types/node": "^18.7.13",
|
||||
"@types/react": "^18.0.9",
|
||||
"@types/styled-components": "^5.1.24",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
|
@ -54,11 +54,11 @@
|
|||
"tailwindcss": "^3.1.8",
|
||||
"ts-loader": "^9.3.0",
|
||||
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
||||
"typescript": "^4.7.4",
|
||||
"web-vitals": "^2.1.4",
|
||||
"typescript": "^4.8.2",
|
||||
"web-vitals": "^3.0.0",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.9.3"
|
||||
"webpack-dev-server": "^4.10.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18",
|
||||
|
|
|
@ -4,6 +4,8 @@ import {
|
|||
result,
|
||||
distributionError,
|
||||
distributionErrorToString,
|
||||
squiggleExpression,
|
||||
resultMap,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { Vega } from "react-vega";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
|
@ -14,6 +16,8 @@ import {
|
|||
DistributionChartSpecOptions,
|
||||
} from "../lib/distributionSpecBuilder";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { Plot, parsePlot } from "../lib/plotParser";
|
||||
import { flattenResult } from "../lib/utility";
|
||||
import { hasMassBelowZero } from "../lib/distributionUtils";
|
||||
|
||||
export type DistributionPlottingSettings = {
|
||||
|
@ -23,26 +27,41 @@ export type DistributionPlottingSettings = {
|
|||
} & DistributionChartSpecOptions;
|
||||
|
||||
export type DistributionChartProps = {
|
||||
distribution: Distribution;
|
||||
plot: Plot;
|
||||
width?: number;
|
||||
height: number;
|
||||
} & DistributionPlottingSettings;
|
||||
|
||||
export function defaultPlot(distribution: Distribution): Plot {
|
||||
return { distributions: [{ name: "default", distribution }] };
|
||||
}
|
||||
|
||||
export function makePlot(record: {
|
||||
[key: string]: squiggleExpression;
|
||||
}): Plot | void {
|
||||
const plotResult = parsePlot(record);
|
||||
if (plotResult.tag === "Ok") {
|
||||
return plotResult.value;
|
||||
}
|
||||
}
|
||||
|
||||
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||
const {
|
||||
distribution,
|
||||
height,
|
||||
showSummary,
|
||||
width,
|
||||
logX,
|
||||
actions = false,
|
||||
} = props;
|
||||
const shape = distribution.pointSet();
|
||||
const { plot, height, showSummary, width, logX, actions = false } = props;
|
||||
const [sized] = useSize((size) => {
|
||||
if (shape.tag === "Error") {
|
||||
let shapes = flattenResult(
|
||||
plot.distributions.map((x) =>
|
||||
resultMap(x.distribution.pointSet(), (shape) => ({
|
||||
name: x.name,
|
||||
// color: x.color, // not supported yet
|
||||
continuous: shape.continuous,
|
||||
discrete: shape.discrete,
|
||||
}))
|
||||
)
|
||||
);
|
||||
if (shapes.tag === "Error") {
|
||||
return (
|
||||
<ErrorAlert heading="Distribution Error">
|
||||
{distributionErrorToString(shape.value)}
|
||||
{distributionErrorToString(shapes.value)}
|
||||
</ErrorAlert>
|
||||
);
|
||||
}
|
||||
|
@ -56,24 +75,29 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
|||
);
|
||||
widthProp = 20;
|
||||
}
|
||||
const domain = shapes.value.flatMap((shape) =>
|
||||
shape.discrete.concat(shape.continuous)
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ width: widthProp }}>
|
||||
{logX && hasMassBelowZero(shape.value) ? (
|
||||
{logX && shapes.value.some(hasMassBelowZero) ? (
|
||||
<ErrorAlert heading="Log Domain Error">
|
||||
Cannot graph distribution with negative values on logarithmic scale.
|
||||
</ErrorAlert>
|
||||
) : (
|
||||
<Vega
|
||||
spec={spec}
|
||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||
data={{ data: shapes.value, domain }}
|
||||
width={widthProp - 10}
|
||||
height={height}
|
||||
actions={actions}
|
||||
/>
|
||||
)}
|
||||
<div className="flex justify-center">
|
||||
{showSummary && <SummaryTable distribution={distribution} />}
|
||||
{showSummary && plot.distributions.length === 1 && (
|
||||
<SummaryTable distribution={plot.distributions[0].distribution} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
|||
import {
|
||||
DistributionChart,
|
||||
DistributionPlottingSettings,
|
||||
defaultPlot,
|
||||
} from "./DistributionChart";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
|
@ -179,7 +180,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
|||
let showChart =
|
||||
mouseItem.tag === "Ok" && mouseItem.value.tag === "distribution" ? (
|
||||
<DistributionChart
|
||||
distribution={mouseItem.value.value}
|
||||
plot={defaultPlot(mouseItem.value.value)}
|
||||
width={400}
|
||||
height={50}
|
||||
{...distributionPlotSettings}
|
||||
|
|
|
@ -37,10 +37,7 @@ import { InputItem } from "./ui/InputItem";
|
|||
import { Text } from "./ui/Text";
|
||||
import { ViewSettings, viewSettingsSchema } from "./ViewSettings";
|
||||
import { HeadedSection } from "./ui/HeadedSection";
|
||||
import {
|
||||
defaultColor,
|
||||
defaultTickFormat,
|
||||
} from "../lib/distributionSpecBuilder";
|
||||
import { defaultTickFormat } from "../lib/distributionSpecBuilder";
|
||||
import { Button } from "./ui/Button";
|
||||
|
||||
type PlaygroundProps = SquiggleChartProps & {
|
||||
|
@ -234,13 +231,12 @@ export const PlaygroundContext = React.createContext<PlaygroundContextShape>({
|
|||
export const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||
defaultCode = "",
|
||||
height = 500,
|
||||
showSummary = false,
|
||||
showSummary = true,
|
||||
logX = false,
|
||||
expY = false,
|
||||
title,
|
||||
minX,
|
||||
maxX,
|
||||
color = defaultColor,
|
||||
tickFormat = defaultTickFormat,
|
||||
distributionChartActions,
|
||||
code: controlledCode,
|
||||
|
@ -268,7 +264,6 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
|||
title,
|
||||
minX,
|
||||
maxX,
|
||||
color,
|
||||
tickFormat,
|
||||
distributionChartActions,
|
||||
showSummary,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { squiggleExpression, declaration } from "@quri/squiggle-lang";
|
||||
import { NumberShower } from "../NumberShower";
|
||||
import { DistributionChart } from "../DistributionChart";
|
||||
import { DistributionChart, defaultPlot, makePlot } from "../DistributionChart";
|
||||
import { FunctionChart, FunctionChartSettings } from "../FunctionChart";
|
||||
import clsx from "clsx";
|
||||
import { VariableBox } from "./VariableBox";
|
||||
|
@ -102,7 +102,7 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
{(settings) => {
|
||||
return (
|
||||
<DistributionChart
|
||||
distribution={expression.value}
|
||||
plot={defaultPlot(expression.value)}
|
||||
{...settings.distributionPlotSettings}
|
||||
height={settings.height}
|
||||
width={width}
|
||||
|
@ -241,9 +241,9 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
case "module": {
|
||||
return (
|
||||
<VariableList path={path} heading="Module">
|
||||
{(settings) =>
|
||||
{(_) =>
|
||||
Object.entries(expression.value)
|
||||
.filter(([key, r]) => !key.match(/^(Math|System)\./))
|
||||
.filter(([key, _]) => !key.match(/^(Math|System)\./))
|
||||
.map(([key, r]) => (
|
||||
<ExpressionViewer
|
||||
key={key}
|
||||
|
@ -257,9 +257,45 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
);
|
||||
}
|
||||
case "record":
|
||||
const plot = makePlot(expression.value);
|
||||
if (plot) {
|
||||
return (
|
||||
<VariableBox
|
||||
path={path}
|
||||
heading={"Plot"}
|
||||
renderSettingsMenu={({ onChange }) => {
|
||||
let disableLogX = plot.distributions.some((x) => {
|
||||
let pointSet = x.distribution.pointSet();
|
||||
return (
|
||||
pointSet.tag === "Ok" && hasMassBelowZero(pointSet.value)
|
||||
);
|
||||
});
|
||||
return (
|
||||
<ItemSettingsMenu
|
||||
path={path}
|
||||
onChange={onChange}
|
||||
disableLogX={disableLogX}
|
||||
withFunctionSettings={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(settings) => {
|
||||
return (
|
||||
<DistributionChart
|
||||
plot={plot}
|
||||
{...settings.distributionPlotSettings}
|
||||
height={settings.height}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</VariableBox>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<VariableList path={path} heading="Record">
|
||||
{(settings) =>
|
||||
{(_) =>
|
||||
Object.entries(expression.value).map(([key, r]) => (
|
||||
<ExpressionViewer
|
||||
key={key}
|
||||
|
@ -271,10 +307,11 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
}
|
||||
</VariableList>
|
||||
);
|
||||
}
|
||||
case "array":
|
||||
return (
|
||||
<VariableList path={path} heading="Array">
|
||||
{(settings) =>
|
||||
{(_) =>
|
||||
expression.value.map((r, i) => (
|
||||
<ExpressionViewer
|
||||
key={i}
|
||||
|
|
|
@ -6,10 +6,7 @@ import { Modal } from "../ui/Modal";
|
|||
import { ViewSettings, viewSettingsSchema } from "../ViewSettings";
|
||||
import { Path, pathAsString } from "./utils";
|
||||
import { ViewerContext } from "./ViewerContext";
|
||||
import {
|
||||
defaultColor,
|
||||
defaultTickFormat,
|
||||
} from "../../lib/distributionSpecBuilder";
|
||||
import { defaultTickFormat } from "../../lib/distributionSpecBuilder";
|
||||
import { PlaygroundContext } from "../SquigglePlayground";
|
||||
|
||||
type Props = {
|
||||
|
@ -46,7 +43,6 @@ const ItemSettingsModal: React.FC<
|
|||
tickFormat:
|
||||
mergedSettings.distributionPlotSettings.format || defaultTickFormat,
|
||||
title: mergedSettings.distributionPlotSettings.title,
|
||||
color: mergedSettings.distributionPlotSettings.color || defaultColor,
|
||||
minX: mergedSettings.distributionPlotSettings.minX,
|
||||
maxX: mergedSettings.distributionPlotSettings.maxX,
|
||||
distributionChartActions: mergedSettings.distributionPlotSettings.actions,
|
||||
|
@ -66,7 +62,6 @@ const ItemSettingsModal: React.FC<
|
|||
expY: vars.expY,
|
||||
format: vars.tickFormat,
|
||||
title: vars.title,
|
||||
color: vars.color,
|
||||
minX: vars.minX,
|
||||
maxX: vars.maxX,
|
||||
actions: vars.distributionChartActions,
|
||||
|
|
|
@ -5,10 +5,7 @@ import { InputItem } from "./ui/InputItem";
|
|||
import { Checkbox } from "./ui/Checkbox";
|
||||
import { HeadedSection } from "./ui/HeadedSection";
|
||||
import { Text } from "./ui/Text";
|
||||
import {
|
||||
defaultColor,
|
||||
defaultTickFormat,
|
||||
} from "../lib/distributionSpecBuilder";
|
||||
import { defaultTickFormat } from "../lib/distributionSpecBuilder";
|
||||
|
||||
export const viewSettingsSchema = yup.object({}).shape({
|
||||
chartHeight: yup.number().required().positive().integer().default(350),
|
||||
|
@ -18,7 +15,6 @@ export const viewSettingsSchema = yup.object({}).shape({
|
|||
expY: yup.boolean().required(),
|
||||
tickFormat: yup.string().default(defaultTickFormat),
|
||||
title: yup.string(),
|
||||
color: yup.string().default(defaultColor).required(),
|
||||
minX: yup.number(),
|
||||
maxX: yup.number(),
|
||||
distributionChartActions: yup.boolean(),
|
||||
|
@ -114,12 +110,6 @@ export const ViewSettings: React.FC<{
|
|||
register={register}
|
||||
label="Tick Format"
|
||||
/>
|
||||
<InputItem
|
||||
name="color"
|
||||
type="color"
|
||||
register={register}
|
||||
label="Color"
|
||||
/>
|
||||
</div>
|
||||
</HeadedSection>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import { Path, UseFormRegister } from "react-hook-form";
|
||||
import { Path, UseFormRegister, FieldValues } from "react-hook-form";
|
||||
|
||||
export function Checkbox<T>({
|
||||
export function Checkbox<T extends FieldValues>({
|
||||
name,
|
||||
label,
|
||||
register,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Path, UseFormRegister } from "react-hook-form";
|
||||
import { Path, UseFormRegister, FieldValues } from "react-hook-form";
|
||||
|
||||
export function InputItem<T>({
|
||||
export function InputItem<T extends FieldValues>({
|
||||
name,
|
||||
label,
|
||||
type,
|
||||
|
|
|
@ -10,8 +10,6 @@ export type DistributionChartSpecOptions = {
|
|||
minX?: number;
|
||||
/** The maximum x coordinate shown on the chart */
|
||||
maxX?: number;
|
||||
/** The color of the chart */
|
||||
color?: string;
|
||||
/** The title of the chart */
|
||||
title?: string;
|
||||
/** The formatting of the ticks */
|
||||
|
@ -25,36 +23,14 @@ export let linearXScale: LinearScale = {
|
|||
range: "width",
|
||||
zero: false,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
domain: { data: "domain", field: "x" },
|
||||
};
|
||||
export let linearYScale: LinearScale = {
|
||||
name: "yscale",
|
||||
type: "linear",
|
||||
range: "height",
|
||||
zero: true,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
domain: { data: "domain", field: "y" },
|
||||
};
|
||||
|
||||
export let logXScale: LogScale = {
|
||||
|
@ -65,18 +41,7 @@ export let logXScale: LogScale = {
|
|||
base: 10,
|
||||
nice: false,
|
||||
clamp: true,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
domain: { data: "domain", field: "x" },
|
||||
};
|
||||
|
||||
export let expYScale: PowScale = {
|
||||
|
@ -86,29 +51,16 @@ export let expYScale: PowScale = {
|
|||
range: "height",
|
||||
zero: true,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
domain: { data: "domain", field: "y" },
|
||||
};
|
||||
|
||||
export const defaultTickFormat = ".9~s";
|
||||
export const defaultColor = "#739ECC";
|
||||
|
||||
export function buildVegaSpec(
|
||||
specOptions: DistributionChartSpecOptions
|
||||
): VisualizationSpec {
|
||||
let {
|
||||
const {
|
||||
format = defaultTickFormat,
|
||||
color = defaultColor,
|
||||
title,
|
||||
minX,
|
||||
maxX,
|
||||
|
@ -127,20 +79,32 @@ export function buildVegaSpec(
|
|||
|
||||
let spec: VisualizationSpec = {
|
||||
$schema: "https://vega.github.io/schema/vega/v5.json",
|
||||
description: "A basic area chart example",
|
||||
description: "Squiggle plot chart",
|
||||
width: 500,
|
||||
height: 100,
|
||||
padding: 5,
|
||||
data: [
|
||||
{
|
||||
name: "con",
|
||||
name: "data",
|
||||
},
|
||||
{
|
||||
name: "dis",
|
||||
name: "domain",
|
||||
},
|
||||
],
|
||||
signals: [],
|
||||
scales: [xScale, expY ? expYScale : linearYScale],
|
||||
scales: [
|
||||
xScale,
|
||||
expY ? expYScale : linearYScale,
|
||||
{
|
||||
name: "color",
|
||||
type: "ordinal",
|
||||
domain: {
|
||||
data: "data",
|
||||
field: "name",
|
||||
},
|
||||
range: { scheme: "blues" },
|
||||
},
|
||||
],
|
||||
axes: [
|
||||
{
|
||||
orient: "bottom",
|
||||
|
@ -152,13 +116,40 @@ export function buildVegaSpec(
|
|||
domainOpacity: 0.0,
|
||||
format: format,
|
||||
tickCount: 10,
|
||||
labelOverlap: "greedy",
|
||||
},
|
||||
],
|
||||
marks: [
|
||||
{
|
||||
name: "all_distributions",
|
||||
type: "group",
|
||||
from: {
|
||||
facet: {
|
||||
name: "distribution_facet",
|
||||
data: "data",
|
||||
groupby: ["name"],
|
||||
},
|
||||
},
|
||||
marks: [
|
||||
{
|
||||
name: "continuous_distribution",
|
||||
type: "group",
|
||||
from: {
|
||||
facet: {
|
||||
name: "continuous_facet",
|
||||
data: "distribution_facet",
|
||||
field: "continuous",
|
||||
},
|
||||
},
|
||||
encode: {
|
||||
update: {},
|
||||
},
|
||||
marks: [
|
||||
{
|
||||
name: "continuous_area",
|
||||
type: "area",
|
||||
from: {
|
||||
data: "con",
|
||||
data: "continuous_facet",
|
||||
},
|
||||
encode: {
|
||||
update: {
|
||||
|
@ -171,23 +162,37 @@ export function buildVegaSpec(
|
|||
scale: "yscale",
|
||||
field: "y",
|
||||
},
|
||||
fill: {
|
||||
scale: "color",
|
||||
field: { parent: "name" },
|
||||
},
|
||||
y2: {
|
||||
scale: "yscale",
|
||||
value: 0,
|
||||
},
|
||||
fill: {
|
||||
value: color,
|
||||
},
|
||||
fillOpacity: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "discrete_distribution",
|
||||
type: "group",
|
||||
from: {
|
||||
facet: {
|
||||
name: "discrete_facet",
|
||||
data: "distribution_facet",
|
||||
field: "discrete",
|
||||
},
|
||||
},
|
||||
marks: [
|
||||
{
|
||||
type: "rect",
|
||||
from: {
|
||||
data: "dis",
|
||||
data: "discrete_facet",
|
||||
},
|
||||
encode: {
|
||||
enter: {
|
||||
|
@ -209,7 +214,8 @@ export function buildVegaSpec(
|
|||
value: 0,
|
||||
},
|
||||
fill: {
|
||||
value: "#2f65a7",
|
||||
scale: "color",
|
||||
field: { parent: "name" },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -217,7 +223,7 @@ export function buildVegaSpec(
|
|||
{
|
||||
type: "symbol",
|
||||
from: {
|
||||
data: "dis",
|
||||
data: "discrete_facet",
|
||||
},
|
||||
encode: {
|
||||
enter: {
|
||||
|
@ -239,21 +245,49 @@ export function buildVegaSpec(
|
|||
field: "y",
|
||||
},
|
||||
fill: {
|
||||
value: "#1e4577",
|
||||
scale: "color",
|
||||
field: { parent: "name" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
if (title) {
|
||||
spec = {
|
||||
...spec,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
legends: [
|
||||
{
|
||||
fill: "color",
|
||||
orient: "top",
|
||||
labelFontSize: 12,
|
||||
encode: {
|
||||
symbols: {
|
||||
update: {
|
||||
fill: [
|
||||
{ test: "length(domain('color')) == 1", value: "transparent" },
|
||||
{ scale: "color", field: "value" },
|
||||
],
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
interactive: true,
|
||||
update: {
|
||||
fill: [
|
||||
{ test: "length(domain('color')) == 1", value: "transparent" },
|
||||
{ value: "black" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
...(title && {
|
||||
title: {
|
||||
text: title,
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
|
72
packages/components/src/lib/plotParser.ts
Normal file
72
packages/components/src/lib/plotParser.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import * as yup from "yup";
|
||||
import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang";
|
||||
|
||||
export type LabeledDistribution = {
|
||||
name: string;
|
||||
distribution: Distribution;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
export type Plot = {
|
||||
distributions: LabeledDistribution[];
|
||||
};
|
||||
|
||||
function error<a, b>(err: b): result<a, b> {
|
||||
return { tag: "Error", value: err };
|
||||
}
|
||||
|
||||
function ok<a, b>(x: a): result<a, b> {
|
||||
return { tag: "Ok", value: x };
|
||||
}
|
||||
|
||||
const schema = yup
|
||||
.object()
|
||||
.strict()
|
||||
.noUnknown()
|
||||
.shape({
|
||||
distributions: yup.object().shape({
|
||||
tag: yup.mixed().oneOf(["array"]),
|
||||
value: yup
|
||||
.array()
|
||||
.of(
|
||||
yup.object().shape({
|
||||
tag: yup.mixed().oneOf(["record"]),
|
||||
value: yup.object({
|
||||
name: yup.object().shape({
|
||||
tag: yup.mixed().oneOf(["string"]),
|
||||
value: yup.string().required(),
|
||||
}),
|
||||
// color: yup
|
||||
// .object({
|
||||
// tag: yup.mixed().oneOf(["string"]),
|
||||
// value: yup.string().required(),
|
||||
// })
|
||||
// .default(undefined),
|
||||
distribution: yup.object({
|
||||
tag: yup.mixed().oneOf(["distribution"]),
|
||||
value: yup.mixed(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.required(),
|
||||
}),
|
||||
});
|
||||
|
||||
export function parsePlot(record: {
|
||||
[key: string]: squiggleExpression;
|
||||
}): result<Plot, string> {
|
||||
try {
|
||||
const plotRecord = schema.validateSync(record);
|
||||
return ok({
|
||||
distributions: plotRecord.distributions.value.map((x) => ({
|
||||
name: x.value.name.value,
|
||||
// color: x.value.color?.value, // not supported yet
|
||||
distribution: x.value.distribution.value,
|
||||
})),
|
||||
});
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : "Unknown error";
|
||||
return error(message);
|
||||
}
|
||||
}
|
37
packages/components/src/lib/utility.ts
Normal file
37
packages/components/src/lib/utility.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { result } from "@quri/squiggle-lang";
|
||||
|
||||
export function flattenResult<a, b>(x: result<a, b>[]): result<a[], b> {
|
||||
if (x.length === 0) {
|
||||
return { tag: "Ok", value: [] };
|
||||
} else {
|
||||
if (x[0].tag === "Error") {
|
||||
return x[0];
|
||||
} else {
|
||||
let rest = flattenResult(x.splice(1));
|
||||
if (rest.tag === "Error") {
|
||||
return rest;
|
||||
} else {
|
||||
return { tag: "Ok", value: [x[0].value].concat(rest.value) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function resultBind<a, b, c>(
|
||||
x: result<a, b>,
|
||||
fn: (y: a) => result<c, b>
|
||||
): result<c, b> {
|
||||
if (x.tag === "Ok") {
|
||||
return fn(x.value);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
export function all(arr: boolean[]): boolean {
|
||||
return arr.reduce((x, y) => x && y, true);
|
||||
}
|
||||
|
||||
export function some(arr: boolean[]): boolean {
|
||||
return arr.reduce((x, y) => x || y, false);
|
||||
}
|
|
@ -93,6 +93,33 @@ could be continuous, discrete or mixed.
|
|||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Multiple plots
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Multiple plots"
|
||||
args={{
|
||||
code: `
|
||||
{
|
||||
distributions: [
|
||||
{
|
||||
name: "one",
|
||||
distribution: mx(0.5, normal(0,1))
|
||||
},
|
||||
{
|
||||
name: "two",
|
||||
distribution: mx(2, normal(5, 2)),
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Constants
|
||||
|
||||
A constant is a simple number as a result. This has special formatting rules
|
||||
|
|
21
packages/squiggle-lang/__tests__/E/A_test.res
Normal file
21
packages/squiggle-lang/__tests__/E/A_test.res
Normal file
|
@ -0,0 +1,21 @@
|
|||
open Jest
|
||||
open TestHelpers
|
||||
|
||||
describe("E.A.getByFmap", () => {
|
||||
makeTest("Empty list returns None", E.A.getByFmap([], x => x + 1, x => mod(x, 2) == 0), None)
|
||||
makeTest(
|
||||
"Never predicate returns None",
|
||||
E.A.getByFmap([1, 2, 3, 4, 5, 6], x => x + 1, _ => false),
|
||||
None,
|
||||
)
|
||||
makeTest(
|
||||
"function evaluates",
|
||||
E.A.getByFmap([1, 1, 1, 1, 1, 1, 1, 2, 1, 1], x => 3 * x, x => x > 4),
|
||||
Some(6),
|
||||
)
|
||||
makeTest(
|
||||
"always predicate returns fn(fst(a))",
|
||||
E.A.getByFmap([0, 1, 2, 3, 4, 5, 6], x => 10 + x, _ => true),
|
||||
Some(10),
|
||||
)
|
||||
})
|
|
@ -1,4 +0,0 @@
|
|||
open Jest
|
||||
open Expect
|
||||
|
||||
test("todo", () => expect("1")->toBe("1"))
|
|
@ -68,3 +68,5 @@ myTypeCheckTest(test, "number | string", "1", "Ok")
|
|||
myTypeCheckTest(test, "date | string", "1", "Expected type: (date | string) but got: 1")
|
||||
myTypeCheckTest(test, "number<-min(10)", "10", "Ok")
|
||||
myTypeCheckTest(test, "number<-min(10)", "0", "Expected type: number<-min(10) but got: 0")
|
||||
myTypeCheckTest(test, "any", "0", "Ok")
|
||||
myTypeCheckTest(test, "any", "'a'", "Ok")
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
open Jest
|
||||
open Expect
|
||||
|
||||
module DispatchT = Reducer_Dispatch_T
|
||||
module Expression = Reducer_Expression
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module TypeCompile = Reducer_Type_Compile
|
||||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
open ReducerInterface_InternalExpressionValue
|
||||
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
||||
// Let's build a function to replace switch statements
|
||||
// In dispatchChainPiece, we execute an return the result of execution if there is a type match.
|
||||
// Otherwise we return None so that the call chain can continue.
|
||||
// So we want to build a function like
|
||||
// dispatchChainPiece = (call: functionCall, environment): option<result<internalExpressionValue, errorValue>>
|
||||
|
||||
// Now lets make the dispatchChainPiece itself.
|
||||
// Note that I am not passing the reducer to the dispatchChainPiece as an argument because it is in the context anyway.
|
||||
// Keep in mind that reducerFn is necessary for map/reduce so dispatchChainPiece should have a reducerFn in context.
|
||||
|
||||
let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispatchChainPiece => {
|
||||
// Let's have a pure implementations
|
||||
module Implementation = {
|
||||
let stringConcat = (a: string, b: string): string => Js.String2.concat(a, b)
|
||||
let arrayConcat = (
|
||||
a: Js.Array2.t<internalExpressionValue>,
|
||||
b: Js.Array2.t<internalExpressionValue>,
|
||||
): Js.Array2.t<internalExpressionValue> => Js.Array2.concat(a, b)
|
||||
let plot = _r => "yey, plotted"
|
||||
}
|
||||
|
||||
let extractStringString = args =>
|
||||
switch args {
|
||||
| [IEvString(a), IEvString(b)] => (a, b)
|
||||
| _ => raise(Reducer_Exception.ImpossibleException("extractStringString developer error"))
|
||||
}
|
||||
|
||||
let extractArrayArray = args =>
|
||||
switch args {
|
||||
| [IEvArray(a), IEvArray(b)] => (a, b)
|
||||
| _ => raise(Reducer_Exception.ImpossibleException("extractArrayArray developer error"))
|
||||
}
|
||||
|
||||
// Let's bridge the pure implementation to expression values
|
||||
module Bridge = {
|
||||
let stringConcat: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
let (a, b) = extractStringString(args)
|
||||
Implementation.stringConcat(a, b)->IEvString->Ok
|
||||
}
|
||||
let arrayConcat: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
let (a, b) = extractArrayArray(args)
|
||||
Implementation.arrayConcat(a, b)->IEvArray->Ok
|
||||
}
|
||||
let plot: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
switch args {
|
||||
// Just assume that we are doing the business of extracting and converting the deep record
|
||||
| [IEvRecord(_)] => Implementation.plot({"title": "This is a plot"})->IEvString->Ok
|
||||
| _ => raise(Reducer_Exception.ImpossibleException("plot developer error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// concat functions are to illustrate polymoprhism. And the plot function is to illustrate complex types
|
||||
let jumpTable = [
|
||||
(
|
||||
"concat",
|
||||
TypeCompile.fromTypeExpressionExn("string=>string=>string", reducer),
|
||||
Bridge.stringConcat,
|
||||
),
|
||||
(
|
||||
"concat",
|
||||
TypeCompile.fromTypeExpressionExn("[any]=>[any]=>[any]", reducer),
|
||||
Bridge.arrayConcat,
|
||||
),
|
||||
(
|
||||
"plot",
|
||||
TypeCompile.fromTypeExpressionExn(
|
||||
// Nested complex types are available
|
||||
// records {property: type}
|
||||
// arrays [type]
|
||||
// tuples [type, type]
|
||||
// <- type contracts are available naturally and they become part of dispatching
|
||||
// Here we are not enumerating the possibilities because type checking has a dedicated test
|
||||
"{title: string, line: {width: number, color: string}}=>string",
|
||||
reducer,
|
||||
),
|
||||
Bridge.plot,
|
||||
),
|
||||
]
|
||||
|
||||
//Here we are creating a dispatchChainPiece function that will do the actual dispatch from the jumpTable
|
||||
Reducer_Dispatch_ChainPiece.makeFromTypes(jumpTable)
|
||||
}
|
||||
|
||||
// And finally, let's write a library dispatch for our external library
|
||||
// Exactly the same as the one used in real life
|
||||
let _dispatch = (
|
||||
call: functionCall,
|
||||
environment,
|
||||
reducer: Reducer_Expression_T.reducerFn,
|
||||
chain,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
let dispatchChainPiece = makeMyDispatchChainPiece(reducer)
|
||||
dispatchChainPiece(call, environment)->E.O2.defaultFn(() => chain(call, environment, reducer))
|
||||
}
|
||||
|
||||
// What is important about this implementation?
|
||||
// A) Exactly the same function jump table can be used to create type guarded lambda functions
|
||||
// Guarded lambda functions will be the basis of the next version of Squiggle
|
||||
// B) Complicated recursive record types are not a problem.
|
||||
|
||||
describe("Type Dispatch", () => {
|
||||
let reducerFn = Expression.reduceExpression
|
||||
let dispatchChainPiece = makeMyDispatchChainPiece(reducerFn)
|
||||
test("stringConcat", () => {
|
||||
let call: functionCall = ("concat", [IEvString("hello"), IEvString("world")])
|
||||
|
||||
let result = dispatchChainPiece(call, defaultEnvironment)
|
||||
expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
|
||||
})
|
||||
})
|
|
@ -74,6 +74,7 @@ describe("eval on distribution functions", () => {
|
|||
testEval("truncateLeft(normal(5,2), 3)", "Ok(Point Set Distribution)")
|
||||
testEval("truncateRight(normal(5,2), 3)", "Ok(Point Set Distribution)")
|
||||
testEval("truncate(normal(5,2), 3, 8)", "Ok(Point Set Distribution)")
|
||||
testEval("truncate(normal(5,2) |> SampleSet.fromDist, 3, 8)", "Ok(Sample Set Distribution)")
|
||||
testEval("isNormalized(truncate(normal(5,2), 3, 8))", "Ok(true)")
|
||||
})
|
||||
|
||||
|
|
|
@ -63,6 +63,9 @@ describe("FunctionRegistry Library", () => {
|
|||
testEvalToBe("SampleSet.fromList([3,5,2,3,5,2,3,5,2,3,3,5])", "Ok(Sample Set Distribution)")
|
||||
testEvalToBe("SampleSet.fromList([3,5,2,3,5,2,3,5,2,3,3,5])", "Ok(Sample Set Distribution)")
|
||||
testEvalToBe("SampleSet.fromFn({|| sample(normal(5,2))})", "Ok(Sample Set Distribution)")
|
||||
testEvalToBe("SampleSet.min(SampleSet.fromDist(normal(50,2)), 2)", "Ok(Sample Set Distribution)")
|
||||
testEvalToBe("mean(SampleSet.min(SampleSet.fromDist(normal(50,2)), 2))", "Ok(2)")
|
||||
testEvalToBe("SampleSet.max(SampleSet.fromDist(normal(50,2)), 10)", "Ok(Sample Set Distribution)")
|
||||
testEvalToBe(
|
||||
"addOne(t)=t+1; SampleSet.toList(SampleSet.map(SampleSet.fromList([1,2,3,4,5,6]), addOne))",
|
||||
"Ok([2,3,4,5,6,7])",
|
||||
|
|
20
packages/squiggle-lang/__tests__/Stdlib_test.res
Normal file
20
packages/squiggle-lang/__tests__/Stdlib_test.res
Normal file
|
@ -0,0 +1,20 @@
|
|||
open Jest
|
||||
open Expect
|
||||
|
||||
let makeTest = (~only=false, str, item1, item2) =>
|
||||
only
|
||||
? Only.test(str, () => expect(item1)->toEqual(item2))
|
||||
: test(str, () => expect(item1)->toEqual(item2))
|
||||
|
||||
describe("Stdlib", () => {
|
||||
makeTest(
|
||||
"Length of Random.sample",
|
||||
Stdlib.Random.sample([1.0, 2.0], {probs: [0.5, 0.5], size: 10})->E.A.length,
|
||||
10,
|
||||
)
|
||||
makeTest(
|
||||
"Random.sample returns elements from input array (will fail with very slim probability)",
|
||||
Stdlib.Random.sample([1.0, 2.0], {probs: [0.5, 0.5], size: 10})->E.A.uniq->E.A.Floats.sort,
|
||||
[1.0, 2.0],
|
||||
)
|
||||
})
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@quri/squiggle-lang",
|
||||
"version": "0.2.11",
|
||||
"version": "0.3.1",
|
||||
"homepage": "https://squiggle-language.com",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
@ -18,6 +18,7 @@
|
|||
"benchmark": "ts-node benchmark/conversion_tests.ts",
|
||||
"test": "jest",
|
||||
"test:ts": "jest __tests__/TS/",
|
||||
"test:stdlib": "jest __tests__/Stdlib_test.bs.js",
|
||||
"test:rescript": "jest --modulePathIgnorePatterns=__tests__/TS/*",
|
||||
"test:watch": "jest --watchAll",
|
||||
"test:fnRegistry": "jest __tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.bs.js",
|
||||
|
@ -44,18 +45,18 @@
|
|||
"@stdlib/stats": "^0.0.13",
|
||||
"jstat": "^1.9.5",
|
||||
"lodash": "^4.17.21",
|
||||
"mathjs": "^11.0.1",
|
||||
"mathjs": "^11.1.0",
|
||||
"pdfast": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@glennsl/rescript-jest": "^0.9.0",
|
||||
"@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",
|
||||
"codecov": "^3.8.3",
|
||||
"fast-check": "^3.1.1",
|
||||
"fast-check": "^3.1.2",
|
||||
"gentype": "^4.5.0",
|
||||
"jest": "^27.5.1",
|
||||
"moduleserve": "^0.9.1",
|
||||
|
@ -68,7 +69,7 @@
|
|||
"ts-jest": "^27.1.4",
|
||||
"ts-loader": "^9.3.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.7.4",
|
||||
"typescript": "^4.8.2",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
},
|
||||
|
|
|
@ -40,8 +40,8 @@ export type { result, shape, environment, lambdaValue, squiggleExpression };
|
|||
export { parse } from "./parse";
|
||||
|
||||
export let defaultSamplingInputs: environment = {
|
||||
sampleCount: 10000,
|
||||
xyPointLength: 10000,
|
||||
sampleCount: 1000,
|
||||
xyPointLength: 1000,
|
||||
};
|
||||
|
||||
export function run(
|
||||
|
|
|
@ -216,7 +216,7 @@ let rec run = (~env: env, functionCallInfo: functionCallInfo): outputType => {
|
|||
| FromFloat(subFnName, x) => reCall(~functionCallInfo=FromFloat(subFnName, x), ())
|
||||
| Mixture(dists) =>
|
||||
dists
|
||||
->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd)
|
||||
->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd, ~env)
|
||||
->E.R2.fmap(r => Dist(r))
|
||||
->OutputLocal.fromResult
|
||||
| FromSamples(xs) =>
|
||||
|
|
|
@ -242,6 +242,13 @@ module Truncate = {
|
|||
switch trySymbolicSimplification(leftCutoff, rightCutoff, t) {
|
||||
| Some(r) => Ok(r)
|
||||
| None =>
|
||||
switch t {
|
||||
| SampleSet(t) =>
|
||||
switch SampleSetDist.truncate(t, ~leftCutoff, ~rightCutoff) {
|
||||
| Ok(r) => Ok(SampleSet(r))
|
||||
| Error(err) => Error(DistributionTypes.SampleSetError(err))
|
||||
}
|
||||
| _ =>
|
||||
toPointSetFn(t)->E.R2.fmap(t => {
|
||||
DistributionTypes.PointSet(
|
||||
PointSetDist.T.truncate(leftCutoff, rightCutoff, t)->PointSetDist.T.normalize,
|
||||
|
@ -250,6 +257,7 @@ module Truncate = {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let truncate = Truncate.run
|
||||
|
@ -491,15 +499,30 @@ let pointwiseCombinationFloat = (
|
|||
m->E.R2.fmap(r => DistributionTypes.PointSet(r))
|
||||
}
|
||||
|
||||
//Note: The result should always cumulatively sum to 1. This would be good to test.
|
||||
//Note: If the inputs are not normalized, this will return poor results. The weights probably refer to the post-normalized forms. It would be good to apply a catch to this.
|
||||
//TODO: The result should always cumulatively sum to 1. This would be good to test.
|
||||
//TODO: If the inputs are not normalized, this will return poor results. The weights probably refer to the post-normalized forms. It would be good to apply a catch to this.
|
||||
let mixture = (
|
||||
values: array<(t, float)>,
|
||||
~scaleMultiplyFn: scaleMultiplyFn,
|
||||
~pointwiseAddFn: pointwiseAddFn,
|
||||
~env: env,
|
||||
) => {
|
||||
if E.A.length(values) == 0 {
|
||||
let allValuesAreSampleSet = v => E.A.all(((t, _)) => isSampleSetSet(t), v)
|
||||
|
||||
if E.A.isEmpty(values) {
|
||||
Error(DistributionTypes.OtherError("Mixture error: mixture must have at least 1 element"))
|
||||
} else if allValuesAreSampleSet(values) {
|
||||
let withSampleSetValues = values->E.A2.fmap(((value, weight)) =>
|
||||
switch value {
|
||||
| SampleSet(sampleSet) => Ok((sampleSet, weight))
|
||||
| _ => Error("Unreachable")
|
||||
}->E.R2.toExn("Mixture coding error: SampleSet expected. This should be inaccessible.")
|
||||
)
|
||||
let sampleSetMixture = SampleSetDist.mixture(withSampleSetValues, env.sampleCount)
|
||||
switch sampleSetMixture {
|
||||
| Ok(sampleSet) => Ok(DistributionTypes.SampleSet(sampleSet))
|
||||
| Error(err) => Error(DistributionTypes.Error.sampleErrorToDistErr(err))
|
||||
}
|
||||
} else {
|
||||
let totalWeight = values->E.A2.fmap(E.Tuple2.second)->E.A.Floats.sum
|
||||
let properlyWeightedValues =
|
||||
|
|
|
@ -81,6 +81,7 @@ let mixture: (
|
|||
array<(t, float)>,
|
||||
~scaleMultiplyFn: scaleMultiplyFn,
|
||||
~pointwiseAddFn: pointwiseAddFn,
|
||||
~env: env,
|
||||
) => result<t, error>
|
||||
|
||||
let isSymbolic: t => bool
|
||||
|
|
|
@ -224,3 +224,8 @@ module T = Dist({
|
|||
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
||||
}
|
||||
})
|
||||
|
||||
let sampleN = (t: t, n): array<float> => {
|
||||
let normalized = t->T.normalize->getShape
|
||||
Stdlib.Random.sample(normalized.xs, {probs: normalized.ys, size: n})
|
||||
}
|
||||
|
|
|
@ -257,3 +257,7 @@ let toSparkline = (t: t, bucketCount): result<string, PointSetTypes.sparklineErr
|
|||
->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount))
|
||||
->E.O2.toResult(PointSetTypes.CannotSparklineDiscrete)
|
||||
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
||||
|
||||
let makeDiscrete = (d): t => Discrete(d)
|
||||
let makeContinuous = (d): t => Continuous(d)
|
||||
let makeMixed = (d): t => Mixed(d)
|
||||
|
|
|
@ -131,3 +131,37 @@ let max = t => T.get(t)->E.A.Floats.max
|
|||
let stdev = t => T.get(t)->E.A.Floats.stdev
|
||||
let variance = t => T.get(t)->E.A.Floats.variance
|
||||
let percentile = (t, f) => T.get(t)->E.A.Floats.percentile(f)
|
||||
|
||||
let mixture = (values: array<(t, float)>, intendedLength: int) => {
|
||||
let totalWeight = values->E.A2.fmap(E.Tuple2.second)->E.A.Floats.sum
|
||||
let discreteSamples =
|
||||
values
|
||||
->Belt.Array.mapWithIndex((i, (_, weight)) => (E.I.toFloat(i), weight /. totalWeight))
|
||||
->XYShape.T.fromZippedArray
|
||||
->Discrete.make
|
||||
->Discrete.sampleN(intendedLength)
|
||||
let dists = values->E.A2.fmap(E.Tuple2.first)->E.A2.fmap(T.get)
|
||||
let samples =
|
||||
discreteSamples
|
||||
->Belt.Array.mapWithIndex((index, distIndexToChoose) => {
|
||||
let chosenDist = E.A.get(dists, E.Float.toInt(distIndexToChoose))
|
||||
chosenDist->E.O.bind(E.A.get(_, index))
|
||||
})
|
||||
->E.A.O.openIfAllSome
|
||||
samples->E.O2.toExn("Mixture unreachable error")->T.make
|
||||
}
|
||||
|
||||
let truncateLeft = (t, f) => T.get(t)->E.A2.filter(x => x >= f)->T.make
|
||||
let truncateRight = (t, f) => T.get(t)->E.A2.filter(x => x <= f)->T.make
|
||||
|
||||
let truncate = (t, ~leftCutoff: option<float>, ~rightCutoff: option<float>) => {
|
||||
let withTruncatedLeft = t => leftCutoff |> E.O.dimap(left => truncateLeft(t, left), _ => Ok(t))
|
||||
let withTruncatedRight = t => rightCutoff |> E.O.dimap(left => truncateRight(t, left), _ => Ok(t))
|
||||
t->withTruncatedLeft |> E.R2.bind(withTruncatedRight)
|
||||
}
|
||||
|
||||
let minOfTwo = (t1: t, t2: t) => map2(~fn=(a, b) => Ok(Js.Math.min_float(a, b)), ~t1, ~t2)
|
||||
let maxOfTwo = (t1: t, t2: t) => map2(~fn=(a, b) => Ok(Js.Math.max_float(a, b)), ~t1, ~t2)
|
||||
|
||||
let minOfFloat = (t: t, f: float) => samplesMap(~fn=a => Ok(Js.Math.min_float(a, f)), t)
|
||||
let maxOfFloat = (t: t, f: float) => samplesMap(~fn=a => Ok(Js.Math.max_float(a, f)), t)
|
||||
|
|
|
@ -23,6 +23,30 @@ let inputsTodist = (inputs: array<FunctionRegistry_Core.frValue>, makeDist) => {
|
|||
expressionValue
|
||||
}
|
||||
|
||||
module Internal = {
|
||||
type t = PointSetDist.t
|
||||
|
||||
let toType = (r): result<
|
||||
ReducerInterface_InternalExpressionValue.t,
|
||||
Reducer_ErrorValue.errorValue,
|
||||
> =>
|
||||
switch r {
|
||||
| Ok(r) => Ok(Wrappers.evDistribution(PointSet(r)))
|
||||
| Error(err) => Error(REOperationError(err))
|
||||
}
|
||||
|
||||
let doLambdaCall = (aLambdaValue, list, environment, reducer) =>
|
||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
||||
| Ok(IEvNumber(f)) => Ok(f)
|
||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||
}
|
||||
|
||||
let mapY = (pointSetDist: t, aLambdaValue, env, reducer) => {
|
||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
|
||||
PointSetDist.T.mapYResult(~fn, pointSetDist)->toType
|
||||
}
|
||||
}
|
||||
|
||||
let library = [
|
||||
Function.make(
|
||||
~name="fromDist",
|
||||
|
@ -53,6 +77,27 @@ let library = [
|
|||
],
|
||||
(),
|
||||
),
|
||||
Function.make(
|
||||
~name="mapY",
|
||||
~nameSpace,
|
||||
~requiresNamespace=true,
|
||||
~examples=[`PointSet.mapY(mx(normal(5,2)), {|x| x + 1})`],
|
||||
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
|
||||
~definitions=[
|
||||
FnDefinition.make(
|
||||
~name="mapY",
|
||||
~inputs=[FRTypeDist, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
switch inputs {
|
||||
| [IEvDistribution(PointSet(dist)), IEvLambda(lambda)] =>
|
||||
Internal.mapY(dist, lambda, env, reducer)->E.R2.errMap(Reducer_ErrorValue.errorToString)
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
),
|
||||
],
|
||||
(),
|
||||
),
|
||||
Function.make(
|
||||
~name="makeContinuous",
|
||||
~nameSpace,
|
||||
|
|
|
@ -75,7 +75,7 @@ module Internal = {
|
|||
}
|
||||
}
|
||||
|
||||
let library = [
|
||||
let libaryBase = [
|
||||
Function.make(
|
||||
~name="fromDist",
|
||||
~nameSpace,
|
||||
|
@ -92,7 +92,7 @@ let library = [
|
|||
GenericDist.toSampleSetDist(dist, env.sampleCount)
|
||||
->E.R2.fmap(Wrappers.sampleSet)
|
||||
->E.R2.fmap(Wrappers.evDistribution)
|
||||
->E.R2.errMap(_ => "")
|
||||
->E.R2.errMap(DistributionTypes.Error.toString)
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -158,7 +158,7 @@ let library = [
|
|||
| [IEvLambda(lambda)] =>
|
||||
switch Internal.fromFn(lambda, env, reducer) {
|
||||
| Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution)
|
||||
| Error(_) => Error("issue")
|
||||
| Error(e) => Error(Operation.Error.toString(e))
|
||||
}
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
|
@ -180,7 +180,7 @@ let library = [
|
|||
~run=(inputs, _, env, reducer) =>
|
||||
switch inputs {
|
||||
| [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] =>
|
||||
Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(_ => "")
|
||||
Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(Reducer_ErrorValue.errorToString)
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -207,7 +207,9 @@ let library = [
|
|||
IEvDistribution(SampleSet(dist2)),
|
||||
IEvLambda(lambda),
|
||||
] =>
|
||||
Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap(_ => "")
|
||||
Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
|
@ -236,7 +238,9 @@ let library = [
|
|||
IEvDistribution(SampleSet(dist3)),
|
||||
IEvLambda(lambda),
|
||||
] =>
|
||||
Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap(_ => "")
|
||||
Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -259,9 +263,9 @@ let library = [
|
|||
~run=(inputs, _, env, reducer) =>
|
||||
switch inputs {
|
||||
| [IEvArray(dists), IEvLambda(lambda)] =>
|
||||
Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap(_e => {
|
||||
"AHHH doesn't work"
|
||||
})
|
||||
Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -270,3 +274,63 @@ let library = [
|
|||
(),
|
||||
),
|
||||
]
|
||||
|
||||
module Comparison = {
|
||||
let template = (name, inputs, run) => {
|
||||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs,
|
||||
~run=(inputs, _, _, _) => {
|
||||
run(inputs)
|
||||
},
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
||||
let wrapper = r =>
|
||||
r
|
||||
->E.R2.fmap(r => r->Wrappers.sampleSet->Wrappers.evDistribution)
|
||||
->E.R2.errMap(SampleSetDist.Error.toString)
|
||||
|
||||
let mkBig = (name, withDist, withFloat) =>
|
||||
Function.make(
|
||||
~name,
|
||||
~nameSpace,
|
||||
~requiresNamespace=false,
|
||||
~examples=[
|
||||
`SampleSet.${name}(SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(6,2)))`,
|
||||
`SampleSet.${name}(SampleSet.fromDist(normal(5,2)), 3.0)`,
|
||||
`SampleSet.${name}(4.0, SampleSet.fromDist(normal(6,2)))`,
|
||||
],
|
||||
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
|
||||
~definitions=[
|
||||
template(name, [FRTypeDist, FRTypeDist], inputs => {
|
||||
switch inputs {
|
||||
| [IEvDistribution(SampleSet(dist1)), IEvDistribution(SampleSet(dist2))] =>
|
||||
withDist(dist1, dist2)->wrapper
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
}),
|
||||
template(name, [FRTypeDist, FRTypeNumber], inputs => {
|
||||
switch inputs {
|
||||
| [IEvDistribution(SampleSet(dist)), IEvNumber(f)] => withFloat(dist, f)->wrapper
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
}),
|
||||
template(name, [FRTypeNumber, FRTypeDist], inputs => {
|
||||
switch inputs {
|
||||
| [IEvNumber(f), IEvDistribution(SampleSet(dist))] => withFloat(dist, f)->wrapper
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
}),
|
||||
],
|
||||
(),
|
||||
)
|
||||
|
||||
let library = [
|
||||
mkBig("min", SampleSetDist.minOfTwo, SampleSetDist.minOfFloat),
|
||||
mkBig("max", SampleSetDist.maxOfTwo, SampleSetDist.maxOfFloat),
|
||||
]
|
||||
}
|
||||
|
||||
let library = E.A.append(libaryBase, Comparison.library)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
module T = Reducer_Dispatch_T
|
||||
open ReducerInterface_InternalExpressionValue
|
||||
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
||||
let makeFromTypes = jumpTable => {
|
||||
let dispatchChainPiece: T.dispatchChainPiece = ((fnName, fnArgs): functionCall, environment) => {
|
||||
let jumpTableEntry = jumpTable->Js.Array2.find(elem => {
|
||||
let (candidName, candidType, _) = elem
|
||||
candidName == fnName && TypeChecker.checkITypeArgumentsBool(candidType, fnArgs)
|
||||
})
|
||||
switch jumpTableEntry {
|
||||
| Some((_, _, bridgeFn)) => bridgeFn(fnArgs, environment)->Some
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
dispatchChainPiece
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
|
||||
// Each piece of the dispatch chain computes the result or returns None so that the chain can continue
|
||||
type dispatchChainPiece = (
|
||||
InternalExpressionValue.functionCall,
|
||||
InternalExpressionValue.environment,
|
||||
) => option<result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>>
|
||||
|
||||
type dispatchChainPieceWithReducer = (
|
||||
InternalExpressionValue.functionCall,
|
||||
InternalExpressionValue.environment,
|
||||
ExpressionT.reducerFn,
|
||||
) => option<result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>>
|
||||
|
||||
// This is a switch statement case implementation: get the arguments and compute the result
|
||||
type genericIEvFunction = (
|
||||
array<InternalExpressionValue.t>,
|
||||
InternalExpressionValue.environment,
|
||||
) => result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>
|
|
@ -250,7 +250,7 @@ float 'float'
|
|||
d = [0-9]
|
||||
|
||||
boolean 'boolean'
|
||||
= ('true'/'false')
|
||||
= ('true'/'false') ! [a-z]i ! [_$]
|
||||
{ return h.nodeBoolean(text() === 'true')}
|
||||
|
||||
valueConstructor
|
||||
|
|
|
@ -38,3 +38,12 @@ let fromTypeExpression = (
|
|||
(reducerFn: ExpressionT.reducerFn),
|
||||
)->Belt.Result.map(T.fromIEvValue)
|
||||
}
|
||||
|
||||
let fromTypeExpressionExn = (
|
||||
typeExpressionSourceCode: string,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
): T.t =>
|
||||
switch fromTypeExpression(typeExpressionSourceCode, reducerFn) {
|
||||
| Ok(value) => value
|
||||
| _ => `Cannot compile ${typeExpressionSourceCode}`->Reducer_Exception.ImpossibleException->raise
|
||||
}
|
||||
|
|
|
@ -7,12 +7,17 @@ open InternalExpressionValue
|
|||
let rec isITypeOf = (anIType: T.iType, aValue): result<bool, T.typeErrorValue> => {
|
||||
let caseTypeIdentifier = (anUpperTypeName, aValue) => {
|
||||
let aTypeName = anUpperTypeName->Js.String2.toLowerCase
|
||||
switch aTypeName {
|
||||
| "any" => Ok(true)
|
||||
| _ => {
|
||||
let valueTypeName = aValue->valueToValueType->valueTypeToString->Js.String2.toLowerCase
|
||||
switch aTypeName == valueTypeName {
|
||||
| true => Ok(true)
|
||||
| false => T.TypeMismatch(anIType, aValue)->Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let caseRecord = (anIType, propertyMap: Belt.Map.String.t<T.iType>, evValue) =>
|
||||
switch evValue {
|
||||
|
@ -149,6 +154,13 @@ let checkITypeArguments = (anIType: T.iType, args: array<InternalExpressionValue
|
|||
}
|
||||
}
|
||||
|
||||
let checkITypeArgumentsBool = (anIType: T.iType, args: array<InternalExpressionValue.t>): bool => {
|
||||
switch checkITypeArguments(anIType, args) {
|
||||
| Ok(_) => true
|
||||
| _ => false
|
||||
}
|
||||
}
|
||||
|
||||
let checkArguments = (
|
||||
typeExpressionSourceCode: string,
|
||||
args: array<InternalExpressionValue.t>,
|
||||
|
|
|
@ -2,7 +2,7 @@ module Bindings = Reducer_Bindings
|
|||
|
||||
let bindings: Bindings.t =
|
||||
[
|
||||
("System.version", ReducerInterface_InternalExpressionValue.IEvString("0.3.0")),
|
||||
("System.version", ReducerInterface_InternalExpressionValue.IEvString("0.3.1")),
|
||||
]->Bindings.fromArray
|
||||
|
||||
let makeBindings = (previousBindings: Bindings.t): Bindings.t =>
|
||||
|
|
|
@ -220,6 +220,7 @@ module I = {
|
|||
let increment = n => n + 1
|
||||
let decrement = n => n - 1
|
||||
let toString = Js.Int.toString
|
||||
let toFloat = Js.Int.toFloat
|
||||
}
|
||||
|
||||
exception Assertion(string)
|
||||
|
@ -572,10 +573,20 @@ module A = {
|
|||
|> (x => Ok(x))
|
||||
}
|
||||
|
||||
let getByOpen = (a, op, bin) =>
|
||||
switch getBy(a, r => bin(op(r))) {
|
||||
| Some(r) => Some(op(r))
|
||||
| None => None
|
||||
let getByFmap = (a, fn, boolCondition) => {
|
||||
let i = ref(0)
|
||||
let finalFunctionValue = ref(None)
|
||||
let length = Belt.Array.length(a)
|
||||
|
||||
while i.contents < length && finalFunctionValue.contents == None {
|
||||
let itemWithFnApplied = Belt.Array.getUnsafe(a, i.contents) |> fn
|
||||
if boolCondition(itemWithFnApplied) {
|
||||
finalFunctionValue := Some(itemWithFnApplied)
|
||||
}
|
||||
i := i.contents + 1
|
||||
}
|
||||
|
||||
finalFunctionValue.contents
|
||||
}
|
||||
|
||||
let tail = Belt.Array.sliceToEnd(_, 1)
|
||||
|
@ -680,7 +691,7 @@ module A = {
|
|||
let firstSome = x => Belt.Array.getBy(x, O.isSome)
|
||||
|
||||
let firstSomeFn = (r: array<unit => option<'a>>): option<'a> =>
|
||||
O.flatten(getByOpen(r, l => l(), O.isSome))
|
||||
O.flatten(getByFmap(r, l => l(), O.isSome))
|
||||
|
||||
let firstSomeFnWithDefault = (r, default) => firstSomeFn(r)->O2.default(default)
|
||||
|
||||
|
|
|
@ -38,3 +38,12 @@ module Logistic = {
|
|||
@module external variance: (float, float) => float = "@stdlib/stats/base/dists/logistic/variance"
|
||||
let variance = variance
|
||||
}
|
||||
|
||||
module Random = {
|
||||
type sampleArgs = {
|
||||
probs: array<float>,
|
||||
size: int,
|
||||
}
|
||||
@module external sample: (array<float>, sampleArgs) => array<float> = "@stdlib/random/sample"
|
||||
let sample = sample
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = {
|
|||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".js"],
|
||||
fallback: { buffer: ["@stdlib/buffer"] },
|
||||
},
|
||||
output: {
|
||||
filename: "bundle.js",
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": "warn",
|
||||
"@typescript-eslint/semi": "warn",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off"
|
||||
},
|
||||
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
|
||||
}
|
3
packages/vscode-ext/.prettierignore
Normal file
3
packages/vscode-ext/.prettierignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
out
|
||||
dist
|
||||
media/vendor
|
|
@ -7,7 +7,7 @@
|
|||
"publisher": "QURI",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/quantified-uncertainty/squiggle.git"
|
||||
"url": "https://github.com/quantified-uncertainty/squiggle.git"
|
||||
},
|
||||
"icon": "media/vendor/icon.png",
|
||||
"engines": {
|
||||
|
@ -121,20 +121,17 @@
|
|||
"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": "eslint client/src server/src --ext ts",
|
||||
"format": "eslint client/src server/src --ext ts --fix",
|
||||
"lint": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"package": "npx vsce package --yarn"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/glob": "^7.2.0",
|
||||
"@types/node": "18.x",
|
||||
"@types/vscode": "^1.70.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
||||
"@typescript-eslint/parser": "^5.32.0",
|
||||
"eslint": "^8.21.0",
|
||||
"glob": "^8.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"typescript": "^4.7.4",
|
||||
"typescript": "^4.8.2",
|
||||
"vsce-yarn-patch": "^1.66.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -290,12 +290,29 @@ quantile: (distribution, number) => number
|
|||
quantile(normal(5, 2), 0.5);
|
||||
```
|
||||
|
||||
### truncateLeft
|
||||
### truncate
|
||||
|
||||
Truncates the left side of a distribution. Returns either a pointSet distribution or a symbolic distribution.
|
||||
Truncates both the left side and the right side of a distribution.
|
||||
|
||||
```
|
||||
truncateLeft: (distribution, l => number) => distribution
|
||||
truncate: (distribution, left: number, right: number) => distribution
|
||||
```
|
||||
|
||||
<Admonition type="note" title="Implementation Details">
|
||||
<p>
|
||||
Sample set distributions are truncated by filtering samples, but point set
|
||||
distributions are truncated using direct geometric manipulation. Uniform
|
||||
distributions are truncated symbolically. Symbolic but non-uniform
|
||||
distributions get converted to Point Set distributions.
|
||||
</p>
|
||||
</Admonition>
|
||||
|
||||
### truncateLeft
|
||||
|
||||
Truncates the left side of a distribution.
|
||||
|
||||
```
|
||||
truncateLeft: (distribution, left: number) => distribution
|
||||
```
|
||||
|
||||
**Examples**
|
||||
|
@ -306,10 +323,10 @@ truncateLeft(normal(5, 2), 3);
|
|||
|
||||
### truncateRight
|
||||
|
||||
Truncates the right side of a distribution. Returns either a pointSet distribution or a symbolic distribution.
|
||||
Truncates the right side of a distribution.
|
||||
|
||||
```
|
||||
truncateRight: (distribution, r => number) => distribution
|
||||
truncateRight: (distribution, right: number) => distribution
|
||||
```
|
||||
|
||||
**Examples**
|
||||
|
@ -388,7 +405,7 @@ The only functions that do not return normalized distributions are the pointwise
|
|||
|
||||
### normalize
|
||||
|
||||
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1. This only impacts Pointset distributions, because those are the only ones that can be non-normlized.
|
||||
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1. This only impacts Point Set distributions, because those are the only ones that can be non-normlized.
|
||||
|
||||
```
|
||||
normalize: (distribution) => distribution
|
||||
|
|
|
@ -46,3 +46,13 @@ PointSet.makeDiscrete([
|
|||
{ x: 3, y: 0.1 },
|
||||
]);
|
||||
```
|
||||
|
||||
### mapY
|
||||
|
||||
```
|
||||
PointSet.mapY: (pointSetDist, (number => number)) => pointSetDist
|
||||
```
|
||||
|
||||
```javascript
|
||||
normal(5,3) |> PointSet.fromDist |> PointSet.mapY({|x| x ^ 2}) |> normalize
|
||||
```
|
||||
|
|
|
@ -52,6 +52,29 @@ const config = {
|
|||
themeConfig:
|
||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||
({
|
||||
algolia: {
|
||||
// The application ID provided by Algolia
|
||||
appId: "KBED3M1CMD",
|
||||
|
||||
// Public API key: it is safe to commit it
|
||||
apiKey: "c61bc7603893cf287ed6971983af8bad",
|
||||
|
||||
indexName: "squiggle_docs",
|
||||
|
||||
// Optional: see doc section below
|
||||
contextualSearch: true,
|
||||
|
||||
// Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them.
|
||||
// externalUrlRegex: 'external\\.com|domain\\.com',
|
||||
|
||||
// Optional: Algolia search parameters
|
||||
searchParameters: {},
|
||||
|
||||
// Optional: path for search page that enabled by default (`false` to disable it)
|
||||
searchPagePath: "search",
|
||||
|
||||
//... other Algolia params
|
||||
},
|
||||
navbar: {
|
||||
title: "Squiggle",
|
||||
hideOnScroll: true,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "squiggle-website",
|
||||
"version": "0.2.1",
|
||||
"version": "0.3.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
@ -15,7 +15,7 @@
|
|||
"@docusaurus/core": "2.0.1",
|
||||
"@docusaurus/preset-classic": "2.0.1",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@quri/squiggle-components": "^0.2.23",
|
||||
"@quri/squiggle-components": "^0.3",
|
||||
"base64-js": "^1.5.1",
|
||||
"clsx": "^1.2.1",
|
||||
"hast-util-is-element": "2.1.2",
|
||||
|
|
Loading…
Reference in New Issue
Block a user