Merge branch 'staging' into dist-generic-library
This commit is contained in:
commit
e93b500d4a
23
.github/CODEOWNERS
vendored
Normal file
23
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# CODEOWNERS file
|
||||||
|
#
|
||||||
|
# This file is used to describe who owns what in this repository.
|
||||||
|
#
|
||||||
|
# For documentation on this file, see https://help.github.com/articles/about-codeowners/
|
||||||
|
# Mentioned users will get code review requests.
|
||||||
|
#
|
||||||
|
# IMPORTANT NOTE: in order to actually get pinged, commit access is required.
|
||||||
|
# This also holds true for GitHub teams.
|
||||||
|
|
||||||
|
# This file
|
||||||
|
/.github/CODEOWNERS @quinn-dougherty
|
||||||
|
|
||||||
|
# Any rescript code
|
||||||
|
*.res @Hazelfire @OAGr @quinn-dougherty
|
||||||
|
|
||||||
|
# Any typescript code
|
||||||
|
*.tsx @Hazelfire @OAGr @quinn-dougherty
|
||||||
|
|
||||||
|
# Any opsy files
|
||||||
|
*.json @quinn-dougherty
|
||||||
|
*.yaml @quinn-dougherty
|
||||||
|
*.yml @quinn-dougherty
|
14
.github/ISSUE_TEMPLATE/developer-bug.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/developer-bug.md
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
name: Developer friction when contributing to Squiggle
|
||||||
|
about: Did your yarn scripts fail? Did the CI diverge from a README? Etc.
|
||||||
|
labels: 'ops'
|
||||||
|
---
|
||||||
|
# Description:
|
||||||
|
|
||||||
|
|
||||||
|
# The OS and version, yarn version, etc. in which this came up
|
||||||
|
|
||||||
|
|
||||||
|
# Desired behavior
|
||||||
|
|
||||||
|
|
7
.github/ISSUE_TEMPLATE/future.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/future.md
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
name: Idea or feature request
|
||||||
|
about: Where would you like to see Squiggle go over the next few months, several months, or few years?
|
||||||
|
---
|
||||||
|
# Description
|
||||||
|
|
||||||
|
|
18
.github/ISSUE_TEMPLATE/user-bug.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/user-bug.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
name: Bug reports for Squiggle users
|
||||||
|
about: Rendering oddly, trouble with the playground, something like this?
|
||||||
|
labels: 'bug'
|
||||||
|
---
|
||||||
|
# Description:
|
||||||
|
|
||||||
|
|
||||||
|
# Steps to reproduce:
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
# Expected behavior:
|
||||||
|
|
||||||
|
|
||||||
|
# What I got instead:
|
||||||
|
|
85
.github/workflows/ci.yaml
vendored
Normal file
85
.github/workflows/ci.yaml
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
name: Squiggle packages check
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
pre_check:
|
||||||
|
name: Precheck for skipping redundant jobs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
should_skip_lang: ${{ steps.skip_lang_check.outputs.should_skip }}
|
||||||
|
should_skip_components: ${{ steps.skip_components_check.outputs.should_skip }}
|
||||||
|
should_skip_website: ${{ steps.skip_website_check.outputs.should_skip }}
|
||||||
|
steps:
|
||||||
|
- id: skip_lang_check
|
||||||
|
name: Check if the changes are about squiggle-lang src files
|
||||||
|
uses: fkirc/skip-duplicate-actions@master
|
||||||
|
with:
|
||||||
|
paths: '["packages/squiggle-lang/*"]'
|
||||||
|
- id: skip_components_check
|
||||||
|
name: Check if the changes are about components src files
|
||||||
|
uses: fkirc/skip-duplicate-actions@master
|
||||||
|
with:
|
||||||
|
paths: '["packages/components/*"]'
|
||||||
|
- id: skip_website_check
|
||||||
|
name: Check if the changes are about website src files
|
||||||
|
uses: fkirc/skip-duplicate-actions@master
|
||||||
|
with:
|
||||||
|
paths: '["packages/website/*"]'
|
||||||
|
|
||||||
|
lang-build-test:
|
||||||
|
name: Language build and test
|
||||||
|
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@v2
|
||||||
|
- name: Install dependencies from monorepo level
|
||||||
|
run: cd ../../ && yarn
|
||||||
|
- name: Build rescript codebase
|
||||||
|
run: yarn build
|
||||||
|
- name: Run tests
|
||||||
|
run: yarn test
|
||||||
|
- name: Run webpack
|
||||||
|
run: yarn bundle
|
||||||
|
|
||||||
|
components-build-test:
|
||||||
|
name: Components build and test
|
||||||
|
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@v2
|
||||||
|
- name: Install dependencies from monorepo level
|
||||||
|
run: cd ../../ && yarn
|
||||||
|
- name: Build rescript in squiggle-lang
|
||||||
|
run: cd ../squiggle-lang && yarn build
|
||||||
|
- name: Run webpack
|
||||||
|
run: yarn bundle
|
||||||
|
- name: Build storybook
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
website-build:
|
||||||
|
name: Website build
|
||||||
|
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@v2
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn
|
||||||
|
- name: Build website assets
|
||||||
|
run: yarn build
|
19
.github/workflows/lang-jest.yml
vendored
19
.github/workflows/lang-jest.yml
vendored
|
@ -1,19 +0,0 @@
|
||||||
name: Squiggle Lang Jest Tests
|
|
||||||
|
|
||||||
on: [push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
working-directory: packages/squiggle-lang
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Packages
|
|
||||||
run: yarn
|
|
||||||
- name: Build rescript
|
|
||||||
run: yarn run build
|
|
||||||
- name: Run tests
|
|
||||||
run: yarn test
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ yarn-error.log
|
||||||
.cache
|
.cache
|
||||||
.merlin
|
.merlin
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
|
.DS_Store
|
||||||
|
|
6
.parcelrc
Normal file
6
.parcelrc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "@parcel/config-default",
|
||||||
|
"transformers": {
|
||||||
|
"*.res": ["@parcel/transformer-raw"]
|
||||||
|
}
|
||||||
|
}
|
42
CONTRIBUTING.md
Normal file
42
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
_The current document was written quickly and not exhaustively, yet, it's unfinished. [Template here](https://mozillascience.github.io/working-open-workshop/contributing/)_
|
||||||
|
|
||||||
|
# Contributing to Squiggle
|
||||||
|
|
||||||
|
We welcome contributions from developers, especially people in react/typescript, rescript, and interpreters/parsers. We also are keen to hear issues filed by users!
|
||||||
|
|
||||||
|
Squiggle is currently pre-alpha.
|
||||||
|
|
||||||
|
# Quick links
|
||||||
|
|
||||||
|
- [Roadmap to the alpha](https://github.com/QURIresearch/squiggle/projects/2)
|
||||||
|
- The team presently communicates via the **EA Forecasting and Epistemics** slack (channels `#squiggle` and `#squiggle-ops`), you can track down an invite by reaching out to Ozzie Gooen
|
||||||
|
- [Squiggle documentation](https://www.squiggle-language.com/docs/Language)
|
||||||
|
- [Rescript documentation](https://rescript-lang.org/docs/manual/latest/introduction)
|
||||||
|
- You can email `quinn@quantifieduncertainty.org` if you need assistance in onboarding or if you have questions
|
||||||
|
|
||||||
|
# Bug reports
|
||||||
|
|
||||||
|
Anyone (with a github account) can file an issue at any time. Please allow Quinn, Sam, and Ozzie to triage, but otherwise just follow the suggestions in the issue templates.
|
||||||
|
|
||||||
|
# Project structure
|
||||||
|
|
||||||
|
Squiggle is a **monorepo** with four **packages**.
|
||||||
|
- **components** is where we improve reactive interfacing with Squiggle
|
||||||
|
- **playground** is the site `playground.squiggle-language.com`
|
||||||
|
- **squiggle-lang** is where the magic happens: probability distributions, the interpreter, etc.
|
||||||
|
- **website** is the site `squiggle-language.com`
|
||||||
|
|
||||||
|
# Deployment ops
|
||||||
|
|
||||||
|
We use netlify, and it should only concern Quinn, Sam, and Ozzie.
|
||||||
|
|
||||||
|
# Development environment, building, testing, dev server
|
||||||
|
|
||||||
|
You need `yarn`.
|
||||||
|
|
||||||
|
TODO: fill this out based on all the different packages scripts once they cool down.
|
||||||
|
|
||||||
|
# Pull request protocol
|
||||||
|
|
||||||
|
Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged.
|
||||||
|
|
43
README.md
43
README.md
|
@ -1,32 +1,43 @@
|
||||||
# Squiggle
|
# Squiggle
|
||||||
|
|
||||||
This is an experiment DSL/language for making probabilistic estimates.
|
This is an experiment DSL/language for making probabilistic estimates. The full story can be found [here](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3).
|
||||||
|
|
||||||
This monorepo has several packages that can be used for various purposes. All
|
This monorepo has several packages that can be used for various purposes. All
|
||||||
the packages can be found in `packages`.
|
the packages can be found in `packages`.
|
||||||
|
|
||||||
`@squiggle/lang` in `packages/squiggle-lang` contains the core language, particularly
|
- `@quri/squiggle-lang` in `packages/squiggle-lang` contains the core language, particularly
|
||||||
an interface to parse squiggle expressions and return descriptions of distributions
|
an interface to parse squiggle expressions and return descriptions of distributions
|
||||||
or results.
|
or results.
|
||||||
|
- `@quri/squiggle-components` in `packages/components` contains React components that
|
||||||
`@squiggle/components` in `packages/components` contains React components that
|
|
||||||
can be passed squiggle strings as props, and return a presentation of the result
|
can be passed squiggle strings as props, and return a presentation of the result
|
||||||
of the calculation.
|
of the calculation.
|
||||||
|
- `@quri/playground` in `packages/playground` contains a website for a playground
|
||||||
`@squiggle/playground` in `packages/playground` contains a website for a playground
|
|
||||||
for squiggle. This website is hosted at `playground.squiggle-language.com`
|
for squiggle. This website is hosted at `playground.squiggle-language.com`
|
||||||
|
- `@quri/squiggle-website` in `packages/website` The main descriptive website for squiggle,
|
||||||
`@squiggle/website` in `packages/website` The main descriptive website for squiggle,
|
|
||||||
it is hosted at `squiggle-language.com`.
|
it is hosted at `squiggle-language.com`.
|
||||||
|
|
||||||
The playground depends on the components library which then depends on the language.
|
The playground depends on the components library which then depends on the language. This means that if you wish to work on the components library, you will need to build (no need to bundle) the language, and as of this writing playground doesn't really work.
|
||||||
This means that if you wish to work on the components library, you will need
|
|
||||||
to package the language, and for the playground to work, you will need to package
|
|
||||||
the components library and the playground.
|
|
||||||
|
|
||||||
Scripts are available for you in the root directory to do important activities,
|
# Develop
|
||||||
such as:
|
|
||||||
|
|
||||||
`yarn build:lang`. Builds and packages the language
|
For any project in the repo, begin by running `yarn` in the top level (TODO: is this true?)
|
||||||
`yarn storybook:components`. Hosts the component storybook
|
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
See `packages/*/README.md` to work with whatever project you're interested in.
|
||||||
|
|
||||||
|
## `codium` for `rescript`
|
||||||
|
|
||||||
|
If you have `nix` installed with `flakes` enabled, you can build a `codium` in this repo for `rescript` development, if you don't want to pollute your machine's global editor with another mode/extension.
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
nix develop
|
||||||
|
codium
|
||||||
|
```
|
||||||
|
|
||||||
|
The `nix develop` shell also provides `yarn`.
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
See `CONTRIBUTING.md`.
|
||||||
|
|
9
flake-compat.nix
Normal file
9
flake-compat.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
let
|
||||||
|
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||||
|
inherit (lock.nodes.flake-compat.locked) owner repo rev narHash;
|
||||||
|
flake-compat = builtins.fetchTarball {
|
||||||
|
url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz";
|
||||||
|
sha256 = narHash;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
import flake-compat { src = ./.; }
|
44
flake.lock
Normal file
44
flake.lock
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1641205782,
|
||||||
|
"narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1647893727,
|
||||||
|
"narHash": "sha256-pOi7VdCb+s5Cwh5CS7YEZVRgH9uCmE87J5W7iXv29Ck=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1ec61dd4167f04be8d05c45780818826132eea0d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
93
flake.nix
Normal file
93
flake.nix
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
description = "Building codium for rescript development";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self
|
||||||
|
, nixpkgs
|
||||||
|
, flake-compat
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# Generate a user-friendly version number.
|
||||||
|
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||||
|
# System types to support.
|
||||||
|
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
|
||||||
|
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
# Nixpkgs instantiated for supported system types.
|
||||||
|
nixpkgsFor = forAllSystems (system:
|
||||||
|
import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [ self.overlay ];
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlay = final: prev: { };
|
||||||
|
# the default devShell used when running `nix develop`
|
||||||
|
devShell = forAllSystems (system: self.devShells.${system}.defaultShell);
|
||||||
|
devShells = forAllSystems (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor."${system}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# In case we don't want to provide an editor, this defaultShell will provide only coq packages we need.
|
||||||
|
defaultShell = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
yarn
|
||||||
|
yarn2nix
|
||||||
|
nodePackages.npm
|
||||||
|
nodejs
|
||||||
|
(pkgs.vscode-with-extensions.override {
|
||||||
|
vscode = pkgs.vscodium;
|
||||||
|
vscodeExtensions = pkgs.vscode-utils.extensionsFromVscodeMarketplace [
|
||||||
|
{
|
||||||
|
name = "rescript-vscode";
|
||||||
|
publisher = "chenglou92";
|
||||||
|
version = "1.2.1";
|
||||||
|
sha256 = "sha256-7/YakKtJ4WhgAR4rZltrq8g4TtM5QZ2spbrEUrNoXVg=";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "vim";
|
||||||
|
publisher = "vscodevim";
|
||||||
|
version = "1.22.2";
|
||||||
|
sha256 = "sha256-dtIlgODzRdoMKnG9050ZcCX3w15A/R3FaMc+ZylvBbU=";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "vscode-typescript-next";
|
||||||
|
publisher = "ms-vscode";
|
||||||
|
version = "4.7.20220323";
|
||||||
|
sha256 = "sha256-mjiBCyg5As/XAU9I5k6jEZWGJA3P6P5o1roe2bS7aUI=";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "nix-ide";
|
||||||
|
publisher = "jnoortheen";
|
||||||
|
version = "0.1.20";
|
||||||
|
sha256 = "sha256-Q6X41I68m0jaCXaQGEFOoAbSUrr/wFhfCH5KrduOtZo=";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "json";
|
||||||
|
publisher = "ZainChen";
|
||||||
|
version = "2.0.2";
|
||||||
|
sha256 = "sha256-nC3Q8KuCtn/jg1j/NaAxWGvnKe/ykrPm2PUjfsJz8aI=";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "prettier-vscode";
|
||||||
|
publisher = "esbenp";
|
||||||
|
version = "9.3.0";
|
||||||
|
sha256 = "sha256-hJgPjWf7a8+ltjmXTK8U/MwqgIZqBjmcCfHsAk2G3PA=";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,14 +2,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "squiggle",
|
"name": "squiggle",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:lang": "cd packages/squiggle-lang && yarn && yarn build && yarn package",
|
"nodeclean": "rm -r node_modules && rm -r packages/*/node_modules"
|
||||||
"storybook:components": "cd packages/components && yarn && yarn storybook",
|
|
||||||
"build-storybook:components": "cd packages/components && yarn && yarn build-storybook",
|
|
||||||
"build:components": "cd packages/components && yarn && yarn package",
|
|
||||||
"build:playground": "cd packages/playground && yarn && yarn parcel-build",
|
|
||||||
"ci:lang": "yarn workspace @squiggle/lang ci",
|
|
||||||
"ci:components": "yarn ci:lang && yarn workspace @squiggle/components ci",
|
|
||||||
"ci:playground": "yarn ci:components && yarn workspace @squiggle/playground ci"
|
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
9
packages/components/.npmignore
Normal file
9
packages/components/.npmignore
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
node_modules
|
||||||
|
storybook-static
|
||||||
|
public
|
||||||
|
build
|
||||||
|
.storybook
|
||||||
|
.direnv
|
||||||
|
.envrc
|
||||||
|
webpack.config.js
|
||||||
|
index.html
|
5
packages/components/.prettierignore
Normal file
5
packages/components/.prettierignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
node_modules
|
||||||
|
storybook-static
|
||||||
|
.storybook
|
1
packages/components/.prettierrc.json
Normal file
1
packages/components/.prettierrc.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -1,15 +1,11 @@
|
||||||
//const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
//const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
|
const custom = require('../webpack.config.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/* webpackFinal: async (config) => {
|
webpackFinal: async (config) => {
|
||||||
config.resolve.plugins = [
|
config.resolve.alias = custom.resolve.alias;
|
||||||
...(config.resolve.plugins || []),
|
return { ...config, module: { ...config.module, rules: config.module.rules.concat(custom.module.rules) } };
|
||||||
new TsconfigPathsPlugin({
|
},
|
||||||
extensions: config.resolve.extensions,
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
return config;
|
|
||||||
},*/
|
|
||||||
"stories": [
|
"stories": [
|
||||||
"../src/**/*.stories.mdx",
|
"../src/**/*.stories.mdx",
|
||||||
"../src/**/*.stories.@(js|jsx|ts|tsx)"
|
"../src/**/*.stories.@(js|jsx|ts|tsx)"
|
||||||
|
|
|
@ -1,6 +1,25 @@
|
||||||
# Squiggle Components
|
# Squiggle Components
|
||||||
|
This package contains all the components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/).
|
||||||
|
|
||||||
This package contains all the components for squiggle. These can be used either
|
# Build for development
|
||||||
as a library or hosted as a [storybook](https://storybook.js.org/).
|
We assume that you had run `yarn` at monorepo level, installing dependencies.
|
||||||
|
|
||||||
To run the storybook, run `yarn` then `yarn storybook`.
|
You need to _prepare_ by building and bundling `squiggle-lang`
|
||||||
|
``` sh
|
||||||
|
cd ../squiggle-lang
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
If you've otherwise done this recently you can skip those.
|
||||||
|
|
||||||
|
Run a development server
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|
||||||
|
And build artefacts for production,
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
yarn bundle # builds components library
|
||||||
|
yarn build # builds storybook app
|
||||||
|
```
|
||||||
|
|
57037
packages/components/package-lock.json
generated
57037
packages/components/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "@squiggle/components",
|
"name": "@quri/squiggle-components",
|
||||||
"version": "0.1.0",
|
"version": "0.1.6",
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squiggle/lang": "0.1.9",
|
"@quri/squiggle-lang": "0.2.2",
|
||||||
"@testing-library/jest-dom": "^5.16.2",
|
"@testing-library/jest-dom": "^5.16.2",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12.1.2",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
@ -27,10 +26,10 @@
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"storybook": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||||
"build-storybook": "build-storybook -s public",
|
"build": "build-storybook -s public",
|
||||||
"package": "tsc",
|
"bundle": "webpack",
|
||||||
"ci": "yarn package"
|
"all": "yarn bundle && yarn build"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
@ -69,11 +68,18 @@
|
||||||
"@storybook/node-logger": "^6.4.18",
|
"@storybook/node-logger": "^6.4.18",
|
||||||
"@storybook/preset-create-react-app": "^4.0.0",
|
"@storybook/preset-create-react-app": "^4.0.0",
|
||||||
"@storybook/react": "^6.4.18",
|
"@storybook/react": "^6.4.18",
|
||||||
"webpack": "^5.68.0"
|
"@types/webpack": "^5.28.0",
|
||||||
|
"prettier": "^2.6.0",
|
||||||
|
"react-codejar": "^1.1.2",
|
||||||
|
"ts-loader": "^9.2.8",
|
||||||
|
"webpack": "^5.70.0",
|
||||||
|
"webpack-cli": "^4.9.2",
|
||||||
|
"webpack-dev-server": "^4.7.4"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@types/react": "17.0.39"
|
"@types/react": "17.0.39"
|
||||||
},
|
},
|
||||||
"main": "dist/index.js",
|
"source": "./src/index.ts",
|
||||||
"types": "dist/index.d.ts"
|
"main": "dist/bundle.js",
|
||||||
|
"types": "dist/src/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta name="description" content="Squiggle components" />
|
||||||
name="description"
|
|
||||||
content="Squiggle components"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<title>Squiggle Components</title>
|
<title>Squiggle Components</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "squiggle-components";
|
|
||||||
buildInputs = with pkgs; [ nodePackages.yarn nodejs ];
|
|
||||||
}
|
|
|
@ -1,86 +1,96 @@
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import * as _ from 'lodash';
|
import _ from "lodash";
|
||||||
import type { Spec } from 'vega';
|
import type { Spec } from "vega";
|
||||||
import { run } from '@squiggle/lang';
|
import { run } from "@quri/squiggle-lang";
|
||||||
import type { DistPlus, SamplingInputs } from '@squiggle/lang';
|
import type {
|
||||||
import { createClassFromSpec } from 'react-vega';
|
DistPlus,
|
||||||
import * as chartSpecification from './spec-distributions.json'
|
SamplingInputs,
|
||||||
import * as percentilesSpec from './spec-pertentiles.json'
|
exportEnv,
|
||||||
|
exportDistribution,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
|
import { createClassFromSpec } from "react-vega";
|
||||||
|
import * as chartSpecification from "./spec-distributions.json";
|
||||||
|
import * as percentilesSpec from "./spec-percentiles.json";
|
||||||
|
|
||||||
let SquiggleVegaChart = createClassFromSpec({'spec': chartSpecification as Spec});
|
let SquiggleVegaChart = createClassFromSpec({
|
||||||
|
spec: chartSpecification as Spec,
|
||||||
|
});
|
||||||
|
|
||||||
let SquigglePercentilesChart = createClassFromSpec({'spec': percentilesSpec as Spec});
|
let SquigglePercentilesChart = createClassFromSpec({
|
||||||
|
spec: percentilesSpec as Spec,
|
||||||
|
});
|
||||||
|
|
||||||
export interface SquiggleChartProps {
|
export interface SquiggleChartProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
squiggleString : string,
|
squiggleString: string;
|
||||||
|
|
||||||
/** If the output requires monte carlo sampling, the amount of samples */
|
/** If the output requires monte carlo sampling, the amount of samples */
|
||||||
sampleCount? : number,
|
sampleCount?: number;
|
||||||
/** The amount of points returned to draw the distribution */
|
/** The amount of points returned to draw the distribution */
|
||||||
outputXYPoints? : number,
|
outputXYPoints?: number;
|
||||||
kernelWidth? : number,
|
kernelWidth?: number;
|
||||||
pointDistLength? : number,
|
pointDistLength?: number;
|
||||||
/** If the result is a function, where the function starts */
|
/** If the result is a function, where the function starts */
|
||||||
diagramStart? : number,
|
diagramStart?: number;
|
||||||
/** If the result is a function, where the function ends */
|
/** If the result is a function, where the function ends */
|
||||||
diagramStop? : number,
|
diagramStop?: number;
|
||||||
/** If the result is a function, how many points along the function it samples */
|
/** If the result is a function, how many points along the function it samples */
|
||||||
diagramCount? : number
|
diagramCount?: number;
|
||||||
|
/** variables declared before this expression */
|
||||||
|
environment?: exportEnv;
|
||||||
|
/** When the environment changes */
|
||||||
|
onEnvChange?(env: exportEnv): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SquiggleChart : React.FC<SquiggleChartProps> = props => {
|
export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
||||||
let samplingInputs : SamplingInputs = {
|
let samplingInputs: SamplingInputs = {
|
||||||
sampleCount : props.sampleCount,
|
sampleCount: props.sampleCount,
|
||||||
outputXYPoints : props.outputXYPoints,
|
outputXYPoints: props.outputXYPoints,
|
||||||
kernelWidth : props.kernelWidth,
|
kernelWidth: props.kernelWidth,
|
||||||
pointDistLength : props.pointDistLength
|
pointDistLength: props.pointDistLength,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let result = run(props.squiggleString, samplingInputs, props.environment);
|
||||||
let result = run(props.squiggleString, samplingInputs);
|
|
||||||
console.log(result)
|
|
||||||
if (result.tag === "Ok") {
|
if (result.tag === "Ok") {
|
||||||
let chartResults = result.value.map(chartResult => {
|
let environment = result.value.environment;
|
||||||
console.log(chartResult)
|
let exports = result.value.exports;
|
||||||
if(chartResult["NAME"] === "Float"){
|
if (props.onEnvChange) props.onEnvChange(environment);
|
||||||
|
let chartResults = exports.map((chartResult: exportDistribution) => {
|
||||||
|
if (chartResult["NAME"] === "Float") {
|
||||||
return <MakeNumberShower precision={3} number={chartResult["VAL"]} />;
|
return <MakeNumberShower precision={3} number={chartResult["VAL"]} />;
|
||||||
}
|
} else if (chartResult["NAME"] === "DistPlus") {
|
||||||
else if(chartResult["NAME"] === "DistPlus"){
|
|
||||||
let shape = chartResult.VAL.pointSetDist;
|
let shape = chartResult.VAL.pointSetDist;
|
||||||
if(shape.tag === "Continuous"){
|
if (shape.tag === "Continuous") {
|
||||||
let xyShape = shape.value.xyShape;
|
let xyShape = shape.value.xyShape;
|
||||||
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let cdf = xyShape.ys.map(y => {
|
let cdf = xyShape.ys.map((y) => {
|
||||||
total += y;
|
total += y;
|
||||||
return total / totalY;
|
return total / totalY;
|
||||||
})
|
});
|
||||||
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y ]) => ({cdf: (c * 100).toFixed(2) + "%", x: x, y: y}));
|
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
|
||||||
|
cdf: (c * 100).toFixed(2) + "%",
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return <SquiggleVegaChart data={{ con: values }} />;
|
||||||
<SquiggleVegaChart
|
} else if (shape.tag === "Discrete") {
|
||||||
data={{"con": values}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if(shape.tag === "Discrete"){
|
|
||||||
let xyShape = shape.value.xyShape;
|
let xyShape = shape.value.xyShape;
|
||||||
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let cdf = xyShape.ys.map(y => {
|
let cdf = xyShape.ys.map((y) => {
|
||||||
total += y;
|
total += y;
|
||||||
return total / totalY;
|
return total / totalY;
|
||||||
})
|
});
|
||||||
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x,y]) => ({cdf: (c * 100).toFixed(2) + "%", x: x, y: y}));
|
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
|
||||||
|
cdf: (c * 100).toFixed(2) + "%",
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return <SquiggleVegaChart data={{ dis: values }} />;
|
||||||
<SquiggleVegaChart
|
} else if (shape.tag === "Mixed") {
|
||||||
data={{"dis": values}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if(shape.tag === "Mixed"){
|
|
||||||
let discreteShape = shape.value.discrete.xyShape;
|
let discreteShape = shape.value.discrete.xyShape;
|
||||||
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
||||||
|
|
||||||
|
@ -89,141 +99,150 @@ export const SquiggleChart : React.FC<SquiggleChartProps> = props => {
|
||||||
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
||||||
|
|
||||||
interface labeledPoint {
|
interface labeledPoint {
|
||||||
x: number,
|
x: number;
|
||||||
y: number,
|
y: number;
|
||||||
type: "discrete" | "continuous"
|
type: "discrete" | "continuous";
|
||||||
};
|
}
|
||||||
|
|
||||||
let markedDisPoints : labeledPoint[] = discretePoints.map(([x,y]) => ({x: x, y: y, type: "discrete"}))
|
let markedDisPoints: labeledPoint[] = discretePoints.map(
|
||||||
let markedConPoints : labeledPoint[] = continuousPoints.map(([x,y]) => ({x: x, y: y, type: "continuous"}))
|
([x, y]) => ({ x: x, y: y, type: "discrete" })
|
||||||
|
);
|
||||||
|
let markedConPoints: labeledPoint[] = continuousPoints.map(
|
||||||
|
([x, y]) => ({ x: x, y: y, type: "continuous" })
|
||||||
|
);
|
||||||
|
|
||||||
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), 'x')
|
let sortedPoints = _.sortBy(
|
||||||
|
markedDisPoints.concat(markedConPoints),
|
||||||
|
"x"
|
||||||
|
);
|
||||||
|
|
||||||
let totalContinuous = 1 - totalDiscrete;
|
let totalContinuous = 1 - totalDiscrete;
|
||||||
let totalY = continuousShape.ys.reduce((a:number, b:number) => a + b);
|
let totalY = continuousShape.ys.reduce(
|
||||||
|
(a: number, b: number) => a + b
|
||||||
|
);
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let cdf = sortedPoints.map((point: labeledPoint) => {
|
let cdf = sortedPoints.map((point: labeledPoint) => {
|
||||||
if(point.type == "discrete") {
|
if (point.type == "discrete") {
|
||||||
total += point.y;
|
total += point.y;
|
||||||
return total;
|
return total;
|
||||||
}
|
} else if (point.type == "continuous") {
|
||||||
else if (point.type == "continuous") {
|
total += (point.y / totalY) * totalContinuous;
|
||||||
total += point.y / totalY * totalContinuous;
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface cdfLabeledPoint {
|
interface cdfLabeledPoint {
|
||||||
cdf: string,
|
cdf: string;
|
||||||
x: number,
|
x: number;
|
||||||
y: number,
|
y: number;
|
||||||
type: "discrete" | "continuous"
|
type: "discrete" | "continuous";
|
||||||
}
|
}
|
||||||
let cdfLabeledPoint : cdfLabeledPoint[] = _.zipWith(cdf, sortedPoints, (c: number, point: labeledPoint) => ({...point, cdf: (c * 100).toFixed(2) + "%"}))
|
let cdfLabeledPoint: cdfLabeledPoint[] = _.zipWith(
|
||||||
let continuousValues = cdfLabeledPoint.filter(x => x.type == "continuous")
|
cdf,
|
||||||
let discreteValues = cdfLabeledPoint.filter(x => x.type == "discrete")
|
sortedPoints,
|
||||||
|
(c: number, point: labeledPoint) => ({
|
||||||
|
...point,
|
||||||
|
cdf: (c * 100).toFixed(2) + "%",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
let continuousValues = cdfLabeledPoint.filter(
|
||||||
|
(x) => x.type == "continuous"
|
||||||
|
);
|
||||||
|
let discreteValues = cdfLabeledPoint.filter(
|
||||||
|
(x) => x.type == "discrete"
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SquiggleVegaChart
|
<SquiggleVegaChart
|
||||||
data={{"con": continuousValues, "dis": discreteValues}}
|
data={{ con: continuousValues, dis: discreteValues }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
} else if (chartResult.NAME === "Function") {
|
||||||
else if(chartResult.NAME === "Function"){
|
|
||||||
// We are looking at a function. In this case, we draw a Percentiles chart
|
// We are looking at a function. In this case, we draw a Percentiles chart
|
||||||
let start = props.diagramStart ? props.diagramStart : 0
|
let start = props.diagramStart ? props.diagramStart : 0;
|
||||||
let stop = props.diagramStop ? props.diagramStop : 10
|
let stop = props.diagramStop ? props.diagramStop : 10;
|
||||||
let count = props.diagramCount ? props.diagramCount : 0.1
|
let count = props.diagramCount ? props.diagramCount : 0.1;
|
||||||
let step = (stop - start)/ count
|
let step = (stop - start) / count;
|
||||||
let data = _.range(start, stop, step).map(x => {
|
let data = _.range(start, stop, step).map((x) => {
|
||||||
if(chartResult.NAME=="Function"){
|
if (chartResult.NAME == "Function") {
|
||||||
let result = chartResult.VAL(x);
|
let result = chartResult.VAL(x);
|
||||||
if(result.tag == "Ok"){
|
if (result.tag == "Ok") {
|
||||||
let percentileArray = [
|
let percentileArray = [
|
||||||
0.01,
|
0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95,
|
||||||
0.05,
|
0.99,
|
||||||
0.1,
|
];
|
||||||
0.2,
|
|
||||||
0.3,
|
|
||||||
0.4,
|
|
||||||
0.5,
|
|
||||||
0.6,
|
|
||||||
0.7,
|
|
||||||
0.8,
|
|
||||||
0.9,
|
|
||||||
0.95,
|
|
||||||
0.99
|
|
||||||
]
|
|
||||||
|
|
||||||
let percentiles = getPercentiles(percentileArray, result.value);
|
let percentiles = getPercentiles(percentileArray, result.value);
|
||||||
return {
|
return {
|
||||||
"x": x,
|
x: x,
|
||||||
"p1": percentiles[0],
|
p1: percentiles[0],
|
||||||
"p5": percentiles[1],
|
p5: percentiles[1],
|
||||||
"p10": percentiles[2],
|
p10: percentiles[2],
|
||||||
"p20": percentiles[3],
|
p20: percentiles[3],
|
||||||
"p30": percentiles[4],
|
p30: percentiles[4],
|
||||||
"p40": percentiles[5],
|
p40: percentiles[5],
|
||||||
"p50": percentiles[6],
|
p50: percentiles[6],
|
||||||
"p60": percentiles[7],
|
p60: percentiles[7],
|
||||||
"p70": percentiles[8],
|
p70: percentiles[8],
|
||||||
"p80": percentiles[9],
|
p80: percentiles[9],
|
||||||
"p90": percentiles[10],
|
p90: percentiles[10],
|
||||||
"p95": percentiles[11],
|
p95: percentiles[11],
|
||||||
"p99": percentiles[12]
|
p99: percentiles[12],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
})
|
});
|
||||||
return <SquigglePercentilesChart data={{"facet": data}} />
|
return <SquigglePercentilesChart data={{ facet: data }} />;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return <>{chartResults}</>;
|
return <>{chartResults}</>;
|
||||||
}
|
} else if (result.tag == "Error") {
|
||||||
else if(result.tag == "Error") {
|
|
||||||
// At this point, we came across an error. What was our error?
|
// At this point, we came across an error. What was our error?
|
||||||
return (<p>{"Error parsing Squiggle: " + result.value}</p>)
|
return <p>{"Error parsing Squiggle: " + result.value}</p>;
|
||||||
|
|
||||||
}
|
}
|
||||||
return (<p>{"Invalid Response"}</p>)
|
return <p>{"Invalid Response"}</p>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getPercentiles(percentiles:number[], t : DistPlus) {
|
function getPercentiles(percentiles: number[], t: DistPlus) {
|
||||||
if(t.pointSetDist.tag == "Discrete") {
|
if (t.pointSetDist.tag == "Discrete") {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs)
|
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
||||||
let bounds = percentiles.map(_ => maxX);
|
let bounds = percentiles.map((_) => maxX);
|
||||||
_.zipWith(t.pointSetDist.value.xyShape.xs,t.pointSetDist.value.xyShape.ys, (x,y) => {
|
_.zipWith(
|
||||||
total += y
|
t.pointSetDist.value.xyShape.xs,
|
||||||
|
t.pointSetDist.value.xyShape.ys,
|
||||||
|
(x, y) => {
|
||||||
|
total += y;
|
||||||
percentiles.forEach((v, i) => {
|
percentiles.forEach((v, i) => {
|
||||||
if(total > v && bounds[i] == maxX){
|
if (total > v && bounds[i] == maxX) {
|
||||||
bounds[i] = x
|
bounds[i] = x;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
});
|
||||||
return bounds;
|
|
||||||
}
|
}
|
||||||
else if(t.pointSetDist.tag == "Continuous"){
|
);
|
||||||
|
return bounds;
|
||||||
|
} else if (t.pointSetDist.tag == "Continuous") {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs)
|
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
||||||
let totalY = _.sum(t.pointSetDist.value.xyShape.ys)
|
let totalY = _.sum(t.pointSetDist.value.xyShape.ys);
|
||||||
let bounds = percentiles.map(_ => maxX);
|
let bounds = percentiles.map((_) => maxX);
|
||||||
_.zipWith(t.pointSetDist.value.xyShape.xs,t.pointSetDist.value.xyShape.ys, (x,y) => {
|
_.zipWith(
|
||||||
|
t.pointSetDist.value.xyShape.xs,
|
||||||
|
t.pointSetDist.value.xyShape.ys,
|
||||||
|
(x, y) => {
|
||||||
total += y / totalY;
|
total += y / totalY;
|
||||||
percentiles.forEach((v, i) => {
|
percentiles.forEach((v, i) => {
|
||||||
if(total > v && bounds[i] == maxX){
|
if (total > v && bounds[i] == maxX) {
|
||||||
bounds[i] = x
|
bounds[i] = x;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
});
|
||||||
return bounds;
|
|
||||||
}
|
}
|
||||||
else if(t.pointSetDist.tag == "Mixed"){
|
);
|
||||||
|
return bounds;
|
||||||
|
} else if (t.pointSetDist.tag == "Mixed") {
|
||||||
let discreteShape = t.pointSetDist.value.discrete.xyShape;
|
let discreteShape = t.pointSetDist.value.discrete.xyShape;
|
||||||
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
||||||
|
|
||||||
|
@ -232,80 +251,87 @@ function getPercentiles(percentiles:number[], t : DistPlus) {
|
||||||
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
||||||
|
|
||||||
interface labeledPoint {
|
interface labeledPoint {
|
||||||
x: number,
|
x: number;
|
||||||
y: number,
|
y: number;
|
||||||
type: "discrete" | "continuous"
|
type: "discrete" | "continuous";
|
||||||
};
|
}
|
||||||
|
|
||||||
let markedDisPoints : labeledPoint[] = discretePoints.map(([x,y]) => ({x: x, y: y, type: "discrete"}))
|
let markedDisPoints: labeledPoint[] = discretePoints.map(([x, y]) => ({
|
||||||
let markedConPoints : labeledPoint[] = continuousPoints.map(([x,y]) => ({x: x, y: y, type: "continuous"}))
|
x: x,
|
||||||
|
y: y,
|
||||||
|
type: "discrete",
|
||||||
|
}));
|
||||||
|
let markedConPoints: labeledPoint[] = continuousPoints.map(([x, y]) => ({
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
type: "continuous",
|
||||||
|
}));
|
||||||
|
|
||||||
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), 'x')
|
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), "x");
|
||||||
|
|
||||||
let totalContinuous = 1 - totalDiscrete;
|
let totalContinuous = 1 - totalDiscrete;
|
||||||
let totalY = continuousShape.ys.reduce((a:number, b:number) => a + b);
|
let totalY = continuousShape.ys.reduce((a: number, b: number) => a + b);
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let maxX = _.max(sortedPoints.map(x => x.x));
|
let maxX = _.max(sortedPoints.map((x) => x.x));
|
||||||
let bounds = percentiles.map(_ => maxX);
|
let bounds = percentiles.map((_) => maxX);
|
||||||
sortedPoints.map((point: labeledPoint) => {
|
sortedPoints.map((point: labeledPoint) => {
|
||||||
if(point.type == "discrete") {
|
if (point.type == "discrete") {
|
||||||
total += point.y;
|
total += point.y;
|
||||||
|
} else if (point.type == "continuous") {
|
||||||
|
total += (point.y / totalY) * totalContinuous;
|
||||||
}
|
}
|
||||||
else if (point.type == "continuous") {
|
percentiles.forEach((v, i) => {
|
||||||
total += point.y / totalY * totalContinuous;
|
if (total > v && bounds[i] == maxX) {
|
||||||
}
|
|
||||||
percentiles.forEach((v,i) => {
|
|
||||||
if(total > v && bounds[i] == maxX){
|
|
||||||
bounds[i] = total;
|
bounds[i] = total;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return total;
|
return total;
|
||||||
});
|
});
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function MakeNumberShower(props: {number: number, precision :number}){
|
function MakeNumberShower(props: { number: number; precision: number }) {
|
||||||
let numberWithPresentation = numberShow(props.number, props.precision);
|
let numberWithPresentation = numberShow(props.number, props.precision);
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{numberWithPresentation.value}
|
{numberWithPresentation.value}
|
||||||
{numberWithPresentation.symbol}
|
{numberWithPresentation.symbol}
|
||||||
{numberWithPresentation.power ?
|
{numberWithPresentation.power ? (
|
||||||
<span>
|
<span>
|
||||||
{'\u00b710'}
|
{"\u00b710"}
|
||||||
<span style={{fontSize: "0.6em", verticalAlign: "super"}}>
|
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
|
||||||
{numberWithPresentation.power}
|
{numberWithPresentation.power}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
: <></>}
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderOfMagnitudeNum = (n:number) => {
|
const orderOfMagnitudeNum = (n: number) => {
|
||||||
return Math.pow(10, n);
|
return Math.pow(10, n);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 105 -> 3
|
// 105 -> 3
|
||||||
const orderOfMagnitude = (n:number) => {
|
const orderOfMagnitude = (n: number) => {
|
||||||
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
|
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
|
||||||
};
|
};
|
||||||
|
|
||||||
function withXSigFigs(number:number, sigFigs:number) {
|
function withXSigFigs(number: number, sigFigs: number) {
|
||||||
const withPrecision = number.toPrecision(sigFigs);
|
const withPrecision = number.toPrecision(sigFigs);
|
||||||
const formatted = Number(withPrecision);
|
const formatted = Number(withPrecision);
|
||||||
return `${formatted}`;
|
return `${formatted}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NumberShower {
|
class NumberShower {
|
||||||
number: number
|
number: number;
|
||||||
precision: number
|
precision: number;
|
||||||
|
|
||||||
constructor(number:number, precision = 2) {
|
constructor(number: number, precision = 2) {
|
||||||
this.number = number;
|
this.number = number;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
}
|
}
|
||||||
|
@ -314,9 +340,9 @@ class NumberShower {
|
||||||
const number = Math.abs(this.number);
|
const number = Math.abs(this.number);
|
||||||
const response = this.evaluate(number);
|
const response = this.evaluate(number);
|
||||||
if (this.number < 0) {
|
if (this.number < 0) {
|
||||||
response.value = '-' + response.value;
|
response.value = "-" + response.value;
|
||||||
}
|
}
|
||||||
return response
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
metricSystem(number: number, order: number) {
|
metricSystem(number: number, order: number) {
|
||||||
|
@ -327,7 +353,7 @@ class NumberShower {
|
||||||
|
|
||||||
evaluate(number: number) {
|
evaluate(number: number) {
|
||||||
if (number === 0) {
|
if (number === 0) {
|
||||||
return { value: this.metricSystem(0, 0) }
|
return { value: this.metricSystem(0, 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
const order = orderOfMagnitude(number);
|
const order = orderOfMagnitude(number);
|
||||||
|
@ -336,13 +362,13 @@ class NumberShower {
|
||||||
} else if (order < 4) {
|
} else if (order < 4) {
|
||||||
return { value: this.metricSystem(number, 0) };
|
return { value: this.metricSystem(number, 0) };
|
||||||
} else if (order < 6) {
|
} else if (order < 6) {
|
||||||
return { value: this.metricSystem(number, 3), symbol: 'K' };
|
return { value: this.metricSystem(number, 3), symbol: "K" };
|
||||||
} else if (order < 9) {
|
} else if (order < 9) {
|
||||||
return { value: this.metricSystem(number, 6), symbol: 'M' };
|
return { value: this.metricSystem(number, 6), symbol: "M" };
|
||||||
} else if (order < 12) {
|
} else if (order < 12) {
|
||||||
return { value: this.metricSystem(number, 9), symbol: 'B' };
|
return { value: this.metricSystem(number, 9), symbol: "B" };
|
||||||
} else if (order < 15) {
|
} else if (order < 15) {
|
||||||
return { value: this.metricSystem(number, 12), symbol: 'T' };
|
return { value: this.metricSystem(number, 12), symbol: "T" };
|
||||||
} else {
|
} else {
|
||||||
return { value: this.metricSystem(number, order), power: order };
|
return { value: this.metricSystem(number, order), power: order };
|
||||||
}
|
}
|
||||||
|
|
120
packages/components/src/SquiggleEditor.tsx
Normal file
120
packages/components/src/SquiggleEditor.tsx
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
|
import { ReactCodeJar } from "react-codejar";
|
||||||
|
import type { exportEnv } from "@quri/squiggle-lang";
|
||||||
|
|
||||||
|
export interface SquiggleEditorProps {
|
||||||
|
/** The input string for squiggle */
|
||||||
|
initialSquiggleString?: string;
|
||||||
|
/** If the output requires monte carlo sampling, the amount of samples */
|
||||||
|
sampleCount?: number;
|
||||||
|
/** The amount of points returned to draw the distribution */
|
||||||
|
outputXYPoints?: number;
|
||||||
|
kernelWidth?: number;
|
||||||
|
pointDistLength?: number;
|
||||||
|
/** If the result is a function, where the function starts */
|
||||||
|
diagramStart?: number;
|
||||||
|
/** If the result is a function, where the function ends */
|
||||||
|
diagramStop?: number;
|
||||||
|
/** If the result is a function, how many points along the function it samples */
|
||||||
|
diagramCount?: number;
|
||||||
|
/** The environment, other variables that were already declared */
|
||||||
|
environment?: exportEnv;
|
||||||
|
/** when the environment changes. Used again for notebook magic*/
|
||||||
|
onEnvChange?(env: exportEnv): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const highlight = (editor: HTMLInputElement) => {
|
||||||
|
let code = editor.textContent;
|
||||||
|
code = code.replace(/\((\w+?)(\b)/g, '(<font color="#8a2be2">$1</font>$2');
|
||||||
|
editor.innerHTML = code;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SquiggleEditorState {
|
||||||
|
expression: string;
|
||||||
|
env: exportEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SquiggleEditor extends React.Component<
|
||||||
|
SquiggleEditorProps,
|
||||||
|
SquiggleEditorState
|
||||||
|
> {
|
||||||
|
constructor(props: SquiggleEditorProps) {
|
||||||
|
super(props);
|
||||||
|
let code = props.initialSquiggleString ? props.initialSquiggleString : "";
|
||||||
|
this.state = { expression: code, env: props.environment };
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let { expression, env } = this.state;
|
||||||
|
let props = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ReactCodeJar
|
||||||
|
code={expression}
|
||||||
|
onUpdate={(e) => {
|
||||||
|
this.setState({ expression: e });
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
borderRadius: "6px",
|
||||||
|
width: "530px",
|
||||||
|
border: "1px solid grey",
|
||||||
|
fontFamily: "'Source Code Pro', monospace",
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "400",
|
||||||
|
letterSpacing: "normal",
|
||||||
|
lineHeight: "20px",
|
||||||
|
padding: "10px",
|
||||||
|
tabSize: "4",
|
||||||
|
}}
|
||||||
|
highlight={highlight}
|
||||||
|
lineNumbers={false}
|
||||||
|
/>
|
||||||
|
<SquiggleChart
|
||||||
|
squiggleString={expression}
|
||||||
|
sampleCount={props.sampleCount}
|
||||||
|
outputXYPoints={props.outputXYPoints}
|
||||||
|
kernelWidth={props.kernelWidth}
|
||||||
|
pointDistLength={props.pointDistLength}
|
||||||
|
diagramStart={props.diagramStart}
|
||||||
|
diagramStop={props.diagramStop}
|
||||||
|
diagramCount={props.diagramCount}
|
||||||
|
environment={env}
|
||||||
|
onEnvChange={props.onEnvChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderSquiggleEditor(props: SquiggleEditorProps) {
|
||||||
|
let parent = document.createElement("div");
|
||||||
|
ReactDOM.render(
|
||||||
|
<SquiggleEditor
|
||||||
|
{...props}
|
||||||
|
onEnvChange={(env) => {
|
||||||
|
// Typescript complains on two levels here.
|
||||||
|
// - Div elements don't have a value property
|
||||||
|
// - Even if it did (like it was an input element), it would have to
|
||||||
|
// be a string
|
||||||
|
//
|
||||||
|
// Which are reasonable in most web contexts.
|
||||||
|
//
|
||||||
|
// However we're using observable, neither of those things have to be
|
||||||
|
// true there. div elements can contain the value property, and can have
|
||||||
|
// the value be any datatype they wish.
|
||||||
|
//
|
||||||
|
// This is here to get the 'viewof' part of:
|
||||||
|
// viewof env = cell('normal(0,1)')
|
||||||
|
// to work
|
||||||
|
// @ts-ignore
|
||||||
|
parent.value = env;
|
||||||
|
|
||||||
|
parent.dispatchEvent(new CustomEvent("input"));
|
||||||
|
if (props.onEnvChange) props.onEnvChange(env);
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
return parent;
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
export { SquiggleChart } from './SquiggleChart';
|
export { SquiggleChart } from "./SquiggleChart";
|
||||||
|
export { SquiggleEditor, renderSquiggleEditor } from "./SquiggleEditor";
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
"width": 500,
|
"width": 500,
|
||||||
"height": 200,
|
"height": 200,
|
||||||
"padding": 5,
|
"padding": 5,
|
||||||
"data": [{"name": "con"}, {"name": "dis"}],
|
"data": [{ "name": "con" }, { "name": "dis" }],
|
||||||
|
|
||||||
"signals": [
|
"signals": [
|
||||||
{
|
{
|
||||||
"name": "mousex",
|
"name": "mousex",
|
||||||
"description": "x position of mouse",
|
"description": "x position of mouse",
|
||||||
"update": "0",
|
"update": "0",
|
||||||
"on": [{"events": "mousemove", "update": "1-x()/width"}]
|
"on": [{ "events": "mousemove", "update": "1-x()/width" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "xscale",
|
"name": "xscale",
|
||||||
|
@ -35,86 +35,88 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
"scales": [{
|
"scales": [
|
||||||
|
{
|
||||||
"name": "xscale",
|
"name": "xscale",
|
||||||
"type": "pow",
|
"type": "pow",
|
||||||
"exponent": {"signal": "xscale"},
|
"exponent": { "signal": "xscale" },
|
||||||
"range": "width",
|
"range": "width",
|
||||||
"zero": false,
|
"zero": false,
|
||||||
"nice": false,
|
"nice": false,
|
||||||
"domain": {
|
"domain": {
|
||||||
"fields": [
|
"fields": [
|
||||||
{ "data": "con", "field": "x"},
|
{ "data": "con", "field": "x" },
|
||||||
{ "data": "dis", "field": "x"}
|
{ "data": "dis", "field": "x" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": "yscale",
|
"name": "yscale",
|
||||||
"type": "pow",
|
"type": "pow",
|
||||||
"exponent": {"signal": "yscale"},
|
"exponent": { "signal": "yscale" },
|
||||||
"range": "height",
|
"range": "height",
|
||||||
"nice": true,
|
"nice": true,
|
||||||
"zero": true,
|
"zero": true,
|
||||||
"domain": {
|
"domain": {
|
||||||
"fields": [
|
"fields": [
|
||||||
{ "data": "con", "field": "y"},
|
{ "data": "con", "field": "y" },
|
||||||
{ "data": "dis", "field": "y"}
|
{ "data": "dis", "field": "y" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
"axes": [
|
"axes": [
|
||||||
{"orient": "bottom", "scale": "xscale", "tickCount": 20},
|
{ "orient": "bottom", "scale": "xscale", "tickCount": 20 },
|
||||||
{"orient": "left", "scale": "yscale"}
|
{ "orient": "left", "scale": "yscale" }
|
||||||
],
|
],
|
||||||
|
|
||||||
"marks": [
|
"marks": [
|
||||||
{
|
{
|
||||||
"type": "area",
|
"type": "area",
|
||||||
"from": {"data": "con"},
|
"from": { "data": "con" },
|
||||||
"encode": {
|
"encode": {
|
||||||
"enter": {
|
"enter": {
|
||||||
"tooltip": {"signal": "datum.cdf"}
|
"tooltip": { "signal": "datum.cdf" }
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"x": {"scale": "xscale", "field": "x"},
|
"x": { "scale": "xscale", "field": "x" },
|
||||||
"y": {"scale": "yscale", "field": "y"},
|
"y": { "scale": "yscale", "field": "y" },
|
||||||
"y2": {"scale": "yscale", "value": 0},
|
"y2": { "scale": "yscale", "value": 0 },
|
||||||
"fill": {
|
"fill": {
|
||||||
"signal": "{gradient: 'linear', x1: 1, y1: 1, x2: 0, y2: 1, stops: [ {offset: 0.0, color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'blue'}, {offset: 1.0, color: 'blue'} ] }"
|
"signal": "{gradient: 'linear', x1: 1, y1: 1, x2: 0, y2: 1, stops: [ {offset: 0.0, color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'blue'}, {offset: 1.0, color: 'blue'} ] }"
|
||||||
},
|
},
|
||||||
"interpolate": {"value": "monotone"},
|
"interpolate": { "value": "monotone" },
|
||||||
"fillOpacity": {"value": 1}
|
"fillOpacity": { "value": 1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rect",
|
"type": "rect",
|
||||||
"from": {"data": "dis"},
|
"from": { "data": "dis" },
|
||||||
"encode": {
|
"encode": {
|
||||||
"enter": {
|
"enter": {
|
||||||
"y2": {"scale": "yscale", "value": 0},
|
"y2": { "scale": "yscale", "value": 0 },
|
||||||
"width": {"value": 1}
|
"width": { "value": 1 }
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"x": {"scale": "xscale", "field": "x"},
|
"x": { "scale": "xscale", "field": "x" },
|
||||||
"y": {"scale": "yscale", "field": "y"}
|
"y": { "scale": "yscale", "field": "y" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "symbol",
|
"type": "symbol",
|
||||||
"from": {"data": "dis"},
|
"from": { "data": "dis" },
|
||||||
"encode": {
|
"encode": {
|
||||||
"enter": {
|
"enter": {
|
||||||
"shape": {"value": "circle"},
|
"shape": { "value": "circle" },
|
||||||
"width": {"value": 5},
|
"width": { "value": 5 },
|
||||||
"tooltip": {"signal": "datum.y"}
|
"tooltip": { "signal": "datum.y" }
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"x": {"scale": "xscale", "field": "x"},
|
"x": { "scale": "xscale", "field": "x" },
|
||||||
"y": {"scale": "yscale", "field": "y"}
|
"y": { "scale": "yscale", "field": "y" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Meta } from '@storybook/addon-docs';
|
import { Meta } from "@storybook/addon-docs";
|
||||||
|
|
||||||
<Meta title="Squiggle/Introduction" />
|
<Meta title="Squiggle/Introduction" />
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { SquiggleChart } from '../SquiggleChart'
|
import { SquiggleChart } from "../SquiggleChart";
|
||||||
import { Canvas, Meta, Story, Props } from '@storybook/addon-docs';
|
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
|
||||||
|
|
||||||
<Meta title="Squiggle/SquiggleChart" component={ SquiggleChart } />
|
<Meta title="Squiggle/SquiggleChart" component={SquiggleChart} />
|
||||||
|
|
||||||
export const Template = SquiggleChart
|
export const Template = SquiggleChart;
|
||||||
|
|
||||||
# Squiggle Chart
|
# Squiggle Chart
|
||||||
|
|
||||||
|
@ -19,53 +19,62 @@ could be continuous, discrete or mixed.
|
||||||
## Distributions
|
## Distributions
|
||||||
|
|
||||||
An example of a normal distribution is:
|
An example of a normal distribution is:
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story
|
<Story
|
||||||
name="Normal"
|
name="Normal"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "normal(5,2)"
|
squiggleString: "normal(5,2)",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
|
||||||
An example of a Discrete distribution is:
|
An example of a Discrete distribution is:
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story
|
<Story
|
||||||
name="Discrete"
|
name="Discrete"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "mm(0, 1, [0.5, 0.5])"
|
squiggleString: "mm(0, 1, [0.5, 0.5])",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
An example of a Mixed distribution is:
|
An example of a Mixed distribution is:
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story
|
<Story
|
||||||
name="Mixed"
|
name="Mixed"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "mm(0, 5 to 10, [0.5, 0.5])"
|
squiggleString: "mm(0, 5 to 10, [0.5, 0.5])",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
## Constants
|
## Constants
|
||||||
|
|
||||||
A constant is a simple number as a result. This has special formatting rules
|
A constant is a simple number as a result. This has special formatting rules
|
||||||
to allow large and small numbers being printed cleanly.
|
to allow large and small numbers being printed cleanly.
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story
|
<Story
|
||||||
name="Constant"
|
name="Constant"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "500000 * 5000000"
|
squiggleString: "500000 * 5000000",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
|
|
||||||
Finally, a function can be returned, and this shows how the distribution changes
|
Finally, a function can be returned, and this shows how the distribution changes
|
||||||
over the axis between x = 0 and 10.
|
over the axis between x = 0 and 10.
|
||||||
|
|
||||||
|
@ -73,8 +82,9 @@ over the axis between x = 0 and 10.
|
||||||
<Story
|
<Story
|
||||||
name="Function"
|
name="Function"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "f(x) = normal(x,x)\nf"
|
squiggleString: "f(x) = normal(x,x)\nf",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
|
@ -1,18 +1,28 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@quri/squiggle-lang": ["../squiggle-lang/src/js"]
|
||||||
|
},
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
|
"resolveJsonModule": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"resolveJsonModule": true,
|
"composite": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"declarationDir": "./dist",
|
"declarationDir": "./dist",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
|
"files": ["src/spec-distributions.json","src/spec-percentiles.json"],
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*", "src/*"],
|
||||||
"exclude": ["node_modules", "**/*.spec.ts"]
|
"exclude": ["node_modules", "**/*.spec.ts"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../squiggle-lang"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
38
packages/components/webpack.config.js
Normal file
38
packages/components/webpack.config.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: "production",
|
||||||
|
devtool: "source-map",
|
||||||
|
entry: "./src/index.ts",
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: { projectReferences: true },
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".js", ".tsx", ".ts"],
|
||||||
|
alias: {
|
||||||
|
"@quri/squiggle-lang": path.resolve(__dirname, '../squiggle-lang/src/js')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "bundle.js",
|
||||||
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
library: {
|
||||||
|
name: "squiggle_components",
|
||||||
|
type: "umd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
static: {
|
||||||
|
directory: path.join(__dirname, "public"),
|
||||||
|
},
|
||||||
|
compress: true,
|
||||||
|
port: 9000,
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,9 +1,11 @@
|
||||||
|
# TODO: REVIVE PLAYGROUND.
|
||||||
|
|
||||||
# Squiggle Playground
|
# Squiggle Playground
|
||||||
|
|
||||||
This repository contains the squiggle playground, a small web interface
|
This repository contains the squiggle playground, a small web interface
|
||||||
for playing around with squiggle concepts.
|
for playing around with squiggle concepts.
|
||||||
|
|
||||||
It depends on `@squiggle/components` and `@squiggle/lang` so both of them will
|
It depends on `@quri/squiggle-components` and `@quri/squiggle-lang` so both of them will
|
||||||
need to be packaged for this to work. This can be done from the root directory
|
need to be packaged for this to work. This can be done from the root directory
|
||||||
with
|
with
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "@squiggle/playground",
|
"name": "@quri/squiggle-playground",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"homepage": "https://foretold-app.github.io/estiband/",
|
"homepage": "https://foretold-app.github.io/estiband/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.8.1",
|
"@emotion/react": "^11.8.1",
|
||||||
"@squiggle/lang": "^0.1.9",
|
"@quri/squiggle-lang": "^0.2.2",
|
||||||
"ace-builds": "^1.4.12",
|
"ace-builds": "^1.4.12",
|
||||||
"antd": "^4.18.5",
|
"antd": "^4.18.5",
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "squiggle";
|
|
||||||
buildInputs = with pkgs; [ yarn yarn2nix nodePackages.npm ];
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FC, useState } from "react"
|
import { FC, useState } from "react"
|
||||||
import { SquiggleChart } from "@squiggle/components"
|
import { SquiggleChart } from "@quri/squiggle-components"
|
||||||
import { CodeEditor } from "./CodeEditor"
|
import { CodeEditor } from "./CodeEditor"
|
||||||
import { Form, Input, Card, Row, Col } from "antd"
|
import { Form, Input, Card, Row, Col } from "antd"
|
||||||
import { css } from '@emotion/react'
|
import { css } from '@emotion/react'
|
||||||
|
|
1
packages/squiggle-lang/.gitignore
vendored
1
packages/squiggle-lang/.gitignore
vendored
|
@ -14,5 +14,6 @@ yarn-error.log
|
||||||
.netlify
|
.netlify
|
||||||
.idea
|
.idea
|
||||||
*.gen.ts
|
*.gen.ts
|
||||||
|
*.gen.tsx
|
||||||
*.gen.js
|
*.gen.js
|
||||||
dist
|
dist
|
||||||
|
|
11
packages/squiggle-lang/.npmignore
Normal file
11
packages/squiggle-lang/.npmignore
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
node_modules
|
||||||
|
shell.nix
|
||||||
|
.cache
|
||||||
|
.direnv
|
||||||
|
src
|
||||||
|
__tests__
|
||||||
|
lib
|
||||||
|
examples
|
||||||
|
yarn.nix
|
||||||
|
bsconfig.json
|
||||||
|
tsconfig.json
|
|
@ -1,9 +1,28 @@
|
||||||
|
# Squiggle language
|
||||||
|
|
||||||
|
# Build for development
|
||||||
|
We assume that you ran `yarn` at the monorepo level.
|
||||||
|
``` sh
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
`yarn bundle` is needed for a deployment.
|
||||||
|
|
||||||
|
Other:
|
||||||
|
``` sh
|
||||||
|
yarn start # listens to files and recompiles at every mutation
|
||||||
|
yarn test
|
||||||
|
yarn test:watch # keeps an active session and runs all tests at every mutation
|
||||||
|
```
|
||||||
|
|
||||||
|
# TODO: clean up this README.md
|
||||||
|
|
||||||
# Squiggle Language
|
# Squiggle Language
|
||||||
Squiggle is a language for representing probability distributions, as well as
|
Squiggle is a language for representing probability distributions, as well as
|
||||||
functions that return probability distributions. Its original intended use is
|
functions that return probability distributions. Its original intended use is
|
||||||
for improving epistemics around EA decisions.
|
for improving epistemics around EA decisions.
|
||||||
|
|
||||||
This package, @squiggle/lang, contains the core language of squiggle. The main
|
This package, @quri/squiggle-lang, contains the core language of squiggle. The main
|
||||||
feature revolves around evaluating squiggle expressions. Currently the package
|
feature revolves around evaluating squiggle expressions. Currently the package
|
||||||
only exports a single function, named "run", which from a squiggle string returns
|
only exports a single function, named "run", which from a squiggle string returns
|
||||||
an object representing the result of the evaluation.
|
an object representing the result of the evaluation.
|
||||||
|
|
|
@ -1,19 +1,34 @@
|
||||||
import { run } from '../src/js/index';
|
import { run } from '../src/js/index';
|
||||||
|
|
||||||
describe("A simple result", () => {
|
let testRun = (x: string) => {
|
||||||
|
let result = run(x)
|
||||||
|
if(result.tag == 'Ok'){
|
||||||
|
return { tag: 'Ok', value: result.value.exports }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Simple calculations and results", () => {
|
||||||
test("mean(normal(5,2))", () => {
|
test("mean(normal(5,2))", () => {
|
||||||
expect(run("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] })
|
expect(testRun("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] })
|
||||||
})
|
})
|
||||||
test("10+10", () => {
|
test("10+10", () => {
|
||||||
let foo = run("10 + 10")
|
let foo = testRun("10 + 10")
|
||||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 20 } ] })
|
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 20 } ] })
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
describe("Log function", () => {
|
||||||
test("log(1) = 0", () => {
|
test("log(1) = 0", () => {
|
||||||
let foo = run("log(1)")
|
let foo = testRun("log(1)")
|
||||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]})
|
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Multimodal too many weights error", () => {
|
||||||
test("mm(0,0,[0,0,0])", () => {
|
test("mm(0,0,[0,0,0])", () => {
|
||||||
let foo = run("mm(0,0,[0,0,0])")
|
let foo = testRun("mm(0,0,[0,0,0])")
|
||||||
expect(foo).toEqual({ "tag": "Error", "value": "Function multimodal error: Too many weights provided" })
|
expect(foo).toEqual({ "tag": "Error", "value": "Function multimodal error: Too many weights provided" })
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "@squiggle/lang",
|
"name": "@quri/squiggle-lang",
|
||||||
"reason": {},
|
"reason": {},
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
|
|
1368
packages/squiggle-lang/dist/index.js
vendored
1368
packages/squiggle-lang/dist/index.js
vendored
File diff suppressed because one or more lines are too long
393
packages/squiggle-lang/dist/report.html
vendored
393
packages/squiggle-lang/dist/report.html
vendored
File diff suppressed because one or more lines are too long
|
@ -1,18 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "@squiggle/lang",
|
"name": "@quri/squiggle-lang",
|
||||||
"version": "0.1.9",
|
"version": "0.2.2",
|
||||||
"homepage": "https://foretold-app.github.io/estiband/",
|
"homepage": "https://squiggle-language.com",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rescript build -with-deps",
|
"build": "rescript build -with-deps",
|
||||||
"parcel": "parcel build ./src/js/index.js --no-source-maps --no-autoinstall",
|
"bundle": "webpack",
|
||||||
"start": "rescript build -w -with-deps",
|
"start": "rescript build -w -with-deps",
|
||||||
"clean": "rescript clean",
|
"clean": "rescript clean",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:ci": "yarn jest ./__tests__/Lodash__test.re",
|
"test:watch": "jest --watchAll",
|
||||||
"watch:test": "jest --watchAll",
|
"all": "yarn build && yarn bundle && yarn test"
|
||||||
"watch:s": "yarn jest -- Converter_test --watch",
|
|
||||||
"package": "tsc",
|
|
||||||
"ci": "yarn build && yarn package"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Rescript"
|
"Rescript"
|
||||||
|
@ -21,27 +18,29 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@glennsl/bs-json": "^5.0.2",
|
"@glennsl/bs-json": "^5.0.2",
|
||||||
"@rescriptbr/reform": "^11.0.1",
|
"jstat": "^1.9.5",
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
|
||||||
"lodash": "4.17.15",
|
"lodash": "4.17.15",
|
||||||
"mathjs": "5.10.3",
|
"mathjs": "5.10.3",
|
||||||
"pdfast": "^0.2.0",
|
"pdfast": "^0.2.0",
|
||||||
"rationale": "0.2.0"
|
"rationale": "0.2.0",
|
||||||
|
"rescript": "^9.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@glennsl/rescript-jest": "^0.9.0",
|
"@glennsl/rescript-jest": "^0.9.0",
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.4.0",
|
||||||
|
"@types/webpack": "^5.28.0",
|
||||||
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||||
"docsify": "^4.12.2",
|
"docsify": "^4.12.2",
|
||||||
"gentype": "^4.3.0",
|
"gentype": "^4.3.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"jstat": "1.9.2",
|
|
||||||
"moduleserve": "0.9.1",
|
"moduleserve": "0.9.1",
|
||||||
"parcel": "^2.2.1",
|
|
||||||
"parcel-bundler": "1.12.4",
|
|
||||||
"rescript": "^9.1.4",
|
|
||||||
"ts-jest": "^27.1.3",
|
"ts-jest": "^27.1.3",
|
||||||
"typescript": "^4.5.5"
|
"ts-loader": "^9.2.8",
|
||||||
|
"typescript": "^4.5.5",
|
||||||
|
"webpack": "^5.70.0",
|
||||||
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"main": "./dist/js/index.js",
|
"source": "./src/js/index.ts",
|
||||||
|
"main": "./dist/bundle.js",
|
||||||
"types": "./dist/js/index.d.ts"
|
"types": "./dist/js/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "squiggle";
|
|
||||||
buildInputs = with pkgs; [ yarn yarn2nix nodePackages.npm ];
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
||||||
import type { Inputs_SamplingInputs_t as SamplingInputs } from '../rescript/ProgramEvaluator.gen';
|
import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen';
|
||||||
export type { SamplingInputs }
|
export type { SamplingInputs, exportEnv, exportDistribution }
|
||||||
export type {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen';
|
export type {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen';
|
||||||
|
|
||||||
export let defaultSamplingInputs : SamplingInputs = {
|
export let defaultSamplingInputs : SamplingInputs = {
|
||||||
|
@ -9,7 +9,9 @@ export let defaultSamplingInputs : SamplingInputs = {
|
||||||
pointDistLength : 1000
|
pointDistLength : 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
export function run(squiggleString : string, samplingInputs? : SamplingInputs) {
|
export function run(squiggleString : string, samplingInputs? : SamplingInputs, environment?: exportEnv) : { tag: "Ok"; value: exportType }
|
||||||
|
| { tag: "Error"; value: string } {
|
||||||
let si : SamplingInputs = samplingInputs ? samplingInputs : defaultSamplingInputs
|
let si : SamplingInputs = samplingInputs ? samplingInputs : defaultSamplingInputs
|
||||||
return runAll(squiggleString, si)
|
let env : exportEnv = environment ? environment : []
|
||||||
|
return runAll(squiggleString, si, env)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,20 @@ module Inputs = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type exportType = [
|
type exportDistribution = [
|
||||||
| #DistPlus(DistPlus.t)
|
| #DistPlus(DistPlus.t)
|
||||||
| #Float(float)
|
| #Float(float)
|
||||||
| #Function((float) => Belt.Result.t<DistPlus.t,string>)
|
| #Function((float) => Belt.Result.t<DistPlus.t,string>)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
type exportEnv = array<(string, ASTTypes.node)>
|
||||||
|
|
||||||
|
type exportType = {
|
||||||
|
environment : exportEnv,
|
||||||
|
exports: array<exportDistribution>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module Internals = {
|
module Internals = {
|
||||||
let addVariable = (
|
let addVariable = (
|
||||||
{samplingInputs, squiggleString, environment}: Inputs.inputs,
|
{samplingInputs, squiggleString, environment}: Inputs.inputs,
|
||||||
|
@ -71,40 +79,17 @@ module Internals = {
|
||||||
let runNode = (inputs, node) =>
|
let runNode = (inputs, node) =>
|
||||||
AST.toLeaf(makeInputs(inputs), inputs.environment, node)
|
AST.toLeaf(makeInputs(inputs), inputs.environment, node)
|
||||||
|
|
||||||
let runProgram = (inputs: Inputs.inputs, p: ASTTypes.program) => {
|
let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.node): result<
|
||||||
let ins = ref(inputs)
|
|
||||||
p
|
|
||||||
|> E.A.fmap(x =>
|
|
||||||
switch x {
|
|
||||||
| #Assignment(name, node) =>
|
|
||||||
ins := addVariable(ins.contents, name, node)
|
|
||||||
None
|
|
||||||
| #Expression(node) =>
|
|
||||||
Some(runNode(ins.contents, node) |> E.R.fmap(r => (ins.contents.environment, r)))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> E.A.O.concatSomes
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
}
|
|
||||||
|
|
||||||
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
|
||||||
Parser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
|
|
||||||
|
|
||||||
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
|
|
||||||
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.node): result<
|
|
||||||
ASTTypes.node,
|
ASTTypes.node,
|
||||||
string,
|
string,
|
||||||
> =>
|
> =>
|
||||||
node |> (
|
node |> (
|
||||||
x =>
|
x =>
|
||||||
switch x {
|
switch x {
|
||||||
| #Normalize(_) as n
|
| #Normalize(_) as n
|
||||||
| #SymbolicDist(_) as n =>
|
| #SymbolicDist(_) as n =>
|
||||||
#Render(n)
|
#Render(n)
|
||||||
|> Internals.runNode(inputs)
|
|> runNode(inputs)
|
||||||
|> (
|
|> (
|
||||||
x =>
|
x =>
|
||||||
switch x {
|
switch x {
|
||||||
|
@ -118,7 +103,10 @@ let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.node): result<
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let rec returnDist = (functionInfo : (array<string>, ASTTypes.node),
|
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
|
||||||
|
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
|
||||||
|
|
||||||
|
let rec returnDist = (functionInfo : (array<string>, ASTTypes.node),
|
||||||
inputs : Inputs.inputs,
|
inputs : Inputs.inputs,
|
||||||
env : ASTTypes.environment) => {
|
env : ASTTypes.environment) => {
|
||||||
(input : float) => {
|
(input : float) => {
|
||||||
|
@ -136,70 +124,80 @@ let rec returnDist = (functionInfo : (array<string>, ASTTypes.node),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
||||||
and coersionToExportedTypes = (
|
and coersionToExportedTypes = (
|
||||||
inputs,
|
inputs,
|
||||||
env: ASTTypes.environment,
|
env: ASTTypes.environment,
|
||||||
node: ASTTypes.node,
|
ex: ASTTypes.node,
|
||||||
): result<exportType, string> =>
|
): result<exportDistribution, string> =>
|
||||||
node
|
ex
|
||||||
|> renderIfNeeded(inputs)
|
|> renderIfNeeded(inputs)
|
||||||
|> E.R.bind(_, x =>
|
|> E.R.bind(_, x =>
|
||||||
switch x {
|
switch x {
|
||||||
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
||||||
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
||||||
| #RenderedDist(n) => Ok(#DistPlus(Internals.outputToDistPlus(inputs, n)))
|
| #RenderedDist(n) => Ok(#DistPlus(outputToDistPlus(inputs, n)))
|
||||||
| #Function(n) => Ok(#Function(returnDist(n, inputs, env)))
|
| #Function(n) => Ok(#Function(returnDist(n, inputs, env)))
|
||||||
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
|
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
and evaluateFunction = (
|
and evaluateFunction = (
|
||||||
inputs: Inputs.inputs,
|
inputs: Inputs.inputs,
|
||||||
fn: (array<string>, ASTTypes.node),
|
fn: (array<string>, ASTTypes.node),
|
||||||
fnInputs,
|
fnInputs,
|
||||||
) => {
|
) => {
|
||||||
let output = AST.runFunction(
|
let output = AST.runFunction(
|
||||||
Internals.makeInputs(inputs),
|
makeInputs(inputs),
|
||||||
inputs.environment,
|
inputs.environment,
|
||||||
fnInputs,
|
fnInputs,
|
||||||
fn,
|
fn,
|
||||||
)
|
)
|
||||||
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
||||||
|
}
|
||||||
|
|
||||||
|
let runProgram = (inputs: Inputs.inputs, p: ASTTypes.program) => {
|
||||||
|
let ins = ref(inputs)
|
||||||
|
p
|
||||||
|
|> E.A.fmap(x =>
|
||||||
|
switch x {
|
||||||
|
| #Assignment(name, node) =>
|
||||||
|
ins := addVariable(ins.contents, name, node)
|
||||||
|
None
|
||||||
|
| #Expression(node) =>
|
||||||
|
Some(runNode(ins.contents, node))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> E.A.O.concatSomes
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
|> E.R.bind(_, d =>
|
||||||
|
d
|
||||||
|
|> E.A.fmap(x => coersionToExportedTypes(inputs, ins.contents.environment, x))
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
)
|
||||||
|
|> E.R.fmap(ex =>
|
||||||
|
{
|
||||||
|
environment: Belt.Map.String.toArray(ins.contents.environment),
|
||||||
|
exports: ex
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
||||||
|
Parser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let rec mapM = (f, xs) =>
|
|
||||||
switch xs {
|
|
||||||
| [] => Ok([])
|
|
||||||
| arr =>
|
|
||||||
switch f(arr[0]) {
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
| Ok(val) =>
|
|
||||||
switch mapM(f, Belt.Array.sliceToEnd(arr, 1)) {
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
| Ok(restList) => Ok(Belt.Array.concat([val], restList))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let evaluateProgram = (inputs: Inputs.inputs) =>
|
|
||||||
inputs
|
|
||||||
|> Internals.inputsToLeaf
|
|
||||||
|> E.R.bind(_, xs => mapM(((a, b)) => coersionToExportedTypes(inputs, a, b), xs))
|
|
||||||
|
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let runAll = (squiggleString: string, samplingInputs: Inputs.SamplingInputs.t) => {
|
let runAll : (string, Inputs.SamplingInputs.t, exportEnv) => result<exportType,string> =
|
||||||
|
(squiggleString, samplingInputs, environment) => {
|
||||||
let inputs = Inputs.make(
|
let inputs = Inputs.make(
|
||||||
~samplingInputs,
|
~samplingInputs,
|
||||||
~squiggleString,
|
~squiggleString,
|
||||||
~environment=[]->Belt.Map.String.fromArray,
|
~environment=Belt.Map.String.fromArray(environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
let response1 = evaluateProgram(inputs);
|
Internals.inputsToLeaf(inputs)
|
||||||
response1
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
@genType
|
||||||
type rec hash = array<(string, node)>
|
type rec hash = array<(string, node)>
|
||||||
and node = [
|
and node = [
|
||||||
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
|
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
|
||||||
|
|
|
@ -297,7 +297,6 @@ let fromString2 = str => {
|
||||||
)
|
)
|
||||||
|
|
||||||
let value = E.R.bind(mathJsParse, MathAdtToDistDst.run)
|
let value = E.R.bind(mathJsParse, MathAdtToDistDst.run)
|
||||||
Js.log2(mathJsParse, value)
|
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ type triangular = {
|
||||||
high: float,
|
high: float,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
type symbolicDist = [
|
type symbolicDist = [
|
||||||
| #Normal(normal)
|
| #Normal(normal)
|
||||||
| #Beta(beta)
|
| #Beta(beta)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// This file has no dependencies. It's used outside of the interpreter, but the interpreter depends on it.
|
// This file has no dependencies. It's used outside of the interpreter, but the interpreter depends on it.
|
||||||
|
|
||||||
|
@genType
|
||||||
type algebraicOperation = [
|
type algebraicOperation = [
|
||||||
| #Add
|
| #Add
|
||||||
| #Multiply
|
| #Multiply
|
||||||
|
@ -7,6 +8,7 @@ type algebraicOperation = [
|
||||||
| #Divide
|
| #Divide
|
||||||
| #Exponentiate
|
| #Exponentiate
|
||||||
]
|
]
|
||||||
|
@genType
|
||||||
type pointwiseOperation = [#Add | #Multiply | #Exponentiate]
|
type pointwiseOperation = [#Add | #Multiply | #Exponentiate]
|
||||||
type scaleOperation = [#Multiply | #Exponentiate | #Log]
|
type scaleOperation = [#Multiply | #Exponentiate | #Log]
|
||||||
type distToFloatOperation = [
|
type distToFloatOperation = [
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"jsx": "react",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
|
@ -8,9 +9,10 @@
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"declarationDir": "./dist",
|
"declarationDir": "./dist",
|
||||||
"declaration": true
|
"declaration": true,
|
||||||
|
"composite": true
|
||||||
},
|
},
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
"exclude": ["node_modules", "**/*.spec.ts"]
|
"exclude": ["node_modules", "**/*.spec.ts", "webpack.config.js"]
|
||||||
}
|
}
|
||||||
|
|
26
packages/squiggle-lang/webpack.config.js
Normal file
26
packages/squiggle-lang/webpack.config.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: './src/js/index.ts',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: 'ts-loader',
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'bundle.js',
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
library: {
|
||||||
|
name: 'squiggle_lang',
|
||||||
|
type: 'umd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
|
@ -4,38 +4,32 @@ This website is built using [Docusaurus 2](https://docusaurus.io/), a modern sta
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```
|
``` sh
|
||||||
$ yarn
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
### Local Development
|
### Local Development
|
||||||
|
|
||||||
```
|
``` sh
|
||||||
$ yarn start
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
```
|
``` sh
|
||||||
$ yarn build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
||||||
|
|
||||||
### Deployment
|
### Clean
|
||||||
|
|
||||||
Using SSH:
|
Clean up the build artefacts.
|
||||||
|
``` sh
|
||||||
```
|
yarn clean
|
||||||
$ USE_SSH=true yarn deploy
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Not using SSH:
|
# TODO: unify formatting across `packages/*/README.md`
|
||||||
|
# TODO: build docs in `ci.yaml`.
|
||||||
```
|
|
||||||
$ GIT_USER=<Your GitHub username> yarn deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
|
||||||
|
|
|
@ -3,15 +3,10 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
|
||||||
"start": "docusaurus start",
|
"start": "docusaurus start",
|
||||||
"build": "docusaurus build",
|
"build": "docusaurus build",
|
||||||
"swizzle": "docusaurus swizzle",
|
"clean": "docusaurus clear",
|
||||||
"deploy": "docusaurus deploy",
|
"all": "yarn build"
|
||||||
"clear": "docusaurus clear",
|
|
||||||
"serve": "docusaurus serve",
|
|
||||||
"write-translations": "docusaurus write-translations",
|
|
||||||
"write-heading-ids": "docusaurus write-heading-ids"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-beta.15",
|
"@docusaurus/core": "2.0.0-beta.15",
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "squiggle-root";
|
|
||||||
buildInputs = with pkgs; [ nodePackages.yarn ];
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user