Merge branch 'develop' into reducer-dev
This commit is contained in:
commit
da37536b4b
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -24,6 +24,7 @@
|
|||
*.json @quinn-dougherty @Hazelfire @OAGr
|
||||
*.y*ml @quinn-dougherty @OAGr
|
||||
*.config.js @Hazelfire @OAGr
|
||||
netlify.toml @quinn-dougherty @OAGr @Hazelfire
|
||||
|
||||
# Documentation
|
||||
*.md @quinn-dougherty @OAGr @Hazelfire
|
||||
|
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ideas and feature requests - Squiggle Discussions on GitHub
|
||||
url: https://github.com/quantified-uncertainty/squiggle/discussions
|
||||
about: Please propose and discuss new features here. Remember to search for your idea before posting a new topic! Where would you like to see Squiggle go over the next few months, several months, or few years?
|
6
.github/ISSUE_TEMPLATE/future.md
vendored
6
.github/ISSUE_TEMPLATE/future.md
vendored
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
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
|
3
.github/ISSUE_TEMPLATE/ops-testing.md
vendored
3
.github/ISSUE_TEMPLATE/ops-testing.md
vendored
|
@ -6,7 +6,8 @@ labels: "ops & testing"
|
|||
|
||||
# Description:
|
||||
|
||||
<!-- delete this section if testing task or otherwise not applicable -->
|
||||
# The OS and version, yarn version, etc. in which this came up
|
||||
|
||||
<!-- delete this section if testing task or otherwise not applicable -->
|
||||
|
||||
# Desired behavior
|
||||
|
|
2
.github/ISSUE_TEMPLATE/user-bug.md
vendored
2
.github/ISSUE_TEMPLATE/user-bug.md
vendored
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: Bug reports for Squiggle users
|
||||
about: Rendering oddly, trouble with the playground, something like this?
|
||||
about: Rendering oddly? Is there a mathematical correctness problem?
|
||||
labels: "bug"
|
||||
---
|
||||
|
||||
|
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -4,14 +4,10 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
- production
|
||||
- staging
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- production
|
||||
- staging
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
|
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -62,7 +62,7 @@ jobs:
|
|||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
- name: Install dependencies
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
- name: Build rescript
|
||||
run: cd packages/squiggle-lang && yarn build
|
||||
|
|
11
README.md
11
README.md
|
@ -42,17 +42,6 @@ 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`.
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
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
44
flake.lock
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"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
|
||||
}
|
94
flake.nix
94
flake.nix
|
@ -1,94 +0,0 @@
|
|||
{
|
||||
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
|
||||
patchelf
|
||||
(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=";
|
||||
}
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
8
packages/components/netlify.toml
Normal file
8
packages/components/netlify.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[build]
|
||||
base = "packages/components/"
|
||||
command = "cd ../squiggle-lang && yarn build && cd ../components && yarn build"
|
||||
publish = "storybook-static/"
|
||||
ignore = "node -e 'process.exitCode = process.env.BRANCH.includes(\"dependabot\") ? 0 : 1' && git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../squiggle-lang"
|
||||
|
||||
[build.environment]
|
||||
NETLIFY_USE_YARN = "true"
|
|
@ -3,19 +3,20 @@
|
|||
"version": "0.1.8",
|
||||
"dependencies": {
|
||||
"@quri/squiggle-lang": "0.2.2",
|
||||
"@react-hook/size": "^2.1.2",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.0.1",
|
||||
"@testing-library/user-event": "^14.0.4",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.181",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/node": "^17.0.24",
|
||||
"@types/react": "^18.0.3",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.1",
|
||||
"antd": "^4.19.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.0.0",
|
||||
"react-ace": "9.5.0",
|
||||
"react-ace": "10.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-vega": "^7.5.0",
|
||||
|
@ -66,14 +67,14 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.16.7",
|
||||
"@storybook/addon-actions": "^6.4.20",
|
||||
"@storybook/addon-essentials": "^6.4.20",
|
||||
"@storybook/addon-links": "^6.4.20",
|
||||
"@storybook/builder-webpack5": "^6.4.20",
|
||||
"@storybook/manager-webpack5": "^6.4.20",
|
||||
"@storybook/node-logger": "^6.4.20",
|
||||
"@storybook/addon-actions": "^6.4.22",
|
||||
"@storybook/addon-essentials": "^6.4.22",
|
||||
"@storybook/addon-links": "^6.4.22",
|
||||
"@storybook/builder-webpack5": "^6.4.22",
|
||||
"@storybook/manager-webpack5": "^6.4.22",
|
||||
"@storybook/node-logger": "^6.4.22",
|
||||
"@storybook/preset-create-react-app": "^4.1.0",
|
||||
"@storybook/react": "^6.4.20",
|
||||
"@storybook/react": "^6.4.22",
|
||||
"@types/styled-components": "^5.1.24",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"react-codejar": "^1.1.2",
|
||||
|
|
|
@ -10,12 +10,16 @@ interface CodeEditorProps {
|
|||
onChange: (value: string) => void;
|
||||
oneLine?: boolean;
|
||||
width?: number;
|
||||
height: number;
|
||||
showGutter?: boolean;
|
||||
}
|
||||
|
||||
export let CodeEditor: FC<CodeEditorProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
oneLine = false,
|
||||
showGutter = false,
|
||||
height,
|
||||
}: CodeEditorProps) => {
|
||||
let lineCount = value.split("\n").length;
|
||||
let id = _.uniqueId();
|
||||
|
@ -25,9 +29,10 @@ export let CodeEditor: FC<CodeEditorProps> = ({
|
|||
mode="golang"
|
||||
theme="github"
|
||||
width={"100%"}
|
||||
minLines={oneLine ? lineCount : 15}
|
||||
maxLines={oneLine ? lineCount : 15}
|
||||
showGutter={false}
|
||||
height={String(height) + "px"}
|
||||
minLines={oneLine ? lineCount : undefined}
|
||||
maxLines={oneLine ? lineCount : undefined}
|
||||
showGutter={showGutter}
|
||||
highlightActiveLine={false}
|
||||
showPrintMargin={false}
|
||||
onChange={onChange}
|
||||
|
|
|
@ -27,7 +27,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
|||
return (
|
||||
<SquiggleVegaChart
|
||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||
width={width}
|
||||
width={width - 20}
|
||||
height={height}
|
||||
actions={false}
|
||||
/>
|
||||
|
|
|
@ -1,10 +1,117 @@
|
|||
import * as React from "react";
|
||||
import _ from "lodash";
|
||||
import { run, errorValueToString } from "@quri/squiggle-lang";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
run,
|
||||
errorValueToString,
|
||||
squiggleExpression,
|
||||
} from "@quri/squiggle-lang";
|
||||
import type { samplingParams, exportEnv } from "@quri/squiggle-lang";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { DistributionChart } from "./DistributionChart";
|
||||
import { ErrorBox } from "./ErrorBox";
|
||||
import useSize from "@react-hook/size";
|
||||
|
||||
const variableBox = {
|
||||
Component: styled.div`
|
||||
background: white;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 0.4em;
|
||||
`,
|
||||
Heading: styled.div`
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-left: 0.8em;
|
||||
padding-right: 0.8em;
|
||||
padding-top: 0.1em;
|
||||
`,
|
||||
Body: styled.div`
|
||||
padding: 0.4em 0.8em;
|
||||
`,
|
||||
};
|
||||
|
||||
export const VariableBox: React.FC<{
|
||||
heading: string;
|
||||
children: React.ReactNode;
|
||||
}> = ({ heading = "Error", children }) => {
|
||||
return (
|
||||
<variableBox.Component>
|
||||
<variableBox.Heading>
|
||||
<h3>{heading}</h3>
|
||||
</variableBox.Heading>
|
||||
<variableBox.Body>{children}</variableBox.Body>
|
||||
</variableBox.Component>
|
||||
);
|
||||
};
|
||||
|
||||
export interface SquiggleItemProps {
|
||||
/** The input string for squiggle */
|
||||
expression: squiggleExpression;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||
expression,
|
||||
width,
|
||||
height,
|
||||
}: SquiggleItemProps) => {
|
||||
switch (expression.tag) {
|
||||
case "number":
|
||||
return (
|
||||
<VariableBox heading="Number">
|
||||
<NumberShower precision={3} number={expression.value} />
|
||||
</VariableBox>
|
||||
);
|
||||
case "distribution": {
|
||||
let distType = expression.value.type();
|
||||
return (
|
||||
<VariableBox heading={`Distribution (${distType})`}>
|
||||
{distType === "Symbolic" ? (
|
||||
<>
|
||||
<div>{expression.value.toString()}</div>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<DistributionChart
|
||||
distribution={expression.value}
|
||||
height={height}
|
||||
width={width}
|
||||
/>
|
||||
</VariableBox>
|
||||
);
|
||||
}
|
||||
case "string":
|
||||
return (
|
||||
<VariableBox heading="String">{`"${expression.value}"`}</VariableBox>
|
||||
);
|
||||
case "boolean":
|
||||
return (
|
||||
<VariableBox heading="Boolean">
|
||||
{expression.value.toString()}
|
||||
</VariableBox>
|
||||
);
|
||||
case "symbol":
|
||||
return <VariableBox heading="Symbol">{expression.value}</VariableBox>;
|
||||
case "call":
|
||||
return <VariableBox heading="Call">{expression.value}</VariableBox>;
|
||||
case "array":
|
||||
return (
|
||||
<VariableBox heading="Array">
|
||||
{expression.value.map((r) => (
|
||||
<SquiggleItem expression={r} width={width - 20} height={50} />
|
||||
))}
|
||||
</VariableBox>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<ErrorBox heading="No Viewer">
|
||||
{"We don't currently have a working viewer for record types."}
|
||||
</ErrorBox>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export interface SquiggleChartProps {
|
||||
/** The input string for squiggle */
|
||||
|
@ -36,41 +143,33 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
|||
outputXYPoints = 1000,
|
||||
environment = [],
|
||||
onEnvChange = () => {},
|
||||
width = 500,
|
||||
height = 60,
|
||||
width = NaN,
|
||||
}: SquiggleChartProps) => {
|
||||
const target = React.useRef(null);
|
||||
const [componentWidth] = useSize(target);
|
||||
// I would have wanted to just use componentWidth, but this created infinite loops with SquiggleChart.stories.
|
||||
//So you can manually add a width, as an escape hatch.
|
||||
let _width = width || componentWidth;
|
||||
let samplingInputs: samplingParams = {
|
||||
sampleCount: sampleCount,
|
||||
xyPointLength: outputXYPoints,
|
||||
};
|
||||
|
||||
let expressionResult = run(squiggleString, samplingInputs, environment);
|
||||
let internal: JSX.Element;
|
||||
if (expressionResult.tag === "Ok") {
|
||||
onEnvChange(environment);
|
||||
let expression = expressionResult.value;
|
||||
if (expression.tag === "number") {
|
||||
return <NumberShower precision={3} number={expression.value} />;
|
||||
} else if (expression.tag === "distribution") {
|
||||
return (
|
||||
<DistributionChart
|
||||
distribution={expression.value}
|
||||
height={height}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ErrorBox heading="No Viewer">
|
||||
{"We don't currently have a viewer for this type: " + expression.tag}
|
||||
</ErrorBox>
|
||||
);
|
||||
}
|
||||
internal = (
|
||||
<SquiggleItem expression={expression} width={_width} height={height} />
|
||||
);
|
||||
} else {
|
||||
// At this point, we came across an error. What was our error?
|
||||
return (
|
||||
internal = (
|
||||
<ErrorBox heading={"Parse Error"}>
|
||||
{errorValueToString(expressionResult.value)}
|
||||
</ErrorBox>
|
||||
);
|
||||
}
|
||||
return <div ref={target}>{internal}</div>;
|
||||
};
|
||||
|
|
|
@ -55,6 +55,8 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
|||
value={expression}
|
||||
onChange={setExpression}
|
||||
oneLine={true}
|
||||
showGutter={false}
|
||||
height={20}
|
||||
/>
|
||||
</Input>
|
||||
<SquiggleChart
|
||||
|
|
|
@ -3,7 +3,8 @@ import React, { FC, useState } from "react";
|
|||
import ReactDOM from "react-dom";
|
||||
import { SquiggleChart } from "./SquiggleChart";
|
||||
import CodeEditor from "./CodeEditor";
|
||||
import { Form, Input, Card, Row, Col } from "antd";
|
||||
import { Form, Input, Row, Col } from "antd";
|
||||
import styled from "styled-components";
|
||||
import "antd/dist/antd.css";
|
||||
|
||||
interface FieldFloatProps {
|
||||
|
@ -34,9 +35,40 @@ function FieldFloat(Props: FieldFloatProps) {
|
|||
|
||||
interface Props {
|
||||
initialSquiggleString?: string;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
let SquigglePlayground: FC<Props> = ({ initialSquiggleString = "" }: Props) => {
|
||||
interface Props2 {
|
||||
height: number;
|
||||
}
|
||||
|
||||
const ShowBox = styled.div<Props2>`
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
height: ${(props) => props.height};
|
||||
`;
|
||||
|
||||
const MyComponent = styled.div`
|
||||
color: ${(props) => props.theme.colors.main};
|
||||
`;
|
||||
|
||||
interface TitleProps {
|
||||
readonly maxHeight: number;
|
||||
}
|
||||
|
||||
const Display = styled.div<TitleProps>`
|
||||
background: #f6f6f6;
|
||||
border-left: 1px solid #eee;
|
||||
height: 100vh;
|
||||
padding: 3px;
|
||||
overflow-y: auto;
|
||||
max-height: ${(props) => props.maxHeight}px;
|
||||
`;
|
||||
|
||||
let SquigglePlayground: FC<Props> = ({
|
||||
initialSquiggleString = "",
|
||||
height = 300,
|
||||
}: Props) => {
|
||||
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
||||
let [sampleCount, setSampleCount] = useState(1000);
|
||||
let [outputXYPoints, setOutputXYPoints] = useState(1000);
|
||||
|
@ -44,81 +76,34 @@ let SquigglePlayground: FC<Props> = ({ initialSquiggleString = "" }: Props) => {
|
|||
let [diagramStart, setDiagramStart] = useState(0);
|
||||
let [diagramStop, setDiagramStop] = useState(10);
|
||||
let [diagramCount, setDiagramCount] = useState(20);
|
||||
var demoDist = (
|
||||
<SquiggleChart
|
||||
squiggleString={squiggleString}
|
||||
sampleCount={sampleCount}
|
||||
outputXYPoints={outputXYPoints}
|
||||
diagramStart={diagramStart}
|
||||
diagramStop={diagramStop}
|
||||
diagramCount={diagramCount}
|
||||
pointDistLength={pointDistLength}
|
||||
height={150}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Card title="Distribution Form">
|
||||
<Form>
|
||||
<Row gutter={16}>
|
||||
<Col span={24}>
|
||||
<CodeEditor
|
||||
value={squiggleString}
|
||||
onChange={setSquiggleString}
|
||||
oneLine={false}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={sampleCount}
|
||||
label="Sample Count"
|
||||
onChange={setSampleCount}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={outputXYPoints}
|
||||
onChange={setOutputXYPoints}
|
||||
label="Output XY-points"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={pointDistLength}
|
||||
onChange={setPointDistLength}
|
||||
label="Downsample To"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={diagramStart}
|
||||
onChange={setDiagramStart}
|
||||
label="Diagram Start"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={diagramStop}
|
||||
onChange={setDiagramStop}
|
||||
label="Diagram Stop"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<FieldFloat
|
||||
value={diagramCount}
|
||||
onChange={setDiagramCount}
|
||||
label="Diagram Count"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>{demoDist}</Col>
|
||||
</Row>
|
||||
<ShowBox height={height}>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<CodeEditor
|
||||
value={squiggleString}
|
||||
onChange={setSquiggleString}
|
||||
oneLine={false}
|
||||
showGutter={true}
|
||||
height={height - 3}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Display maxHeight={height - 3}>
|
||||
<SquiggleChart
|
||||
squiggleString={squiggleString}
|
||||
sampleCount={sampleCount}
|
||||
outputXYPoints={outputXYPoints}
|
||||
diagramStart={diagramStart}
|
||||
diagramStop={diagramStop}
|
||||
diagramCount={diagramCount}
|
||||
pointDistLength={pointDistLength}
|
||||
height={150}
|
||||
/>
|
||||
</Display>
|
||||
</Col>
|
||||
</Row>
|
||||
</ShowBox>
|
||||
);
|
||||
};
|
||||
export default SquigglePlayground;
|
||||
|
|
|
@ -4,6 +4,11 @@ import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
|
|||
<Meta title="Squiggle/SquiggleChart" component={SquiggleChart} />
|
||||
|
||||
export const Template = SquiggleChart;
|
||||
/*
|
||||
We have to hardcode a width here, because otherwise some interaction with
|
||||
Storybook creates an infinite loop with the internal width
|
||||
*/
|
||||
const width = 600;
|
||||
|
||||
# Squiggle Chart
|
||||
|
||||
|
@ -18,13 +23,42 @@ could be continuous, discrete or mixed.
|
|||
|
||||
## Distributions
|
||||
|
||||
### Continuous Distributions
|
||||
### Continuous Distributions (Symbolic)
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Normal"
|
||||
name="Continuous Symbolic"
|
||||
args={{
|
||||
squiggleString: "normal(5,2)",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Continuous Distributions (PointSet)
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Continuous Pointset"
|
||||
args={{
|
||||
squiggleString: "toPointSet(normal(5,2))",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Continuous Distributions (SampleSet)
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Continuous SampleSet"
|
||||
args={{
|
||||
squiggleString: "toSampleSet(normal(5,2), 1000)",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
@ -38,6 +72,7 @@ could be continuous, discrete or mixed.
|
|||
name="Discrete"
|
||||
args={{
|
||||
squiggleString: "mx(0, 1, 3, 5, 8, 10, [0.1, 0.8, 0.5, 0.3, 0.2, 0.1])",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
@ -52,6 +87,7 @@ could be continuous, discrete or mixed.
|
|||
args={{
|
||||
squiggleString:
|
||||
"mx(0, 1, 3, 5, 8, normal(8, 1), [0.1, 0.3, 0.4, 0.35, 0.2, 0.8])",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
@ -68,23 +104,21 @@ to allow large and small numbers being printed cleanly.
|
|||
name="Constant"
|
||||
args={{
|
||||
squiggleString: "500000000",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Functions
|
||||
|
||||
Full functions can be returned. These plot out the results of distributions between a set of x-coordinates.
|
||||
|
||||
The default is show 10 points between 0 and 10.
|
||||
## Arrays
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Function"
|
||||
name="Array"
|
||||
args={{
|
||||
squiggleString: "f(x) = normal(x^2,(x+.1)^1.8)\nf",
|
||||
squiggleString: "[normal(5,2), normal(10,1), normal(40,2), 400000]",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
@ -98,6 +132,49 @@ The default is show 10 points between 0 and 10.
|
|||
name="Error"
|
||||
args={{
|
||||
squiggleString: "f(x) = normal(",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Booleans
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Boolean"
|
||||
args={{
|
||||
squiggleString: "3 == 3",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Records
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Record"
|
||||
args={{
|
||||
squiggleString: "{foo: 35 to 50, bar: [1,2,3]}",
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Strings
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="String"
|
||||
args={{
|
||||
squiggleString: '"Lucky day!"',
|
||||
width,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import SquigglePlayground from "../components/SquigglePlayground";
|
||||
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
|
||||
import styled from "styled-components";
|
||||
|
||||
<Meta title="Squiggle/SquigglePlayground" component={SquigglePlayground} />
|
||||
|
||||
|
@ -15,6 +16,7 @@ including sampling settings, in squiggle.
|
|||
name="Normal"
|
||||
args={{
|
||||
initialSquiggleString: "normal(5,2)",
|
||||
height: 500,
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
|
|
|
@ -19,12 +19,12 @@ describe("eval on distribution functions", () => {
|
|||
testEval("lognormal(5,2)", "Ok(Lognormal(5,2))")
|
||||
})
|
||||
describe("unaryMinus", () => {
|
||||
testEval("mean(-normal(5,2))", "Ok(-5.002887370380851)")
|
||||
testEval("mean(-normal(5,2))", "Ok(-5)")
|
||||
})
|
||||
describe("to", () => {
|
||||
testEval("5 to 2", "Error(TODO: Low value must be less than high value.)")
|
||||
testEval("to(2,5)", "Ok(Lognormal(1.1512925464970227,0.278507821238345))")
|
||||
testEval("to(-2,2)", "Ok(Normal(0,1.215913388057542))")
|
||||
testEval("to(2,5)", "Ok(Lognormal(1.1512925464970227,0.27853260523016377))")
|
||||
testEval("to(-2,2)", "Ok(Normal(0,1.2159136638235384))")
|
||||
})
|
||||
describe("mean", () => {
|
||||
testEval("mean(normal(5,2))", "Ok(5)")
|
||||
|
@ -45,10 +45,30 @@ describe("eval on distribution functions", () => {
|
|||
describe("add", () => {
|
||||
testEval("add(normal(5,2), normal(10,2))", "Ok(Normal(15,2.8284271247461903))")
|
||||
testEval("add(normal(5,2), lognormal(10,2))", "Ok(Sample Set Distribution)")
|
||||
testEval("add(normal(5,2), 3)", "Ok(Point Set Distribution)")
|
||||
testEval("add(3, normal(5,2))", "Ok(Point Set Distribution)")
|
||||
testEval("3+normal(5,2)", "Ok(Point Set Distribution)")
|
||||
testEval("normal(5,2)+3", "Ok(Point Set Distribution)")
|
||||
testEval("add(normal(5,2), 3)", "Ok(Normal(8,2))")
|
||||
testEval("add(3, normal(5,2))", "Ok(Normal(8,2))")
|
||||
testEval("3+normal(5,2)", "Ok(Normal(8,2))")
|
||||
testEval("normal(5,2)+3", "Ok(Normal(8,2))")
|
||||
})
|
||||
describe("subtract", () => {
|
||||
testEval("10 - normal(5, 1)", "Ok(Normal(5,1))")
|
||||
testEval("normal(5, 1) - 10", "Ok(Normal(-5,1))")
|
||||
})
|
||||
describe("multiply", () => {
|
||||
testEval("normal(10, 2) * 2", "Ok(Normal(20,4))")
|
||||
testEval("2 * normal(10, 2)", "Ok(Normal(20,4))")
|
||||
testEval("lognormal(5,2) * lognormal(10,2)", "Ok(Lognormal(15,2.8284271247461903))")
|
||||
testEval("lognormal(10, 2) * lognormal(5, 2)", "Ok(Lognormal(15,2.8284271247461903))")
|
||||
testEval("2 * lognormal(5, 2)", "Ok(Lognormal(5.693147180559945,2))")
|
||||
testEval("lognormal(5, 2) * 2", "Ok(Lognormal(5.693147180559945,2))")
|
||||
})
|
||||
describe("division", () => {
|
||||
testEval("lognormal(5,2) / lognormal(10,2)", "Ok(Lognormal(-5,2.8284271247461903))")
|
||||
testEval("lognormal(10,2) / lognormal(5,2)", "Ok(Lognormal(5,2.8284271247461903))")
|
||||
testEval("lognormal(5, 2) / 2", "Ok(Lognormal(4.306852819440055,2))")
|
||||
testEval("2 / lognormal(5, 2)", "Ok(Lognormal(-4.306852819440055,2))")
|
||||
testEval("2 / normal(10, 2)", "Ok(Point Set Distribution)")
|
||||
testEval("normal(10, 2) / 2", "Ok(Normal(5,1))")
|
||||
})
|
||||
describe("truncate", () => {
|
||||
testEval("truncateLeft(normal(5,2), 3)", "Ok(Point Set Distribution)")
|
||||
|
@ -101,6 +121,10 @@ describe("parse on distribution functions", () => {
|
|||
testParse("3 ^ normal(5,1)", "Ok((:pow 3 (:normal 5 1)))")
|
||||
testParse("normal(5,2) ^ 3", "Ok((:pow (:normal 5 2) 3))")
|
||||
})
|
||||
describe("subtraction", () => {
|
||||
testParse("10 - normal(5,1)", "Ok((:subtract 10 (:normal 5 1)))")
|
||||
testParse("normal(5,1) - 10", "Ok((:subtract (:normal 5 1) 10))")
|
||||
})
|
||||
describe("pointwise arithmetic expressions", () => {
|
||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||
testParse(
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
Constructors_cdf,
|
||||
Constructors_inv,
|
||||
Constructors_normalize,
|
||||
Constructors_isNormalized,
|
||||
Constructors_toPointSet,
|
||||
Constructors_toSampleSet,
|
||||
Constructors_truncate,
|
||||
|
@ -47,6 +48,7 @@ import {
|
|||
Constructors_pointwiseLogarithm,
|
||||
Constructors_pointwisePower,
|
||||
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
||||
import { pointSetDistFn } from "../rescript/OldInterpreter/DistPlus.bs";
|
||||
export type { samplingParams, errorValue };
|
||||
|
||||
export let defaultSamplingInputs: samplingParams = {
|
||||
|
@ -189,12 +191,20 @@ export class Distribution {
|
|||
return Constructors_inv({ env: this.env }, this.t, n);
|
||||
}
|
||||
|
||||
isNormalized(): result<boolean, distributionError> {
|
||||
return Constructors_isNormalized({ env: this.env }, this.t);
|
||||
}
|
||||
|
||||
normalize(): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_normalize({ env: this.env }, this.t)
|
||||
);
|
||||
}
|
||||
|
||||
type() {
|
||||
return this.t.tag;
|
||||
}
|
||||
|
||||
pointSet(): result<shape, distributionError> {
|
||||
let pointSet = toPointSet(
|
||||
this.t,
|
||||
|
|
|
@ -13,6 +13,7 @@ type outputType =
|
|||
| Dist(genericDist)
|
||||
| Float(float)
|
||||
| String(string)
|
||||
| Bool(bool)
|
||||
| GenDistError(error)
|
||||
|
||||
/*
|
||||
|
@ -66,6 +67,18 @@ module OutputLocal = {
|
|||
| e => Error(toErrorOrUnreachable(e))
|
||||
}
|
||||
|
||||
let toBool = (t: t) =>
|
||||
switch t {
|
||||
| Bool(d) => Some(d)
|
||||
| _ => None
|
||||
}
|
||||
|
||||
let toBoolR = (t: t): result<bool, error> =>
|
||||
switch t {
|
||||
| Bool(r) => Ok(r)
|
||||
| e => Error(toErrorOrUnreachable(e))
|
||||
}
|
||||
|
||||
//This is used to catch errors in other switch statements.
|
||||
let fromResult = (r: result<t, error>): outputType =>
|
||||
switch r {
|
||||
|
@ -107,8 +120,8 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
|
|||
(),
|
||||
)->OutputLocal.toDistR
|
||||
|
||||
let fromDistFn = (subFnName: GenericDist_Types.Operation.fromDist, dist: genericDist) =>
|
||||
switch subFnName {
|
||||
let fromDistFn = (subFnName: GenericDist_Types.Operation.fromDist, dist: genericDist) => {
|
||||
let response = switch subFnName {
|
||||
| ToFloat(distToFloatOperation) =>
|
||||
GenericDist.toFloatOperation(dist, ~toPointSetFn, ~distToFloatOperation)
|
||||
->E.R2.fmap(r => Float(r))
|
||||
|
@ -123,6 +136,7 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
|
|||
Dist(dist)
|
||||
}
|
||||
| ToDist(Normalize) => dist->GenericDist.normalize->Dist
|
||||
| ToBool(IsNormalized) => dist->GenericDist.isNormalized->Bool
|
||||
| ToDist(Truncate(leftCutoff, rightCutoff)) =>
|
||||
GenericDist.truncate(~toPointSetFn, ~leftCutoff, ~rightCutoff, dist, ())
|
||||
->E.R2.fmap(r => Dist(r))
|
||||
|
@ -154,6 +168,8 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
|
|||
->E.R2.fmap(r => Dist(r))
|
||||
->OutputLocal.fromResult
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
switch functionCallInfo {
|
||||
| FromDist(subFnName, dist) => fromDistFn(subFnName, dist)
|
||||
|
@ -201,6 +217,7 @@ module Constructors = {
|
|||
let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR
|
||||
let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR
|
||||
let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR
|
||||
let isNormalized = (~env, dist) => C.isNormalized(dist)->run(~env)->toBoolR
|
||||
let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR
|
||||
let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR
|
||||
let truncate = (~env, dist, leftCutoff, rightCutoff) =>
|
||||
|
|
|
@ -11,6 +11,7 @@ type outputType =
|
|||
| Dist(genericDist)
|
||||
| Float(float)
|
||||
| String(string)
|
||||
| Bool(bool)
|
||||
| GenDistError(error)
|
||||
|
||||
@genType
|
||||
|
@ -34,6 +35,8 @@ module Output: {
|
|||
let toFloatR: t => result<float, error>
|
||||
let toString: t => option<string>
|
||||
let toStringR: t => result<string, error>
|
||||
let toBool: t => option<bool>
|
||||
let toBoolR: t => result<bool, error>
|
||||
let toError: t => option<error>
|
||||
let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t
|
||||
}
|
||||
|
@ -52,6 +55,8 @@ module Constructors: {
|
|||
@genType
|
||||
let normalize: (~env: env, genericDist) => result<genericDist, error>
|
||||
@genType
|
||||
let isNormalized: (~env: env, genericDist) => result<bool, error>
|
||||
@genType
|
||||
let toPointSet: (~env: env, genericDist) => result<genericDist, error>
|
||||
@genType
|
||||
let toSampleSet: (~env: env, genericDist, int) => result<genericDist, error>
|
||||
|
|
|
@ -32,6 +32,15 @@ let normalize = (t: t): t =>
|
|||
| SampleSet(_) => t
|
||||
}
|
||||
|
||||
let integralEndY = (t: t): float =>
|
||||
switch t {
|
||||
| PointSet(r) => PointSetDist.T.integralEndY(r)
|
||||
| Symbolic(_) => 1.0
|
||||
| SampleSet(_) => 1.0
|
||||
}
|
||||
|
||||
let isNormalized = (t: t): bool => Js.Math.abs_float(integralEndY(t) -. 1.0) < 1e-7
|
||||
|
||||
let toFloatOperation = (
|
||||
t,
|
||||
~toPointSetFn: toPointSetFn,
|
||||
|
|
|
@ -15,6 +15,8 @@ let toString: t => string
|
|||
|
||||
let normalize: t => t
|
||||
|
||||
let isNormalized: t => bool
|
||||
|
||||
let toFloatOperation: (
|
||||
t,
|
||||
~toPointSetFn: toPointSetFn,
|
||||
|
|
|
@ -71,11 +71,14 @@ module Operation = {
|
|||
| ToString
|
||||
| ToSparkline(int)
|
||||
|
||||
type toBool = IsNormalized
|
||||
|
||||
type fromDist =
|
||||
| ToFloat(toFloat)
|
||||
| ToDist(toDist)
|
||||
| ToDistCombination(direction, arithmeticOperation, [#Dist(genericDist) | #Float(float)])
|
||||
| ToString(toString)
|
||||
| ToBool(toBool)
|
||||
|
||||
type singleParamaterFunction =
|
||||
| FromDist(fromDist)
|
||||
|
@ -101,6 +104,7 @@ module Operation = {
|
|||
| ToDist(Inspect) => `inspect`
|
||||
| ToString(ToString) => `toString`
|
||||
| ToString(ToSparkline(n)) => `toSparkline(${E.I.toString(n)})`
|
||||
| ToBool(IsNormalized) => `isNormalized`
|
||||
| ToDistCombination(Algebraic, _, _) => `algebraic`
|
||||
| ToDistCombination(Pointwise, _, _) => `pointwise`
|
||||
}
|
||||
|
@ -131,6 +135,7 @@ module Constructors = {
|
|||
let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist)
|
||||
let pdf = (dist, x): t => FromDist(ToFloat(#Pdf(x)), dist)
|
||||
let normalize = (dist): t => FromDist(ToDist(Normalize), dist)
|
||||
let isNormalized = (dist): t => FromDist(ToBool(IsNormalized), dist)
|
||||
let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist)
|
||||
let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist)
|
||||
let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist)
|
||||
|
|
|
@ -47,6 +47,7 @@ module Dist = (T: dist) => {
|
|||
let truncate = T.truncate
|
||||
let mean = T.mean
|
||||
let variance = T.variance
|
||||
let integralEndY = T.integralEndY
|
||||
|
||||
let updateIntegralCache = T.updateIntegralCache
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
open SymbolicDistTypes
|
||||
|
||||
let normal95confidencePoint = 1.6448536269514722
|
||||
// explained in website/docs/internal/ProcessingConfidenceIntervals
|
||||
|
||||
module Normal = {
|
||||
type t = normal
|
||||
let make = (mean: float, stdev: float): result<symbolicDist, string> =>
|
||||
|
@ -11,7 +14,7 @@ module Normal = {
|
|||
|
||||
let from90PercentCI = (low, high) => {
|
||||
let mean = E.A.Floats.mean([low, high])
|
||||
let stdev = (high -. low) /. (2. *. 1.644854)
|
||||
let stdev = (high -. low) /. (2. *. normal95confidencePoint)
|
||||
#Normal({mean: mean, stdev: stdev})
|
||||
}
|
||||
let inv = (p, t: t) => Jstat.Normal.inv(p, t.mean, t.stdev)
|
||||
|
@ -21,12 +24,12 @@ module Normal = {
|
|||
|
||||
let add = (n1: t, n2: t) => {
|
||||
let mean = n1.mean +. n2.mean
|
||||
let stdev = sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
|
||||
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
|
||||
#Normal({mean: mean, stdev: stdev})
|
||||
}
|
||||
let subtract = (n1: t, n2: t) => {
|
||||
let mean = n1.mean -. n2.mean
|
||||
let stdev = sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
|
||||
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
|
||||
#Normal({mean: mean, stdev: stdev})
|
||||
}
|
||||
|
||||
|
@ -44,6 +47,23 @@ module Normal = {
|
|||
| #Subtract => Some(subtract(n1, n2))
|
||||
| _ => None
|
||||
}
|
||||
|
||||
let operateFloatFirst = (operation: Operation.Algebraic.t, n1: float, n2: t) =>
|
||||
switch operation {
|
||||
| #Add => Some(#Normal({mean: n1 +. n2.mean, stdev: n2.stdev}))
|
||||
| #Subtract => Some(#Normal({mean: n1 -. n2.mean, stdev: n2.stdev}))
|
||||
| #Multiply => Some(#Normal({mean: n1 *. n2.mean, stdev: n1 *. n2.stdev}))
|
||||
| _ => None
|
||||
}
|
||||
|
||||
let operateFloatSecond = (operation: Operation.Algebraic.t, n1: t, n2: float) =>
|
||||
switch operation {
|
||||
| #Add => Some(#Normal({mean: n1.mean +. n2, stdev: n1.stdev}))
|
||||
| #Subtract => Some(#Normal({mean: n1.mean -. n2, stdev: n1.stdev}))
|
||||
| #Multiply => Some(#Normal({mean: n1.mean *. n2, stdev: n1.stdev *. n2}))
|
||||
| #Divide => Some(#Normal({mean: n1.mean /. n2, stdev: n1.stdev /. n2}))
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
||||
module Exponential = {
|
||||
|
@ -115,19 +135,22 @@ module Lognormal = {
|
|||
let mean = (t: t) => Ok(Jstat.Lognormal.mean(t.mu, t.sigma))
|
||||
let sample = (t: t) => Jstat.Lognormal.sample(t.mu, t.sigma)
|
||||
let toString = ({mu, sigma}: t) => j`Lognormal($mu,$sigma)`
|
||||
|
||||
let from90PercentCI = (low, high) => {
|
||||
let logLow = Js.Math.log(low)
|
||||
let logHigh = Js.Math.log(high)
|
||||
let mu = E.A.Floats.mean([logLow, logHigh])
|
||||
let sigma = (logHigh -. logLow) /. (2.0 *. 1.645)
|
||||
let sigma = (logHigh -. logLow) /. (2.0 *. normal95confidencePoint)
|
||||
#Lognormal({mu: mu, sigma: sigma})
|
||||
}
|
||||
let fromMeanAndStdev = (mean, stdev) => {
|
||||
// https://math.stackexchange.com/questions/2501783/parameters-of-a-lognormal-distribution
|
||||
// https://wikiless.org/wiki/Log-normal_distribution?lang=en#Generation_and_parameters
|
||||
if stdev > 0.0 {
|
||||
let variance = Js.Math.pow_float(~base=stdev, ~exp=2.0)
|
||||
let meanSquared = Js.Math.pow_float(~base=mean, ~exp=2.0)
|
||||
let mu = Js.Math.log(mean) -. 0.5 *. Js.Math.log(variance /. meanSquared +. 1.0)
|
||||
let sigma = Js.Math.pow_float(~base=Js.Math.log(variance /. meanSquared +. 1.0), ~exp=0.5)
|
||||
let variance = stdev ** 2.
|
||||
let meanSquared = mean ** 2.
|
||||
let mu = 2. *. Js.Math.log(mean) -. 0.5 *. Js.Math.log(variance +. meanSquared)
|
||||
let sigma = Js.Math.sqrt(Js.Math.log(variance /. meanSquared +. 1.))
|
||||
Ok(#Lognormal({mu: mu, sigma: sigma}))
|
||||
} else {
|
||||
Error("Lognormal standard deviation must be larger than 0")
|
||||
|
@ -135,15 +158,16 @@ module Lognormal = {
|
|||
}
|
||||
|
||||
let multiply = (l1, l2) => {
|
||||
// https://wikiless.org/wiki/Log-normal_distribution?lang=en#Multiplication_and_division_of_independent,_log-normal_random_variables
|
||||
let mu = l1.mu +. l2.mu
|
||||
let sigma = l1.sigma +. l2.sigma
|
||||
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
|
||||
#Lognormal({mu: mu, sigma: sigma})
|
||||
}
|
||||
let divide = (l1, l2) => {
|
||||
let mu = l1.mu -. l2.mu
|
||||
// We believe the ratiands will have covariance zero.
|
||||
// See here https://stats.stackexchange.com/questions/21735/what-are-the-mean-and-variance-of-the-ratio-of-two-lognormal-variables for details
|
||||
let sigma = l1.sigma +. l2.sigma
|
||||
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
|
||||
#Lognormal({mu: mu, sigma: sigma})
|
||||
}
|
||||
let operate = (operation: Operation.Algebraic.t, n1: t, n2: t) =>
|
||||
|
@ -152,6 +176,22 @@ module Lognormal = {
|
|||
| #Divide => Some(divide(n1, n2))
|
||||
| _ => None
|
||||
}
|
||||
|
||||
let operateFloatFirst = (operation: Operation.Algebraic.t, n1: float, n2: t) =>
|
||||
switch operation {
|
||||
| #Multiply =>
|
||||
n1 > 0.0 ? Some(#Lognormal({mu: Js.Math.log(n1) +. n2.mu, sigma: n2.sigma})) : None
|
||||
| #Divide => n1 > 0.0 ? Some(#Lognormal({mu: Js.Math.log(n1) -. n2.mu, sigma: n2.sigma})) : None
|
||||
| _ => None
|
||||
}
|
||||
|
||||
let operateFloatSecond = (operation: Operation.Algebraic.t, n1: t, n2: float) =>
|
||||
switch operation {
|
||||
| #Multiply =>
|
||||
n2 > 0.0 ? Some(#Lognormal({mu: n1.mu +. Js.Math.log(n2), sigma: n1.sigma})) : None
|
||||
| #Divide => n2 > 0.0 ? Some(#Lognormal({mu: n1.mu -. Js.Math.log(n2), sigma: n1.sigma})) : None
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
||||
module Uniform = {
|
||||
|
@ -343,8 +383,28 @@ module T = {
|
|||
}
|
||||
| (#Normal(v1), #Normal(v2)) =>
|
||||
Normal.operate(op, v1, v2) |> E.O.dimap(r => #AnalyticalSolution(r), () => #NoSolution)
|
||||
| (#Float(v1), #Normal(v2)) =>
|
||||
Normal.operateFloatFirst(op, v1, v2) |> E.O.dimap(
|
||||
r => #AnalyticalSolution(r),
|
||||
() => #NoSolution,
|
||||
)
|
||||
| (#Normal(v1), #Float(v2)) =>
|
||||
Normal.operateFloatSecond(op, v1, v2) |> E.O.dimap(
|
||||
r => #AnalyticalSolution(r),
|
||||
() => #NoSolution,
|
||||
)
|
||||
| (#Lognormal(v1), #Lognormal(v2)) =>
|
||||
Lognormal.operate(op, v1, v2) |> E.O.dimap(r => #AnalyticalSolution(r), () => #NoSolution)
|
||||
| (#Float(v1), #Lognormal(v2)) =>
|
||||
Lognormal.operateFloatFirst(op, v1, v2) |> E.O.dimap(
|
||||
r => #AnalyticalSolution(r),
|
||||
() => #NoSolution,
|
||||
)
|
||||
| (#Lognormal(v1), #Float(v2)) =>
|
||||
Lognormal.operateFloatSecond(op, v1, v2) |> E.O.dimap(
|
||||
r => #AnalyticalSolution(r),
|
||||
() => #NoSolution,
|
||||
)
|
||||
| _ => #NoSolution
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
module ExpressionValue = ReducerInterface_ExpressionValue
|
||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||
|
||||
let defaultSampleCount = 10000
|
||||
|
||||
let runGenericOperation = DistributionOperation.run(
|
||||
~env={
|
||||
sampleCount: 1000,
|
||||
sampleCount: defaultSampleCount,
|
||||
xyPointLength: 1000,
|
||||
},
|
||||
)
|
||||
|
@ -52,6 +54,13 @@ module Helpers = {
|
|||
FromDist(GenericDist_Types.Operation.ToString(fnCall), dist)->runGenericOperation->Some
|
||||
}
|
||||
|
||||
let toBoolFn = (
|
||||
fnCall: GenericDist_Types.Operation.toBool,
|
||||
dist: GenericDist_Types.genericDist,
|
||||
) => {
|
||||
FromDist(GenericDist_Types.Operation.ToBool(fnCall), dist)->runGenericOperation->Some
|
||||
}
|
||||
|
||||
let toDistFn = (fnCall: GenericDist_Types.Operation.toDist, dist) => {
|
||||
FromDist(GenericDist_Types.Operation.ToDist(fnCall), dist)->runGenericOperation->Some
|
||||
}
|
||||
|
@ -193,12 +202,16 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
|||
// https://mathjs.org/docs/reference/functions/exp.html
|
||||
Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some
|
||||
| ("normalize", [EvDistribution(dist)]) => Helpers.toDistFn(Normalize, dist)
|
||||
| ("isNormalized", [EvDistribution(dist)]) => Helpers.toBoolFn(IsNormalized, dist)
|
||||
| ("toPointSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToPointSet, dist)
|
||||
| ("cdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Cdf(float), dist)
|
||||
| ("pdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Pdf(float), dist)
|
||||
| ("inv", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Inv(float), dist)
|
||||
| ("toSampleSet", [EvDistribution(dist), EvNumber(float)]) =>
|
||||
Helpers.toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist)
|
||||
| ("toSampleSet", [EvDistribution(dist)]) =>
|
||||
Helpers.toDistFn(ToSampleSet(defaultSampleCount), dist)
|
||||
| ("inspect", [EvDistribution(dist)]) => Helpers.toDistFn(Inspect, dist)
|
||||
| ("truncateLeft", [EvDistribution(dist), EvNumber(float)]) =>
|
||||
Helpers.toDistFn(Truncate(Some(float), None), dist)
|
||||
| ("truncateRight", [EvDistribution(dist), EvNumber(float)]) =>
|
||||
|
@ -244,6 +257,7 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result<
|
|||
| Dist(d) => Ok(ReducerInterface_ExpressionValue.EvDistribution(d))
|
||||
| Float(d) => Ok(EvNumber(d))
|
||||
| String(d) => Ok(EvString(d))
|
||||
| Bool(d) => Ok(EvBool(d))
|
||||
| GenDistError(NotYetImplemented) => Error(RETodo("Function not yet implemented"))
|
||||
| GenDistError(Unreachable) => Error(RETodo("Unreachable"))
|
||||
| GenDistError(DistributionVerticalShiftIsInvalid) =>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Processing confidence intervals
|
||||
|
||||
This page explains what we are doing when we take a 95% confidence interval, and we get a mean and a standard deviation from it
|
||||
|
||||
## For normals
|
||||
|
||||
```js
|
||||
module Normal = {
|
||||
//...
|
||||
let from90PercentCI = (low, high) => {
|
||||
let mean = E.A.Floats.mean([low, high])
|
||||
let stdev = (high -. low) /. (2. *. 1.6448536269514722)
|
||||
#Normal({mean: mean, stdev: stdev})
|
||||
}
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
We know that for a normal with mean $\mu$ and standard deviation $\sigma$,
|
||||
|
||||
$$
|
||||
|
||||
a \cdot Normal(\mu, \sigma) = Normal(a\cdot \mu, |a|\cdot \sigma)
|
||||
|
||||
|
||||
$$
|
||||
|
||||
We can now look at the inverse cdf of a $Normal(0,1)$. We find that the 95% point is reached at $1.6448536269514722$. ([source](https://stackoverflow.com/questions/20626994/how-to-calculate-the-inverse-of-the-normal-cumulative-distribution-function-in-p)) This means that the 90% confidence interval is $[-1.6448536269514722, 1.6448536269514722]$, which has a width of $2 \cdot 1.6448536269514722$.
|
||||
|
||||
So then, if we take a $Normal(0,1)$ and we multiply it by $\frac{(high -. low)}{(2. *. 1.6448536269514722)}$, it's 90% confidence interval will be multiplied by the same amount. Then we just have to shift it by the mean to get our target normal.
|
||||
|
||||
## For lognormals
|
8
packages/website/netlify.toml
Normal file
8
packages/website/netlify.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[build]
|
||||
base = "packages/website/"
|
||||
command = "cd ../squiggle-lang && yarn build && cd ../website && yarn build"
|
||||
publish = "build/"
|
||||
ignore = "node -e 'process.exitCode = process.env.BRANCH.includes(\"dependabot\") ? 0 : 1' && git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ../"
|
||||
|
||||
[build.environment]
|
||||
NETLIFY_USE_YARN = "true"
|
22133
packages/website/package-lock.json
generated
22133
packages/website/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -20,7 +20,7 @@
|
|||
"react-dom": "^18.0.0",
|
||||
"remark-math": "^3",
|
||||
"rehype-katex": "^5",
|
||||
"hast-util-is-element": "1.1.0"
|
||||
"hast-util-is-element": "2.1.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
@ -8,12 +8,9 @@ export default function PlaygroundPage() {
|
|||
<div
|
||||
style={{
|
||||
maxWidth: 2000,
|
||||
paddingTop: "3em",
|
||||
margin: "0 auto",
|
||||
}}
|
||||
>
|
||||
<h2> Squiggle Playground </h2>
|
||||
<SquigglePlayground initialSquiggleString="normal(0,1)" />
|
||||
<SquigglePlayground initialSquiggleString="normal(0,1)" height={500} />
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user