Merge branch 'Umur-reducer-dev' into reducer-dev
18
README.md
|
@ -1,12 +1,22 @@
|
||||||
# Squiggle
|
# Squiggle
|
||||||
|
|
||||||
[![Packages check](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml/badge.svg)](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml)
|
[![Packages check](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml/badge.svg)](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml)
|
||||||
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
[![npm version - lang](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||||
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
[![npm version - components](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
||||||
[![codecov](https://codecov.io/gh/quantified-uncertainty/squiggle/branch/develop/graph/badge.svg?token=QRLBL5CQ7C)](https://codecov.io/gh/quantified-uncertainty/squiggle)
|
[![codecov](https://codecov.io/gh/quantified-uncertainty/squiggle/branch/develop/graph/badge.svg?token=QRLBL5CQ7C)](https://codecov.io/gh/quantified-uncertainty/squiggle)
|
||||||
|
|
||||||
This is an experimental DSL/language for making probabilistic estimates. The full story can be found [here](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3).
|
_An estimation language_.
|
||||||
|
|
||||||
|
## Get started
|
||||||
|
|
||||||
|
- [Gallery](https://www.squiggle-language.com/docs/Discussions/Gallery)
|
||||||
|
- [Squiggle playground](https://squiggle-language.com/playground)
|
||||||
|
- [Language basics](https://www.squiggle-language.com/docs/Features/Language)
|
||||||
|
- [Squiggle functions source of truth](https://www.squiggle-language.com/docs/Features/Functions)
|
||||||
|
- [Known bugs](https://www.squiggle-language.com/docs/Discussions/Bugs)
|
||||||
|
- [Original lesswrong sequence](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3)
|
||||||
|
- [Author your squiggle models as Observable notebooks](https://observablehq.com/@hazelfire/squiggle)
|
||||||
|
|
||||||
## Our deployments
|
## Our deployments
|
||||||
|
|
||||||
|
@ -27,7 +37,7 @@ the packages can be found in `packages`.
|
||||||
- `@quri/squiggle-components` in `packages/components` contains React components that
|
- `@quri/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/squiggle-website` in `packages/website` The main descriptive website for squiggle,
|
- `packages/website` is 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. 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.
|
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.
|
||||||
|
|
20
examples/decay.squiggle
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# The following code was provided by Nuño Sempere, it comes directly from the post https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3/p/j8o6sgRerE3tqNWdj
|
||||||
|
## Initial setup
|
||||||
|
yearly_probability_max = 0.95
|
||||||
|
yearly_probability_min = 0.66
|
||||||
|
period_probability_function(epsilon, yearly_probability) = 1 - (1 - yearly_probability) ^ (1 / epsilon)
|
||||||
|
probability_decayed(t, time_periods, period_probability) = 1 - (1 - period_probability) ^ (time_periods - t)
|
||||||
|
|
||||||
|
## Monthly decomposition
|
||||||
|
months_in_a_year=12
|
||||||
|
|
||||||
|
monthly_probability_min = period_probability_function(months_in_a_year, yearly_probability_min)
|
||||||
|
monthly_probability_max = period_probability_function(months_in_a_year, yearly_probability_max)
|
||||||
|
|
||||||
|
probability_decayed_monthly_min(t) = probability_decayed(t, months_in_a_year, monthly_probability_min)
|
||||||
|
probability_decayed_monthly_max(t) = probability_decayed(t, months_in_a_year, monthly_probability_max)
|
||||||
|
probability_decayed_monthly(t) = probability_decayed_monthly_min(t) to probability_decayed_monthly_max(t)
|
||||||
|
|
||||||
|
probability_decayed_monthly
|
||||||
|
## probability_decayed_monthly(6)
|
||||||
|
## mean(probability_decayed_monthly(6))
|
38
examples/givedirectly.squiggle
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# This is a cost effectiveness analysis of givedirectly, originally done by givewell, and translated into Squiggle by Sam Nolan
|
||||||
|
donation_size = 10000
|
||||||
|
proportion_of_funding_available = beta(10, 2)
|
||||||
|
total_funding_available = donation_size * proportion_of_funding_available
|
||||||
|
household_size = 3.7 to 5.7
|
||||||
|
size_of_transfer = 800 to 1200
|
||||||
|
size_of_transfer_per_person = size_of_transfer / household_size
|
||||||
|
|
||||||
|
portion_invested = 0.3 to 0.5
|
||||||
|
amount_invested = portion_invested * size_of_transfer_per_person
|
||||||
|
amount_consumed = (1 - portion_invested) * size_of_transfer_per_person
|
||||||
|
return_on_investment = 0.08 to 0.12
|
||||||
|
increase_in_consumption_from_investments = return_on_investment * amount_invested
|
||||||
|
baseline_consumption = 200 to 350
|
||||||
|
log_increase_in_consumption = log(amount_consumed + baseline_consumption) + log(baseline_consumption)
|
||||||
|
log_increase_in_consumption_from_investment = log(increase_in_consumption_from_investments + baseline_consumption) + log(baseline_consumption)
|
||||||
|
investment_duration = 8 to 12
|
||||||
|
discount_rate = beta(1.004, 20)
|
||||||
|
|
||||||
|
present_value_excluding_last_year = log_increase_in_consumption_from_investment * (1 - (1 + discount_rate) ^ (-investment_duration)) / (log(1 + discount_rate))
|
||||||
|
|
||||||
|
percent_of_investment_returned = 0.15 to 0.25
|
||||||
|
|
||||||
|
pv_consumption_last_year = (log(baseline_consumption + amount_invested * (return_on_investment + percent_of_investment_returned)) - log(baseline_consumption)) / (1 + discount_rate)^investment_duration
|
||||||
|
|
||||||
|
total_pv_of_cash_transfer = pv_consumption_last_year + present_value_excluding_last_year + log_increase_in_consumption
|
||||||
|
|
||||||
|
discount_negative_spoiler = 0.03 to 0.07
|
||||||
|
|
||||||
|
value_discounting_spoiler = discount_negative_spoiler * total_pv_of_cash_transfer
|
||||||
|
|
||||||
|
consumption_increase_per_household = value_discounting_spoiler * household_size
|
||||||
|
|
||||||
|
amount_of_transfers_made = total_funding_available / size_of_transfer
|
||||||
|
|
||||||
|
total_increase_in_ln_consumption = amount_of_transfers_made * consumption_increase_per_household
|
||||||
|
|
||||||
|
total_increase_in_ln_consumption
|
3
examples/wholenumberassignmentevaluation.squiggle
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
xY1 = 99
|
||||||
|
aBa3 = xY1 * 2 + 1
|
||||||
|
aBa3 * xY1 + aBa3
|
|
@ -1,8 +1,26 @@
|
||||||
|
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||||
|
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
||||||
|
|
||||||
# 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 as a library or hosted as a [storybook](https://storybook.js.org/).
|
||||||
|
|
||||||
# Build for development
|
# Usage in a `react` project
|
||||||
|
|
||||||
|
For example, in a fresh `create-react-app` project
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @quri/squiggle-components
|
||||||
|
```
|
||||||
|
|
||||||
|
Add to `App.js`:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { SquiggleEditor } from "@quri/squiggle-components";
|
||||||
|
<SquiggleEditor initialSquiggleString="x = beta(3, 10); x + 20" />;
|
||||||
|
```
|
||||||
|
|
||||||
|
# Build storybook for development
|
||||||
|
|
||||||
We assume that you had run `yarn` at monorepo level, installing dependencies.
|
We assume that you had run `yarn` at monorepo level, installing dependencies.
|
||||||
|
|
||||||
|
@ -24,6 +42,5 @@ yarn start
|
||||||
And build artefacts for production,
|
And build artefacts for production,
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn bundle # builds components library
|
|
||||||
yarn build # builds storybook app
|
yarn build # builds storybook app
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
{
|
{
|
||||||
"name": "@quri/squiggle-components",
|
"name": "@quri/squiggle-components",
|
||||||
"version": "0.2.9",
|
"version": "0.2.14",
|
||||||
"licence": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"antd": "^4.20.1",
|
|
||||||
"react-ace": "10.1.0",
|
"react-ace": "10.1.0",
|
||||||
|
"@quri/squiggle-lang": "^0.2.7",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"vega": "^5.22.1",
|
||||||
|
"vega-embed": "^6.20.6",
|
||||||
|
"vega-lite": "^5.2.0",
|
||||||
|
"react-vega": "^7.5.0",
|
||||||
|
"react": "^18.1.0",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"styled-components": "^5.3.5"
|
"styled-components": "^5.3.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -26,31 +32,25 @@
|
||||||
"webpack": "^5.72.0",
|
"webpack": "^5.72.0",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.2",
|
||||||
"webpack-dev-server": "^4.8.1",
|
"webpack-dev-server": "^4.8.1",
|
||||||
"@quri/squiggle-lang": "0.2.5",
|
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.1.1",
|
"@testing-library/react": "^13.1.1",
|
||||||
"@testing-library/user-event": "^14.1.1",
|
"@testing-library/user-event": "^14.1.1",
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.4.0",
|
||||||
|
"web-vitals": "^2.1.4",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^17.0.29",
|
"@types/node": "^17.0.29",
|
||||||
"@types/react": "^18.0.3",
|
"@types/react": "^18.0.3",
|
||||||
"@types/react-dom": "^18.0.2",
|
"@types/react-dom": "^18.0.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"react": "^18.1.0",
|
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-vega": "^7.5.0",
|
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"vega": "^5.22.1",
|
|
||||||
"vega-embed": "^6.20.6",
|
|
||||||
"vega-lite": "^5.2.0",
|
|
||||||
"web-vitals": "^2.1.4",
|
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "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": "tsc -b && build-storybook -s public",
|
"build": "tsc -b && build-storybook -s public",
|
||||||
|
"build:package": "tsc -b",
|
||||||
"bundle": "webpack",
|
"bundle": "webpack",
|
||||||
"all": "yarn bundle && yarn build",
|
"all": "yarn bundle && yarn build",
|
||||||
"lint": "prettier --check .",
|
"lint": "prettier --check .",
|
||||||
|
@ -88,6 +88,7 @@
|
||||||
"@types/react": "17.0.43"
|
"@types/react": "17.0.43"
|
||||||
},
|
},
|
||||||
"source": "./src/index.ts",
|
"source": "./src/index.ts",
|
||||||
"main": "dist/bundle.js",
|
"browser": "dist/bundle.js",
|
||||||
|
"main": "dist/src/index.js",
|
||||||
"types": "dist/src/index.d.ts"
|
"types": "dist/src/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { distributionErrorToString } from "@quri/squiggle-lang";
|
||||||
import { createClassFromSpec } from "react-vega";
|
import { createClassFromSpec } from "react-vega";
|
||||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
let SquiggleVegaChart = createClassFromSpec({
|
let SquiggleVegaChart = createClassFromSpec({
|
||||||
spec: chartSpecification as Spec,
|
spec: chartSpecification as Spec,
|
||||||
|
@ -24,19 +25,21 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
}: DistributionChartProps) => {
|
}: DistributionChartProps) => {
|
||||||
let shape = distribution.pointSet();
|
let shape = distribution.pointSet();
|
||||||
if (shape.tag === "Ok") {
|
if (shape.tag === "Ok") {
|
||||||
return (
|
let widthProp = width ? width - 20 : undefined;
|
||||||
|
var result = (
|
||||||
<SquiggleVegaChart
|
<SquiggleVegaChart
|
||||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||||
width={width - 20}
|
width={widthProp}
|
||||||
height={height}
|
height={height}
|
||||||
actions={false}
|
actions={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
var result = (
|
||||||
<ErrorBox heading="Distribution Error">
|
<ErrorBox heading="Distribution Error">
|
||||||
{distributionErrorToString(shape.value)}
|
{distributionErrorToString(shape.value)}
|
||||||
</ErrorBox>
|
</ErrorBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,10 +3,12 @@ import _ from "lodash";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import {
|
import {
|
||||||
run,
|
run,
|
||||||
|
runPartial,
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
squiggleExpression,
|
squiggleExpression,
|
||||||
|
bindings,
|
||||||
|
samplingParams,
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
import type { samplingParams } from "@quri/squiggle-lang";
|
|
||||||
import { NumberShower } from "./NumberShower";
|
import { NumberShower } from "./NumberShower";
|
||||||
import { DistributionChart } from "./DistributionChart";
|
import { DistributionChart } from "./DistributionChart";
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
@ -44,6 +46,8 @@ export const VariableBox: React.FC<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let RecordKeyHeader = styled.h3``;
|
||||||
|
|
||||||
export interface SquiggleItemProps {
|
export interface SquiggleItemProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
expression: squiggleExpression;
|
expression: squiggleExpression;
|
||||||
|
@ -104,6 +108,17 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
))}
|
))}
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
|
case "record":
|
||||||
|
return (
|
||||||
|
<VariableBox heading="Record">
|
||||||
|
{Object.entries(expression.value).map(([key, r]) => (
|
||||||
|
<>
|
||||||
|
<RecordKeyHeader>{key}</RecordKeyHeader>
|
||||||
|
<SquiggleItem expression={r} width={width - 20} height={50} />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</VariableBox>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<ErrorBox heading="No Viewer">
|
<ErrorBox heading="No Viewer">
|
||||||
|
@ -135,40 +150,43 @@ export interface SquiggleChartProps {
|
||||||
/** CSS width of the element */
|
/** CSS width of the element */
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
/** Bindings of previous variables declared */
|
||||||
|
bindings?: bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ChartWrapper = styled.div`
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
|
"Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji",
|
||||||
|
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
`;
|
||||||
|
|
||||||
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
squiggleString = "",
|
squiggleString = "",
|
||||||
sampleCount = 1000,
|
sampleCount = 1000,
|
||||||
outputXYPoints = 1000,
|
outputXYPoints = 1000,
|
||||||
onChange = () => {},
|
onChange = () => {},
|
||||||
height = 60,
|
height = 60,
|
||||||
|
bindings = {},
|
||||||
width = NaN,
|
width = NaN,
|
||||||
}: SquiggleChartProps) => {
|
}: 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 = {
|
let samplingInputs: samplingParams = {
|
||||||
sampleCount: sampleCount,
|
sampleCount: sampleCount,
|
||||||
xyPointLength: outputXYPoints,
|
xyPointLength: outputXYPoints,
|
||||||
};
|
};
|
||||||
let expressionResult = run(squiggleString, samplingInputs);
|
let expressionResult = run(squiggleString, bindings, samplingInputs);
|
||||||
let internal: JSX.Element;
|
let internal: JSX.Element;
|
||||||
if (expressionResult.tag === "Ok") {
|
if (expressionResult.tag === "Ok") {
|
||||||
let expression = expressionResult.value;
|
let expression = expressionResult.value;
|
||||||
onChange(expression);
|
onChange(expression);
|
||||||
internal = (
|
internal = (
|
||||||
<SquiggleItem expression={expression} width={_width} height={height} />
|
<SquiggleItem expression={expression} width={width} height={height} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// At this point, we came across an error. What was our error?
|
|
||||||
internal = (
|
internal = (
|
||||||
<ErrorBox heading={"Parse Error"}>
|
<ErrorBox heading={"Parse Error"}>
|
||||||
{errorValueToString(expressionResult.value)}
|
{errorValueToString(expressionResult.value)}
|
||||||
</ErrorBox>
|
</ErrorBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <div ref={target}>{internal}</div>;
|
return <ChartWrapper>{internal}</ChartWrapper>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,9 @@ import * as ReactDOM from "react-dom";
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
import { CodeEditor } from "./CodeEditor";
|
import { CodeEditor } from "./CodeEditor";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import type { squiggleExpression } from "@quri/squiggle-lang";
|
import type { squiggleExpression, bindings } from "@quri/squiggle-lang";
|
||||||
|
import { runPartial, errorValueToString } from "@quri/squiggle-lang";
|
||||||
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
|
||||||
export interface SquiggleEditorProps {
|
export interface SquiggleEditorProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
|
@ -26,6 +28,8 @@ export interface SquiggleEditorProps {
|
||||||
onChange?(expr: squiggleExpression): void;
|
onChange?(expr: squiggleExpression): void;
|
||||||
/** The width of the element */
|
/** The width of the element */
|
||||||
width: number;
|
width: number;
|
||||||
|
/** Previous variable declarations */
|
||||||
|
bindings: bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Input = styled.div`
|
const Input = styled.div`
|
||||||
|
@ -46,6 +50,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
diagramCount,
|
diagramCount,
|
||||||
onChange,
|
onChange,
|
||||||
environment,
|
environment,
|
||||||
|
bindings = {},
|
||||||
}: SquiggleEditorProps) => {
|
}: SquiggleEditorProps) => {
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
return (
|
return (
|
||||||
|
@ -71,6 +76,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
diagramCount={diagramCount}
|
diagramCount={diagramCount}
|
||||||
environment={environment}
|
environment={environment}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
bindings={bindings}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -107,3 +113,76 @@ export function renderSquiggleEditorToDom(props: SquiggleEditorProps) {
|
||||||
);
|
);
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SquigglePartialProps {
|
||||||
|
/** 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;
|
||||||
|
/** when the environment changes. Used again for notebook magic*/
|
||||||
|
onChange?(expr: bindings): void;
|
||||||
|
/** The width of the element */
|
||||||
|
width: number;
|
||||||
|
/** Previously declared variables */
|
||||||
|
bindings: bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
|
initialSquiggleString = "",
|
||||||
|
onChange,
|
||||||
|
bindings,
|
||||||
|
}: SquigglePartialProps) => {
|
||||||
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
|
let squiggleResult = runPartial(expression, bindings);
|
||||||
|
if (squiggleResult.tag == "Ok") {
|
||||||
|
if (onChange) onChange(squiggleResult.value);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input>
|
||||||
|
<CodeEditor
|
||||||
|
value={expression}
|
||||||
|
onChange={setExpression}
|
||||||
|
oneLine={true}
|
||||||
|
showGutter={false}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
</Input>
|
||||||
|
{squiggleResult.tag == "Error" ? (
|
||||||
|
<ErrorBox heading="Error">
|
||||||
|
{errorValueToString(squiggleResult.value)}
|
||||||
|
</ErrorBox>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function renderSquigglePartialToDom(props: SquigglePartialProps) {
|
||||||
|
let parent = document.createElement("div");
|
||||||
|
ReactDOM.render(
|
||||||
|
<SquigglePartial
|
||||||
|
{...props}
|
||||||
|
onChange={(bindings) => {
|
||||||
|
// @ts-ignore
|
||||||
|
parent.value = bindings;
|
||||||
|
|
||||||
|
parent.dispatchEvent(new CustomEvent("input"));
|
||||||
|
if (props.onChange) props.onChange(bindings);
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { FC, useState } from "react";
|
import React, { FC, ReactElement, useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
import CodeEditor from "./CodeEditor";
|
import CodeEditor from "./CodeEditor";
|
||||||
import { Form, Input, Row, Col } from "antd";
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import "antd/dist/antd.css";
|
|
||||||
|
|
||||||
interface FieldFloatProps {
|
interface FieldFloatProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -14,10 +12,19 @@ interface FieldFloatProps {
|
||||||
onChange: (value: number) => void;
|
onChange: (value: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Input = styled.input``;
|
||||||
|
|
||||||
|
const FormItem = (props: { label: string; children: ReactElement }) => (
|
||||||
|
<div>
|
||||||
|
<label>{props.label}</label>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
function FieldFloat(Props: FieldFloatProps) {
|
function FieldFloat(Props: FieldFloatProps) {
|
||||||
let [contents, setContents] = useState(Props.value + "");
|
let [contents, setContents] = useState(Props.value + "");
|
||||||
return (
|
return (
|
||||||
<Form.Item label={Props.label}>
|
<FormItem label={Props.label}>
|
||||||
<Input
|
<Input
|
||||||
value={contents}
|
value={contents}
|
||||||
className={Props.className ? Props.className : ""}
|
className={Props.className ? Props.className : ""}
|
||||||
|
@ -29,7 +36,7 @@ function FieldFloat(Props: FieldFloatProps) {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</FormItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +72,12 @@ const Display = styled.div<TitleProps>`
|
||||||
max-height: ${(props) => props.maxHeight}px;
|
max-height: ${(props) => props.maxHeight}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const Row = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
`;
|
||||||
|
const Col = styled.div``;
|
||||||
|
|
||||||
let SquigglePlayground: FC<Props> = ({
|
let SquigglePlayground: FC<Props> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
height = 300,
|
height = 300,
|
||||||
|
@ -79,7 +92,7 @@ let SquigglePlayground: FC<Props> = ({
|
||||||
return (
|
return (
|
||||||
<ShowBox height={height}>
|
<ShowBox height={height}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={12}>
|
<Col>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
value={squiggleString}
|
value={squiggleString}
|
||||||
onChange={setSquiggleString}
|
onChange={setSquiggleString}
|
||||||
|
@ -88,7 +101,7 @@ let SquigglePlayground: FC<Props> = ({
|
||||||
height={height - 3}
|
height={height - 3}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col>
|
||||||
<Display maxHeight={height - 3}>
|
<Display maxHeight={height - 3}>
|
||||||
<SquiggleChart
|
<SquiggleChart
|
||||||
squiggleString={squiggleString}
|
squiggleString={squiggleString}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
export { SquiggleChart } from "./components/SquiggleChart";
|
export { SquiggleChart } from "./components/SquiggleChart";
|
||||||
export {
|
export {
|
||||||
SquiggleEditor,
|
SquiggleEditor,
|
||||||
|
SquigglePartial,
|
||||||
renderSquiggleEditorToDom,
|
renderSquiggleEditorToDom,
|
||||||
|
renderSquigglePartialToDom,
|
||||||
} from "./components/SquiggleEditor";
|
} from "./components/SquiggleEditor";
|
||||||
import SquigglePlayground, {
|
import SquigglePlayground, {
|
||||||
renderSquigglePlaygroundToDom,
|
renderSquigglePlaygroundToDom,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"description": "A basic area chart example",
|
"description": "A basic area chart example",
|
||||||
"width": 500,
|
"width": 500,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
|
"autosize": "fit",
|
||||||
"padding": 5,
|
"padding": 5,
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,6 @@ node_modules
|
||||||
shell.nix
|
shell.nix
|
||||||
.cache
|
.cache
|
||||||
.direnv
|
.direnv
|
||||||
src
|
|
||||||
__tests__
|
__tests__
|
||||||
lib
|
lib
|
||||||
examples
|
examples
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||||
|
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
||||||
|
|
||||||
# Squiggle language
|
# Squiggle language
|
||||||
|
|
||||||
## Build for development
|
## Build for development
|
||||||
|
@ -15,13 +18,16 @@ Other:
|
||||||
```sh
|
```sh
|
||||||
yarn start # listens to files and recompiles at every mutation
|
yarn start # listens to files and recompiles at every mutation
|
||||||
yarn test
|
yarn test
|
||||||
yarn test:watch # keeps an active session and runs all tests at every mutation
|
|
||||||
|
|
||||||
# where o := open in osx and o := xdg-open in linux,
|
# where o := open in osx and o := xdg-open in linux,
|
||||||
yarn coverage; o _coverage/index.html # produces coverage report and opens it in browser
|
yarn coverage:rescript; o _coverage/index.html # produces coverage report and opens it in browser
|
||||||
```
|
```
|
||||||
|
|
||||||
## Information
|
## Distributing this package or using this package from other monorepo packages
|
||||||
|
|
||||||
|
As it says in the other `packages/*/README.md`s, building this package is an essential step of building other packages.
|
||||||
|
|
||||||
|
# Information
|
||||||
|
|
||||||
Squiggle is a language for representing probability distributions, as well as functions that return probability distributions. Its original intended use is for improving epistemics around EA decisions.
|
Squiggle is a language for representing probability distributions, as well as functions that return probability distributions. Its original intended use is for improving epistemics around EA decisions.
|
||||||
|
|
||||||
|
@ -34,11 +40,3 @@ This package is mainly written in [ReScript](https://rescript-lang.org/), but ha
|
||||||
ReScript has an interesting philosophy of not providing much in the way of effective build tools. Every ReScript file is compiled into `.bs.js` and `.gen.ts` files with the same name and same location, and then you can use these files in other `.js` files to create your program. To generate these files to build the package, you run `yarn build`.
|
ReScript has an interesting philosophy of not providing much in the way of effective build tools. Every ReScript file is compiled into `.bs.js` and `.gen.ts` files with the same name and same location, and then you can use these files in other `.js` files to create your program. To generate these files to build the package, you run `yarn build`.
|
||||||
|
|
||||||
`.gen.ts` files are created by the [`@genType`](https://rescript-lang.org/docs/gentype/latest/getting-started) decorator, which creates typescript typings for needed parts of the codebase so that they can be easily used in typescript. These .gen.ts files reference the .bs.js files generated by rescript.
|
`.gen.ts` files are created by the [`@genType`](https://rescript-lang.org/docs/gentype/latest/getting-started) decorator, which creates typescript typings for needed parts of the codebase so that they can be easily used in typescript. These .gen.ts files reference the .bs.js files generated by rescript.
|
||||||
|
|
||||||
### Errors regarding the `rationale` package
|
|
||||||
|
|
||||||
You may notice sometimes, that there are errors about the `rationale` package. If you ever get these errors, `yarn build` should fix this issue. These errors occur because `yarn build` also needs to create build files that are in `node_modules`. So if you replace `node_modules` you may need to rebuild to get those files back.
|
|
||||||
|
|
||||||
## Distributing this package or using this package from other monorepo packages
|
|
||||||
|
|
||||||
As it says in the other `packages/*/README.md`s, building this package is an essential step of building other packages.
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
open Jest
|
|
||||||
open TestHelpers
|
|
||||||
|
|
||||||
describe("Continuous and discrete splits", () => {
|
|
||||||
makeTest(
|
|
||||||
"splits (1)",
|
|
||||||
SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]),
|
|
||||||
([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()),
|
|
||||||
)
|
|
||||||
makeTest(
|
|
||||||
"splits (2)",
|
|
||||||
SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([
|
|
||||||
1.432,
|
|
||||||
1.33455,
|
|
||||||
2.0,
|
|
||||||
2.0,
|
|
||||||
2.0,
|
|
||||||
2.0,
|
|
||||||
]) |> (((c, disc)) => (c, disc |> E.FloatFloatMap.toArray)),
|
|
||||||
([1.432, 1.33455], [(2.0, 4.0)]),
|
|
||||||
)
|
|
||||||
|
|
||||||
let makeDuplicatedArray = count => {
|
|
||||||
let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int)
|
|
||||||
let sorted = arr |> Belt.SortArray.stableSortBy(_, compare)
|
|
||||||
E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare)
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_, discrete1) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete(
|
|
||||||
makeDuplicatedArray(10),
|
|
||||||
)
|
|
||||||
let toArr1 = discrete1 |> E.FloatFloatMap.toArray
|
|
||||||
makeTest("splitMedium at count=10", toArr1 |> Belt.Array.length, 10)
|
|
||||||
|
|
||||||
let (_c, discrete2) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete(
|
|
||||||
makeDuplicatedArray(500),
|
|
||||||
)
|
|
||||||
let toArr2 = discrete2 |> E.FloatFloatMap.toArray
|
|
||||||
makeTest("splitMedium at count=500", toArr2 |> Belt.Array.length, 500)
|
|
||||||
// makeTest("foo", [] |> Belt.Array.length, 500)
|
|
||||||
})
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
open Jest
|
||||||
|
open TestHelpers
|
||||||
|
|
||||||
|
let prepareInputs = (ar, minWeight) =>
|
||||||
|
E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(ar, ~minDiscreteWeight=minWeight) |> (
|
||||||
|
((c, disc)) => (c, disc |> E.FloatFloatMap.toArray)
|
||||||
|
)
|
||||||
|
|
||||||
|
describe("Continuous and discrete splits", () => {
|
||||||
|
makeTest(
|
||||||
|
"is empty, with no common elements",
|
||||||
|
prepareInputs([1.432, 1.33455, 2.0], 2),
|
||||||
|
([1.33455, 1.432, 2.0], []),
|
||||||
|
)
|
||||||
|
|
||||||
|
makeTest(
|
||||||
|
"only stores 3.5 as discrete when minWeight is 3",
|
||||||
|
prepareInputs([1.432, 1.33455, 2.0, 2.0, 3.5, 3.5, 3.5], 3),
|
||||||
|
([1.33455, 1.432, 2.0, 2.0], [(3.5, 3.0)]),
|
||||||
|
)
|
||||||
|
|
||||||
|
makeTest(
|
||||||
|
"doesn't store 3.5 as discrete when minWeight is 5",
|
||||||
|
prepareInputs([1.432, 1.33455, 2.0, 2.0, 3.5, 3.5, 3.5], 5),
|
||||||
|
([1.33455, 1.432, 2.0, 2.0, 3.5, 3.5, 3.5], []),
|
||||||
|
)
|
||||||
|
|
||||||
|
let makeDuplicatedArray = count => {
|
||||||
|
let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int)
|
||||||
|
let sorted = arr |> Belt.SortArray.stableSortBy(_, compare)
|
||||||
|
E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_, discrete1) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(
|
||||||
|
makeDuplicatedArray(10),
|
||||||
|
~minDiscreteWeight=2,
|
||||||
|
)
|
||||||
|
let toArr1 = discrete1 |> E.FloatFloatMap.toArray
|
||||||
|
makeTest("splitMedium at count=10", toArr1 |> Belt.Array.length, 10)
|
||||||
|
|
||||||
|
let (_c, discrete2) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(
|
||||||
|
makeDuplicatedArray(500),
|
||||||
|
~minDiscreteWeight=2,
|
||||||
|
)
|
||||||
|
let toArr2 = discrete2 |> E.FloatFloatMap.toArray
|
||||||
|
makeTest("splitMedium at count=500", toArr2 |> Belt.Array.length, 500)
|
||||||
|
// makeTest("foo", [] |> Belt.Array.length, 500)
|
||||||
|
})
|
|
@ -0,0 +1,142 @@
|
||||||
|
open Jest
|
||||||
|
// open Expect
|
||||||
|
|
||||||
|
open Reducer_Expression_ExpressionBuilder
|
||||||
|
open Reducer_TestMacroHelpers
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
|
||||||
|
let exampleExpression = eNumber(1.)
|
||||||
|
let exampleExpressionY = eSymbol("y")
|
||||||
|
let exampleStatement = eLetStatement("y", eNumber(1.))
|
||||||
|
let exampleStatementX = eLetStatement("y", eSymbol("x"))
|
||||||
|
let exampleStatementZ = eLetStatement("z", eSymbol("y"))
|
||||||
|
|
||||||
|
// If it is not a mactro then it is not expanded
|
||||||
|
testMacro([], exampleExpression, "Ok(1)")
|
||||||
|
|
||||||
|
describe("bindStatement", () => {
|
||||||
|
// A statement is bound by the bindings created by the previous statement
|
||||||
|
testMacro([], eBindStatement(eBindings([]), exampleStatement), "Ok((:$setBindings {} :y 1))")
|
||||||
|
// Then it answers the bindings for the next statement when reduced
|
||||||
|
testMacroEval([], eBindStatement(eBindings([]), exampleStatement), "Ok({y: 1})")
|
||||||
|
// Now let's feed a binding to see what happens
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBindStatement(eBindings([("x", EvNumber(2.))]), exampleStatementX),
|
||||||
|
"Ok((:$setBindings {x: 2} :y 2))",
|
||||||
|
)
|
||||||
|
// An expression does not return a binding, thus error
|
||||||
|
testMacro([], eBindStatement(eBindings([]), exampleExpression), "Error(Assignment expected)")
|
||||||
|
// When bindings from previous statement are missing the context is injected. This must be the first statement of a block
|
||||||
|
testMacro(
|
||||||
|
[("z", EvNumber(99.))],
|
||||||
|
eBindStatementDefault(exampleStatement),
|
||||||
|
"Ok((:$setBindings {z: 99} :y 1))",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("bindExpression", () => {
|
||||||
|
// x is simply bound in the expression
|
||||||
|
testMacro([], eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")), "Ok(2)")
|
||||||
|
// When an let statement is the end expression then bindings are returned
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement),
|
||||||
|
"Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))",
|
||||||
|
)
|
||||||
|
// Now let's reduce that expression
|
||||||
|
testMacroEval(
|
||||||
|
[],
|
||||||
|
eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement),
|
||||||
|
"Ok({x: 2,y: 1})",
|
||||||
|
)
|
||||||
|
// When bindings are missing the context is injected. This must be the first and last statement of a block
|
||||||
|
testMacroEval(
|
||||||
|
[("z", EvNumber(99.))],
|
||||||
|
eBindExpressionDefault(exampleStatement),
|
||||||
|
"Ok({y: 1,z: 99})",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("block", () => {
|
||||||
|
// Block with a single expression
|
||||||
|
testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))")
|
||||||
|
testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)")
|
||||||
|
// Block with a single statement
|
||||||
|
testMacro([], eBlock(list{exampleStatement}), "Ok((:$$bindExpression (:$let :y 1)))")
|
||||||
|
testMacroEval([], eBlock(list{exampleStatement}), "Ok({y: 1})")
|
||||||
|
// Block with a statement and an expression
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{exampleStatement, exampleExpressionY}),
|
||||||
|
"Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{exampleStatement, exampleExpressionY}), "Ok(1)")
|
||||||
|
// Block with a statement and another statement
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{exampleStatement, exampleStatementZ}),
|
||||||
|
"Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{exampleStatement, exampleStatementZ}), "Ok({y: 1,z: 1})")
|
||||||
|
// Block inside a block
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{eBlock(list{exampleExpression})}),
|
||||||
|
"Ok((:$$bindExpression (:$$block 1)))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{eBlock(list{exampleExpression})}), "Ok(1)")
|
||||||
|
// Block assigned to a variable
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}),
|
||||||
|
"Ok((:$$bindExpression (:$let :z (:$$block (:$$block :y)))))",
|
||||||
|
)
|
||||||
|
testMacroEval(
|
||||||
|
[],
|
||||||
|
eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}),
|
||||||
|
"Ok({z: :y})",
|
||||||
|
)
|
||||||
|
// Empty block
|
||||||
|
testMacro([], eBlock(list{}), "Ok(:undefined block)") //TODO: should be an error
|
||||||
|
// :$$block (:$$block (:$let :y (:add :x 1)) :y)"
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{
|
||||||
|
eBlock(list{
|
||||||
|
eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})),
|
||||||
|
eSymbol("y"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
"Ok((:$$bindExpression (:$$block (:$let :y (:add :x 1)) :y)))",
|
||||||
|
)
|
||||||
|
MyOnly.testMacroEval(
|
||||||
|
[("x", EvNumber(1.))],
|
||||||
|
eBlock(list{
|
||||||
|
eBlock(list{
|
||||||
|
eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})),
|
||||||
|
eSymbol("y"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
"Ok(2)",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("lambda", () => {
|
||||||
|
// assign a lambda to a variable
|
||||||
|
let lambdaExpression = eFunction("$$lambda", list{eArrayString(["y"]), exampleExpressionY})
|
||||||
|
testMacro([], lambdaExpression, "Ok(lambda(y=>internal))")
|
||||||
|
// call a lambda
|
||||||
|
let callLambdaExpression = list{lambdaExpression, eNumber(1.)}->ExpressionT.EList
|
||||||
|
testMacro([], callLambdaExpression, "Ok(((:$$lambda [y] :y) 1))")
|
||||||
|
testMacroEval([], callLambdaExpression, "Ok(1)")
|
||||||
|
// Parameters shadow the outer scope
|
||||||
|
testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(1)")
|
||||||
|
// When not shadowed by the parameters, the outer scope variables are available
|
||||||
|
let lambdaExpression = eFunction(
|
||||||
|
"$$lambda",
|
||||||
|
list{eArrayString(["z"]), eFunction("add", list{eSymbol("y"), eSymbol("z")})},
|
||||||
|
)
|
||||||
|
let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)})
|
||||||
|
testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(667)")
|
||||||
|
})
|
|
@ -0,0 +1,6 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
test("dummy", () => {
|
||||||
|
expect(true)->toBe(true)
|
||||||
|
})
|
|
@ -1,4 +1,4 @@
|
||||||
module Expression = Reducer.Expression
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
|
||||||
|
@ -14,47 +14,18 @@ let unwrapRecord = rValue =>
|
||||||
)
|
)
|
||||||
|
|
||||||
let expectParseToBe = (expr: string, answer: string) =>
|
let expectParseToBe = (expr: string, answer: string) =>
|
||||||
Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer)
|
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectParseOuterToBe = (expr: string, answer: string) =>
|
|
||||||
Reducer.parseOuter(expr)->Expression.toStringResult->expect->toBe(answer)
|
|
||||||
|
|
||||||
let expectParsePartialToBe = (expr: string, answer: string) =>
|
|
||||||
Reducer.parsePartial(expr)->Expression.toStringResult->expect->toBe(answer)
|
|
||||||
|
|
||||||
let expectEvalToBe = (expr: string, answer: string) =>
|
let expectEvalToBe = (expr: string, answer: string) =>
|
||||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
||||||
Reducer.evaluateUsingOptions(
|
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None)
|
||||||
expr,
|
|
||||||
~externalBindings=Some(bindings),
|
|
||||||
~isPartial=None,
|
|
||||||
~environment=None,
|
|
||||||
)
|
|
||||||
->ExpressionValue.toStringResult
|
->ExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toBe(answer)
|
||||||
|
|
||||||
let expectEvalPartialBindingsToBe = (
|
|
||||||
expr: string,
|
|
||||||
bindings: Reducer.externalBindings,
|
|
||||||
answer: string,
|
|
||||||
) =>
|
|
||||||
Reducer.evaluateUsingOptions(
|
|
||||||
expr,
|
|
||||||
~externalBindings=Some(bindings),
|
|
||||||
~isPartial=Some(true),
|
|
||||||
~environment=None,
|
|
||||||
)
|
|
||||||
->unwrapRecord
|
|
||||||
->ExpressionValue.toStringResultRecord
|
|
||||||
->expect
|
|
||||||
->toBe(answer)
|
|
||||||
|
|
||||||
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) => test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) => test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testDescriptionParseToBe = (desc, expr, answer) =>
|
let testDescriptionParseToBe = (desc, expr, answer) =>
|
||||||
test(desc, () => expectParseToBe(expr, answer))
|
test(desc, () => expectParseToBe(expr, answer))
|
||||||
|
|
||||||
|
@ -62,34 +33,16 @@ let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answe
|
||||||
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
test(expr, () => expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
|
||||||
|
|
||||||
module MySkip = {
|
module MySkip = {
|
||||||
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) =>
|
|
||||||
Skip.test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) =>
|
|
||||||
Skip.test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Skip.test(expr, () =>
|
|
||||||
expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
module MyOnly = {
|
module MyOnly = {
|
||||||
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) =>
|
|
||||||
Only.test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) =>
|
|
||||||
Only.test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Only.test(expr, () =>
|
|
||||||
expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
module Macro = Reducer_Expression_Macro
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
module ExpressionValue = ReducerInterface_ExpressionValue
|
||||||
|
module T = Reducer_Expression_T
|
||||||
|
|
||||||
|
let testMacro_ = (
|
||||||
|
tester,
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedCode: string,
|
||||||
|
) => {
|
||||||
|
let bindings = Belt.Map.String.fromArray(bindArray)
|
||||||
|
tester(expr->T.toString, () =>
|
||||||
|
expr
|
||||||
|
->Macro.expandMacroCall(
|
||||||
|
bindings,
|
||||||
|
ExpressionValue.defaultEnvironment,
|
||||||
|
Expression.reduceExpression,
|
||||||
|
)
|
||||||
|
->T.toStringResult
|
||||||
|
->expect
|
||||||
|
->toEqual(expectedCode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let testMacroEval_ = (
|
||||||
|
tester,
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => {
|
||||||
|
let bindings = Belt.Map.String.fromArray(bindArray)
|
||||||
|
tester(expr->T.toString, () =>
|
||||||
|
expr
|
||||||
|
->Macro.doMacroCall(bindings, ExpressionValue.defaultEnvironment, Expression.reduceExpression)
|
||||||
|
->ExpressionValue.toStringResult
|
||||||
|
->expect
|
||||||
|
->toEqual(expectedValue)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(test, bindArray, expr, expectedValue)
|
||||||
|
|
||||||
|
module MySkip = {
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(Skip.test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(Skip.test, bindArray, expr, expectedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
module MyOnly = {
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(Only.test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
|
||||||
|
}
|
|
@ -1,60 +1,63 @@
|
||||||
|
// TODO: Reimplement with usual parse
|
||||||
open Jest
|
open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
describe("Parse for Bindings", () => {
|
// describe("Parse for Bindings", () => {
|
||||||
testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
// testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
||||||
testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
// testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
||||||
testParseOuterToBe(
|
// testParseOuterToBe(
|
||||||
"y = x+1; y",
|
// "y = x+1; y",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
||||||
describe("Parse Partial", () => {
|
// describe("Parse Partial", () => {
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"x",
|
// "x",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y=x",
|
// "y=x",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y=x+1",
|
// "y=x+1",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y = x+1; z = y",
|
// "y = x+1; z = y",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
||||||
describe("Eval with Bindings", () => {
|
describe("Eval with Bindings", () => {
|
||||||
testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)")
|
testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)")
|
||||||
testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
||||||
|
testParseToBe("y = x+1; y", "Ok((:$$block (:$$block (:$let :y (:add :x 1)) :y)))")
|
||||||
testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
||||||
|
testEvalBindingsToBe("y = x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 2})")
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Partial code is a partial code fragment that is cut out from a larger code.
|
Partial code is a partial code fragment that is cut out from a larger code.
|
||||||
Therefore it does not end with an expression.
|
Therefore it does not end with an expression.
|
||||||
*/
|
*/
|
||||||
describe("Eval Partial", () => {
|
// describe("Eval Partial", () => {
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
// A partial cannot end with an expression
|
// // A partial cannot end with an expression
|
||||||
"x",
|
// "x",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Error(Assignment expected)",
|
// "Error(Assignment expected)",
|
||||||
)
|
// )
|
||||||
testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1, y: 1})")
|
// testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 1})")
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
"y=x+1",
|
// "y=x+1",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Ok({x: 1, y: 2})",
|
// "Ok({x: 1,y: 2})",
|
||||||
)
|
// )
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
"y = x+1; z = y",
|
// "y = x+1; z = y",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Ok({x: 1, y: 2, z: 2})",
|
// "Ok({x: 1,y: 2,z: 2})",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
|
@ -2,8 +2,8 @@ open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
describe("Parse function assignment", () => {
|
describe("Parse function assignment", () => {
|
||||||
testParseToBe("f(x)=x", "Ok((:$let :f (:$lambda (x) :x)))")
|
testParseToBe("f(x)=x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block :x)))))")
|
||||||
testParseToBe("f(x)=2*x", "Ok((:$let :f (:$lambda (x) (:multiply 2 :x))))")
|
testParseToBe("f(x)=2*x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block (:multiply 2 :x))))))")
|
||||||
//MathJs does not allow blocks in function definitions
|
//MathJs does not allow blocks in function definitions
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -10,46 +10,39 @@ describe("reducer using mathjs parse", () => {
|
||||||
// Those tests toString that we are converting mathjs parse tree to what we need
|
// Those tests toString that we are converting mathjs parse tree to what we need
|
||||||
|
|
||||||
describe("expressions", () => {
|
describe("expressions", () => {
|
||||||
testParseToBe("1", "Ok(1)")
|
testParseToBe("1", "Ok((:$$block 1))")
|
||||||
testParseToBe("(1)", "Ok(1)")
|
testParseToBe("(1)", "Ok((:$$block 1))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
testParseToBe("1+2", "Ok((:$$block (:add 1 2)))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
testParseToBe("1+2*3", "Ok((:$$block (:add 1 (:multiply 2 3))))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
|
||||||
testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")
|
|
||||||
})
|
})
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
//Note. () is a empty list in Lisp
|
//Note. () is a empty list in Lisp
|
||||||
// The only builtin structure in Lisp is list. There are no arrays
|
// The only builtin structure in Lisp is list. There are no arrays
|
||||||
// [1,2,3] becomes (1 2 3)
|
// [1,2,3] becomes (1 2 3)
|
||||||
testDescriptionParseToBe("empty", "[]", "Ok(())")
|
testDescriptionParseToBe("empty", "[]", "Ok((:$$block ()))")
|
||||||
testParseToBe("[1, 2, 3]", "Ok((1 2 3))")
|
testParseToBe("[1, 2, 3]", "Ok((:$$block (1 2 3)))")
|
||||||
testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")
|
testParseToBe("['hello', 'world']", "Ok((:$$block ('hello' 'world')))")
|
||||||
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")
|
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$$block (:$atIndex (0 1 2) (1))))")
|
||||||
})
|
})
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))")
|
testDescriptionParseToBe(
|
||||||
|
"define",
|
||||||
|
"{a: 1, b: 2}",
|
||||||
|
"Ok((:$$block (:$constructRecord (('a' 1) ('b' 2)))))",
|
||||||
|
)
|
||||||
testDescriptionParseToBe(
|
testDescriptionParseToBe(
|
||||||
"use",
|
"use",
|
||||||
"{a: 1, b: 2}.a",
|
"{a: 1, b: 2}.a",
|
||||||
"Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))",
|
"Ok((:$$block (:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a'))))",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))")
|
testParseToBe("1; 2", "Ok((:$$block (:$$block 1 2)))")
|
||||||
testParseToBe(
|
testParseToBe("1+1; 2+1", "Ok((:$$block (:$$block (:add 1 1) (:add 2 1))))")
|
||||||
"1+1; 2+1",
|
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))",
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
describe("assignment", () => {
|
describe("assignment", () => {
|
||||||
testParseToBe(
|
testParseToBe("x=1; x", "Ok((:$$block (:$$block (:$let :x 1) :x)))")
|
||||||
"x=1; x",
|
testParseToBe("x=1+1; x+1", "Ok((:$$block (:$$block (:$let :x (:add 1 1)) (:add :x 1))))")
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))",
|
|
||||||
)
|
|
||||||
testParseToBe(
|
|
||||||
"x=1+1; x+1",
|
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))",
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -70,13 +63,13 @@ describe("eval", () => {
|
||||||
})
|
})
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
test("empty array", () => expectEvalToBe("[]", "Ok([])"))
|
test("empty array", () => expectEvalToBe("[]", "Ok([])"))
|
||||||
testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")
|
testEvalToBe("[1, 2, 3]", "Ok([1,2,3])")
|
||||||
testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")
|
testEvalToBe("['hello', 'world']", "Ok(['hello','world'])")
|
||||||
testEvalToBe("([0,1,2])[1]", "Ok(1)")
|
testEvalToBe("([0,1,2])[1]", "Ok(1)")
|
||||||
testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
|
testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
|
||||||
})
|
})
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})"))
|
test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})"))
|
||||||
test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
|
test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
|
||||||
test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
|
test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
|
||||||
})
|
})
|
||||||
|
@ -91,7 +84,7 @@ describe("eval", () => {
|
||||||
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
||||||
testEvalToBe("1; x=1", "Error(Assignment expected)")
|
testEvalToBe("1; x=1", "Error(Assignment expected)")
|
||||||
testEvalToBe("1; 1", "Error(Assignment expected)")
|
testEvalToBe("1; 1", "Error(Assignment expected)")
|
||||||
testEvalToBe("x=1; x=1", "Error(Expression expected)")
|
testEvalToBe("x=1; x=1", "Ok({x: 1})")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -92,11 +92,11 @@ describe("eval on distribution functions", () => {
|
||||||
testEval("log(2, uniform(5,8))", "Ok(Sample Set Distribution)")
|
testEval("log(2, uniform(5,8))", "Ok(Sample Set Distribution)")
|
||||||
testEval(
|
testEval(
|
||||||
"log(normal(5,2), 3)",
|
"log(normal(5,2), 3)",
|
||||||
"Error(Distribution Math Error: Logarithm of input error: First input must completely greater than 0)",
|
"Error(Distribution Math Error: Logarithm of input error: First input must be completely greater than 0)",
|
||||||
)
|
)
|
||||||
testEval(
|
testEval(
|
||||||
"log(normal(5,2), normal(10,1))",
|
"log(normal(5,2), normal(10,1))",
|
||||||
"Error(Distribution Math Error: Logarithm of input error: First input must completely greater than 0)",
|
"Error(Distribution Math Error: Logarithm of input error: First input must be completely greater than 0)",
|
||||||
)
|
)
|
||||||
testEval("log(uniform(5,8))", "Ok(Sample Set Distribution)")
|
testEval("log(uniform(5,8))", "Ok(Sample Set Distribution)")
|
||||||
testEval("log10(uniform(5,8))", "Ok(Sample Set Distribution)")
|
testEval("log10(uniform(5,8))", "Ok(Sample Set Distribution)")
|
||||||
|
@ -119,27 +119,33 @@ describe("eval on distribution functions", () => {
|
||||||
|
|
||||||
describe("parse on distribution functions", () => {
|
describe("parse on distribution functions", () => {
|
||||||
describe("power", () => {
|
describe("power", () => {
|
||||||
testParse("normal(5,2) ^ normal(5,1)", "Ok((:pow (:normal 5 2) (:normal 5 1)))")
|
testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$block (:pow (:normal 5 2) (:normal 5 1))))")
|
||||||
testParse("3 ^ normal(5,1)", "Ok((:pow 3 (:normal 5 1)))")
|
testParse("3 ^ normal(5,1)", "Ok((:$$block (:pow 3 (:normal 5 1))))")
|
||||||
testParse("normal(5,2) ^ 3", "Ok((:pow (:normal 5 2) 3))")
|
testParse("normal(5,2) ^ 3", "Ok((:$$block (:pow (:normal 5 2) 3)))")
|
||||||
})
|
})
|
||||||
describe("subtraction", () => {
|
describe("subtraction", () => {
|
||||||
testParse("10 - normal(5,1)", "Ok((:subtract 10 (:normal 5 1)))")
|
testParse("10 - normal(5,1)", "Ok((:$$block (:subtract 10 (:normal 5 1))))")
|
||||||
testParse("normal(5,1) - 10", "Ok((:subtract (:normal 5 1) 10))")
|
testParse("normal(5,1) - 10", "Ok((:$$block (:subtract (:normal 5 1) 10)))")
|
||||||
})
|
})
|
||||||
describe("pointwise arithmetic expressions", () => {
|
describe("pointwise arithmetic expressions", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
testParse(
|
testParse(
|
||||||
~skip=true,
|
~skip=true,
|
||||||
"normal(5,2) .- normal(5,1)",
|
"normal(5,2) .- normal(5,1)",
|
||||||
"Ok((:dotSubtract (:normal 5 2) (:normal 5 1)))",
|
"Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))",
|
||||||
)
|
)
|
||||||
testParse("normal(5,2) .* normal(5,1)", "Ok((:dotMultiply (:normal 5 2) (:normal 5 1)))")
|
testParse(
|
||||||
testParse("normal(5,2) ./ normal(5,1)", "Ok((:dotDivide (:normal 5 2) (:normal 5 1)))")
|
"normal(5,2) .* normal(5,1)",
|
||||||
testParse("normal(5,2) .^ normal(5,1)", "Ok((:dotPow (:normal 5 2) (:normal 5 1)))")
|
"Ok((:$$block (:dotMultiply (:normal 5 2) (:normal 5 1))))",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"normal(5,2) ./ normal(5,1)",
|
||||||
|
"Ok((:$$block (:dotDivide (:normal 5 2) (:normal 5 1))))",
|
||||||
|
)
|
||||||
|
testParse("normal(5,2) .^ normal(5,1)", "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))")
|
||||||
})
|
})
|
||||||
describe("equality", () => {
|
describe("equality", () => {
|
||||||
testParse("5 == normal(5,2)", "Ok((:equal 5 (:normal 5 2)))")
|
testParse("5 == normal(5,2)", "Ok((:$$block (:equal 5 (:normal 5 2))))")
|
||||||
})
|
})
|
||||||
describe("pointwise adding two normals", () => {
|
describe("pointwise adding two normals", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
|
|
|
@ -3,9 +3,9 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
describe("ExpressionValue", () => {
|
describe("ExpressionValue", () => {
|
||||||
test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1, 'a'"))
|
test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1,'a'"))
|
||||||
|
|
||||||
test("toStringFunctionCall", () =>
|
test("toStringFunctionCall", () =>
|
||||||
expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1, 'a')")
|
expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')")
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,23 +1,5 @@
|
||||||
import {
|
import { Distribution, resultMap } from "../../src/js/index";
|
||||||
run,
|
import { testRun, testRunPartial } from "./TestHelpers";
|
||||||
Distribution,
|
|
||||||
resultMap,
|
|
||||||
squiggleExpression,
|
|
||||||
errorValueToString,
|
|
||||||
} from "../../src/js/index";
|
|
||||||
|
|
||||||
let testRun = (x: string): squiggleExpression => {
|
|
||||||
let result = run(x, { sampleCount: 100, xyPointLength: 100 });
|
|
||||||
expect(result.tag).toEqual("Ok");
|
|
||||||
if (result.tag === "Ok") {
|
|
||||||
return result.value;
|
|
||||||
} else {
|
|
||||||
throw Error(
|
|
||||||
"Expected squiggle expression to evaluate but got error: " +
|
|
||||||
errorValueToString(result.value)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function Ok<b>(x: b) {
|
function Ok<b>(x: b) {
|
||||||
return { tag: "Ok", value: x };
|
return { tag: "Ok", value: x };
|
||||||
|
@ -42,6 +24,50 @@ describe("Log function", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Array", () => {
|
||||||
|
test("nested Array", () => {
|
||||||
|
expect(testRun("[[1]]")).toEqual({
|
||||||
|
tag: "array",
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
tag: "array",
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
tag: "number",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Record", () => {
|
||||||
|
test("Return record", () => {
|
||||||
|
expect(testRun("{a: 1}")).toEqual({
|
||||||
|
tag: "record",
|
||||||
|
value: {
|
||||||
|
a: {
|
||||||
|
tag: "number",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Partials", () => {
|
||||||
|
test("Can pass variables between partials and cells", () => {
|
||||||
|
let bindings = testRunPartial(`x = 5`);
|
||||||
|
let bindings2 = testRunPartial(`y = x + 2`, bindings);
|
||||||
|
expect(testRun(`y + 3`, bindings2)).toEqual({
|
||||||
|
tag: "number",
|
||||||
|
value: 10,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Distribution", () => {
|
describe("Distribution", () => {
|
||||||
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
||||||
//Also, note, the value should be created using makeSampleSetDist() later on.
|
//Also, note, the value should be created using makeSampleSetDist() later on.
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import {
|
import {
|
||||||
run,
|
run,
|
||||||
// Distribution,
|
runPartial,
|
||||||
|
bindings,
|
||||||
squiggleExpression,
|
squiggleExpression,
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
// errorValue,
|
|
||||||
// result,
|
|
||||||
} from "../../src/js/index";
|
} from "../../src/js/index";
|
||||||
|
|
||||||
export function testRun(x: string): squiggleExpression {
|
export function testRun(x: string, bindings = {}): squiggleExpression {
|
||||||
let squiggleResult = run(x, { sampleCount: 1000, xyPointLength: 100 });
|
let squiggleResult = run(x, bindings, {
|
||||||
|
sampleCount: 1000,
|
||||||
|
xyPointLength: 100,
|
||||||
|
});
|
||||||
// return squiggleResult.value
|
// return squiggleResult.value
|
||||||
if (squiggleResult.tag === "Ok") {
|
if (squiggleResult.tag === "Ok") {
|
||||||
return squiggleResult.value;
|
return squiggleResult.value;
|
||||||
|
@ -21,6 +23,22 @@ export function testRun(x: string): squiggleExpression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testRunPartial(x: string, bindings: bindings = {}): bindings {
|
||||||
|
let squiggleResult = runPartial(x, bindings, {
|
||||||
|
sampleCount: 1000,
|
||||||
|
xyPointLength: 100,
|
||||||
|
});
|
||||||
|
if (squiggleResult.tag === "Ok") {
|
||||||
|
return squiggleResult.value;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Expected squiggle expression to evaluate but got error: ${errorValueToString(
|
||||||
|
squiggleResult.value
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function failDefault() {
|
export function failDefault() {
|
||||||
expect("be reached").toBe("codepath should never");
|
expect("be reached").toBe("codepath should never");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,26 @@ let pointSetDist3: PointSetTypes.xyShape = {
|
||||||
ys: [0.2, 0.5, 0.8],
|
ys: [0.2, 0.5, 0.8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let makeAndGetErrorString = (~xs, ~ys) =>
|
||||||
|
XYShape.T.make(~xs, ~ys)->E.R.getError->E.O2.fmap(XYShape.Error.toString)
|
||||||
|
|
||||||
describe("XYShapes", () => {
|
describe("XYShapes", () => {
|
||||||
|
describe("Validator", () => {
|
||||||
|
makeTest(
|
||||||
|
"with no errors",
|
||||||
|
makeAndGetErrorString(~xs=[1.0, 4.0, 8.0], ~ys=[0.2, 0.4, 0.8]),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
makeTest("when empty", makeAndGetErrorString(~xs=[], ~ys=[]), Some("Xs is empty"))
|
||||||
|
makeTest(
|
||||||
|
"when not sorted, different lengths, and not finite",
|
||||||
|
makeAndGetErrorString(~xs=[2.0, 1.0, infinity, 0.0], ~ys=[3.0, Js.Float._NaN]),
|
||||||
|
Some(
|
||||||
|
"Multiple Errors: [Xs is not sorted], [Xs and Ys have different lengths. Xs has length 4 and Ys has length 2], [Xs is not finite. Example value: Infinity], [Ys is not finite. Example value: NaN]",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
describe("logScorePoint", () => {
|
describe("logScorePoint", () => {
|
||||||
makeTest("When identical", XYShape.logScorePoint(30, pointSetDist1, pointSetDist1), Some(0.0))
|
makeTest("When identical", XYShape.logScorePoint(30, pointSetDist1, pointSetDist1), Some(0.0))
|
||||||
makeTest(
|
makeTest(
|
||||||
|
@ -32,16 +51,6 @@ describe("XYShapes", () => {
|
||||||
Some(210.3721280423322),
|
Some(210.3721280423322),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
// describe("transverse", () => {
|
|
||||||
// makeTest(
|
|
||||||
// "When very different",
|
|
||||||
// XYShape.Transversal._transverse(
|
|
||||||
// (aCurrent, aLast) => aCurrent +. aLast,
|
|
||||||
// [|1.0, 2.0, 3.0, 4.0|],
|
|
||||||
// ),
|
|
||||||
// [|1.0, 3.0, 6.0, 10.0|],
|
|
||||||
// )
|
|
||||||
// });
|
|
||||||
describe("integrateWithTriangles", () =>
|
describe("integrateWithTriangles", () =>
|
||||||
makeTest(
|
makeTest(
|
||||||
"integrates correctly",
|
"integrates correctly",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
],
|
],
|
||||||
"suffix": ".bs.js",
|
"suffix": ".bs.js",
|
||||||
"namespace": true,
|
"namespace": true,
|
||||||
"bs-dependencies": ["@glennsl/rescript-jest", "rationale", "bisect_ppx"],
|
"bs-dependencies": ["@glennsl/rescript-jest", "bisect_ppx"],
|
||||||
"gentypeconfig": {
|
"gentypeconfig": {
|
||||||
"language": "typescript",
|
"language": "typescript",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "@quri/squiggle-lang",
|
"name": "@quri/squiggle-lang",
|
||||||
"version": "0.2.5",
|
"version": "0.2.7",
|
||||||
"homepage": "https://squiggle-language.com",
|
"homepage": "https://squiggle-language.com",
|
||||||
"licence": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rescript build -with-deps",
|
"build": "rescript build -with-deps && tsc",
|
||||||
"bundle": "webpack",
|
"bundle": "webpack",
|
||||||
"start": "rescript build -w -with-deps",
|
"start": "rescript build -w -with-deps",
|
||||||
"clean": "rescript clean",
|
"clean": "rescript clean && rm -r dist",
|
||||||
"test:reducer": "jest __tests__/Reducer*/",
|
"test:reducer": "jest __tests__/Reducer*/",
|
||||||
"benchmark": "ts-node benchmark/conversion_tests.ts",
|
"benchmark": "ts-node benchmark/conversion_tests.ts",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
|
@ -31,34 +31,28 @@
|
||||||
],
|
],
|
||||||
"author": "Quantified Uncertainty Research Institute",
|
"author": "Quantified Uncertainty Research Institute",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"rescript": "^9.1.4",
|
||||||
|
"jstat": "^1.9.5",
|
||||||
|
"pdfast": "^0.2.0",
|
||||||
|
"mathjs": "10.5.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bisect_ppx": "^2.7.1",
|
"bisect_ppx": "^2.7.1",
|
||||||
"jstat": "^1.9.5",
|
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"mathjs": "10.5.0",
|
|
||||||
"pdfast": "^0.2.0",
|
|
||||||
"rationale": "0.2.0",
|
|
||||||
"rescript": "^9.1.4",
|
|
||||||
"rescript-fast-check": "^1.1.1",
|
"rescript-fast-check": "^1.1.1",
|
||||||
"@glennsl/rescript-jest": "^0.9.0",
|
"@glennsl/rescript-jest": "^0.9.0",
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.4.0",
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||||
"bisect_ppx": "^2.7.1",
|
"chalk": "^5.0.1",
|
||||||
"chalk": "^4.1.2",
|
|
||||||
"codecov": "3.8.3",
|
"codecov": "3.8.3",
|
||||||
"fast-check": "2.25.0",
|
"fast-check": "2.25.0",
|
||||||
"gentype": "^4.3.0",
|
"gentype": "^4.3.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"jstat": "^1.9.5",
|
|
||||||
"lodash": "4.17.21",
|
|
||||||
"mathjs": "10.5.0",
|
|
||||||
"moduleserve": "0.9.1",
|
"moduleserve": "0.9.1",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"pdfast": "^0.2.0",
|
|
||||||
"rationale": "0.2.0",
|
|
||||||
"reanalyze": "^2.19.0",
|
"reanalyze": "^2.19.0",
|
||||||
"rescript": "^9.1.4",
|
|
||||||
"ts-jest": "^27.1.4",
|
"ts-jest": "^27.1.4",
|
||||||
"ts-loader": "^9.2.8",
|
"ts-loader": "^9.2.8",
|
||||||
"ts-node": "^10.7.0",
|
"ts-node": "^10.7.0",
|
||||||
|
@ -67,6 +61,6 @@
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"source": "./src/js/index.ts",
|
"source": "./src/js/index.ts",
|
||||||
"main": "./dist/bundle.js",
|
"main": "./dist/src/js/index.js",
|
||||||
"types": "./dist/js/index.d.ts"
|
"types": "./dist/src/js/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ import * as _ from "lodash";
|
||||||
import {
|
import {
|
||||||
genericDist,
|
genericDist,
|
||||||
samplingParams,
|
samplingParams,
|
||||||
evaluate,
|
evaluatePartialUsingExternalBindings,
|
||||||
|
externalBindings,
|
||||||
expressionValue,
|
expressionValue,
|
||||||
errorValue,
|
errorValue,
|
||||||
distributionError,
|
distributionError,
|
||||||
|
@ -11,6 +12,9 @@ import {
|
||||||
discreteShape,
|
discreteShape,
|
||||||
distributionErrorToString,
|
distributionErrorToString,
|
||||||
internalCode,
|
internalCode,
|
||||||
|
mixedShape,
|
||||||
|
sampleSetDist,
|
||||||
|
symbolicDist,
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
export {
|
export {
|
||||||
makeSampleSetDist,
|
makeSampleSetDist,
|
||||||
|
@ -44,7 +48,7 @@ import {
|
||||||
Constructors_pointwiseLogarithm,
|
Constructors_pointwiseLogarithm,
|
||||||
Constructors_pointwisePower,
|
Constructors_pointwisePower,
|
||||||
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
||||||
export type { samplingParams, errorValue };
|
export type { samplingParams, errorValue, externalBindings as bindings };
|
||||||
|
|
||||||
export let defaultSamplingInputs: samplingParams = {
|
export let defaultSamplingInputs: samplingParams = {
|
||||||
sampleCount: 10000,
|
sampleCount: 10000,
|
||||||
|
@ -92,26 +96,67 @@ export type squiggleExpression =
|
||||||
| tagged<"distribution", Distribution>
|
| tagged<"distribution", Distribution>
|
||||||
| tagged<"number", number>
|
| tagged<"number", number>
|
||||||
| tagged<"record", { [key: string]: squiggleExpression }>;
|
| tagged<"record", { [key: string]: squiggleExpression }>;
|
||||||
|
|
||||||
export function run(
|
export function run(
|
||||||
squiggleString: string,
|
squiggleString: string,
|
||||||
|
bindings?: externalBindings,
|
||||||
samplingInputs?: samplingParams
|
samplingInputs?: samplingParams
|
||||||
): result<squiggleExpression, errorValue> {
|
): result<squiggleExpression, errorValue> {
|
||||||
|
let b = bindings ? bindings : {};
|
||||||
let si: samplingParams = samplingInputs
|
let si: samplingParams = samplingInputs
|
||||||
? samplingInputs
|
? samplingInputs
|
||||||
: defaultSamplingInputs;
|
: defaultSamplingInputs;
|
||||||
let result: result<expressionValue, errorValue> = evaluate(squiggleString);
|
|
||||||
|
let result: result<expressionValue, errorValue> =
|
||||||
|
evaluateUsingExternalBindings(squiggleString, b);
|
||||||
return resultMap(result, (x) => createTsExport(x, si));
|
return resultMap(result, (x) => createTsExport(x, si));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run Partial. A partial is a block of code that doesn't return a value
|
||||||
|
export function runPartial(
|
||||||
|
squiggleString: string,
|
||||||
|
bindings: externalBindings,
|
||||||
|
_samplingInputs?: samplingParams
|
||||||
|
): result<externalBindings, errorValue> {
|
||||||
|
return evaluatePartialUsingExternalBindings(squiggleString, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
function createTsExport(
|
function createTsExport(
|
||||||
x: expressionValue,
|
x: expressionValue,
|
||||||
sampEnv: samplingParams
|
sampEnv: samplingParams
|
||||||
): squiggleExpression {
|
): squiggleExpression {
|
||||||
switch (x.tag) {
|
switch (x.tag) {
|
||||||
case "EvArray":
|
case "EvArray":
|
||||||
|
// genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
|
||||||
|
// format, leaving it as the raw values. This converts the raw values
|
||||||
|
// directly into typescript values.
|
||||||
|
//
|
||||||
|
// The casting here is because genType is about the types of the returned
|
||||||
|
// values, claiming they are fully recursive when that's not actually the
|
||||||
|
// case
|
||||||
return tag(
|
return tag(
|
||||||
"array",
|
"array",
|
||||||
x.value.map((x) => createTsExport(x, sampEnv))
|
x.value.map((arrayItem): squiggleExpression => {
|
||||||
|
switch (arrayItem.tag) {
|
||||||
|
case "EvRecord":
|
||||||
|
return tag(
|
||||||
|
"record",
|
||||||
|
_.mapValues(arrayItem.value, (recordValue: unknown) =>
|
||||||
|
convertRawToTypescript(recordValue as rescriptExport, sampEnv)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
case "EvArray":
|
||||||
|
let y = arrayItem.value as unknown as rescriptExport[];
|
||||||
|
return tag(
|
||||||
|
"array",
|
||||||
|
y.map((childArrayItem) =>
|
||||||
|
convertRawToTypescript(childArrayItem, sampEnv)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return createTsExport(arrayItem, sampEnv);
|
||||||
|
}
|
||||||
|
})
|
||||||
);
|
);
|
||||||
case "EvBool":
|
case "EvBool":
|
||||||
return tag("boolean", x.value);
|
return tag("boolean", x.value);
|
||||||
|
@ -124,10 +169,14 @@ function createTsExport(
|
||||||
case "EvNumber":
|
case "EvNumber":
|
||||||
return tag("number", x.value);
|
return tag("number", x.value);
|
||||||
case "EvRecord":
|
case "EvRecord":
|
||||||
return tag(
|
// genType doesn't support records, so we have to do the raw conversion ourself
|
||||||
|
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag(
|
||||||
"record",
|
"record",
|
||||||
_.mapValues(x.value, (x) => createTsExport(x, sampEnv))
|
_.mapValues(x.value, (x: unknown) =>
|
||||||
|
convertRawToTypescript(x as rescriptExport, sampEnv)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
case "EvString":
|
case "EvString":
|
||||||
return tag("string", x.value);
|
return tag("string", x.value);
|
||||||
case "EvSymbol":
|
case "EvSymbol":
|
||||||
|
@ -135,6 +184,118 @@ function createTsExport(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper functions to convert the rescript representations that genType doesn't
|
||||||
|
// cover
|
||||||
|
function convertRawToTypescript(
|
||||||
|
result: rescriptExport,
|
||||||
|
sampEnv: samplingParams
|
||||||
|
): squiggleExpression {
|
||||||
|
switch (result.TAG) {
|
||||||
|
case 0: // EvArray
|
||||||
|
return tag(
|
||||||
|
"array",
|
||||||
|
result._0.map((x) => convertRawToTypescript(x, sampEnv))
|
||||||
|
);
|
||||||
|
case 1: // EvBool
|
||||||
|
return tag("boolean", result._0);
|
||||||
|
case 2: // EvCall
|
||||||
|
return tag("call", result._0);
|
||||||
|
case 3: // EvDistribution
|
||||||
|
return tag(
|
||||||
|
"distribution",
|
||||||
|
new Distribution(
|
||||||
|
convertRawDistributionToGenericDist(result._0),
|
||||||
|
sampEnv
|
||||||
|
)
|
||||||
|
);
|
||||||
|
case 4: // EvNumber
|
||||||
|
return tag("number", result._0);
|
||||||
|
case 5: // EvRecord
|
||||||
|
return tag(
|
||||||
|
"record",
|
||||||
|
_.mapValues(result._0, (x) => convertRawToTypescript(x, sampEnv))
|
||||||
|
);
|
||||||
|
case 6: // EvString
|
||||||
|
return tag("string", result._0);
|
||||||
|
case 7: // EvSymbol
|
||||||
|
return tag("symbol", result._0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertRawDistributionToGenericDist(
|
||||||
|
result: rescriptDist
|
||||||
|
): genericDist {
|
||||||
|
switch (result.TAG) {
|
||||||
|
case 0: // Point Set Dist
|
||||||
|
switch (result._0.TAG) {
|
||||||
|
case 0: // Mixed
|
||||||
|
return tag("PointSet", tag("Mixed", result._0._0));
|
||||||
|
case 1: // Discrete
|
||||||
|
return tag("PointSet", tag("Discrete", result._0._0));
|
||||||
|
case 2: // Continuous
|
||||||
|
return tag("PointSet", tag("Continuous", result._0._0));
|
||||||
|
}
|
||||||
|
case 1: // Sample Set Dist
|
||||||
|
return tag("SampleSet", result._0);
|
||||||
|
case 2: // Symbolic Dist
|
||||||
|
return tag("Symbolic", result._0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw rescript types.
|
||||||
|
type rescriptExport =
|
||||||
|
| {
|
||||||
|
TAG: 0; // EvArray
|
||||||
|
_0: rescriptExport[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 1; // EvBool
|
||||||
|
_0: boolean;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 2; // EvCall
|
||||||
|
_0: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 3; // EvDistribution
|
||||||
|
_0: rescriptDist;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 4; // EvNumber
|
||||||
|
_0: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 5; // EvRecord
|
||||||
|
_0: { [key: string]: rescriptExport };
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 6; // EvString
|
||||||
|
_0: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 7; // EvSymbol
|
||||||
|
_0: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type rescriptDist =
|
||||||
|
| { TAG: 0; _0: rescriptPointSetDist }
|
||||||
|
| { TAG: 1; _0: sampleSetDist }
|
||||||
|
| { TAG: 2; _0: symbolicDist };
|
||||||
|
|
||||||
|
type rescriptPointSetDist =
|
||||||
|
| {
|
||||||
|
TAG: 0; // Mixed
|
||||||
|
_0: mixedShape;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 1; // Discrete
|
||||||
|
_0: discreteShape;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 2; // ContinuousShape
|
||||||
|
_0: continuousShape;
|
||||||
|
};
|
||||||
|
|
||||||
export function resultExn<a, c>(r: result<a, c>): a | c {
|
export function resultExn<a, c>(r: result<a, c>): a | c {
|
||||||
return r.value;
|
return r.value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ type error =
|
||||||
| RequestedStrategyInvalidError(string)
|
| RequestedStrategyInvalidError(string)
|
||||||
| LogarithmOfDistributionError(string)
|
| LogarithmOfDistributionError(string)
|
||||||
| OtherError(string)
|
| OtherError(string)
|
||||||
|
| XYShapeError(XYShape.error)
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
module Error = {
|
module Error = {
|
||||||
|
@ -39,6 +40,7 @@ module Error = {
|
||||||
| PointSetConversionError(err) => SampleSetDist.pointsetConversionErrorToString(err)
|
| PointSetConversionError(err) => SampleSetDist.pointsetConversionErrorToString(err)
|
||||||
| SparklineError(err) => PointSetTypes.sparklineErrorToString(err)
|
| SparklineError(err) => PointSetTypes.sparklineErrorToString(err)
|
||||||
| RequestedStrategyInvalidError(err) => `Requested strategy invalid: ${err}`
|
| RequestedStrategyInvalidError(err) => `Requested strategy invalid: ${err}`
|
||||||
|
| XYShapeError(err) => `XY Shape Error: ${XYShape.Error.toString(err)}`
|
||||||
| OtherError(s) => s
|
| OtherError(s) => s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,24 @@ type toSampleSetFn = t => result<SampleSetDist.t, error>
|
||||||
type scaleMultiplyFn = (t, float) => result<t, error>
|
type scaleMultiplyFn = (t, float) => result<t, error>
|
||||||
type pointwiseAddFn = (t, t) => result<t, error>
|
type pointwiseAddFn = (t, t) => result<t, error>
|
||||||
|
|
||||||
|
let isPointSet = (t: t) =>
|
||||||
|
switch t {
|
||||||
|
| PointSet(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
let isSampleSetSet = (t: t) =>
|
||||||
|
switch t {
|
||||||
|
| SampleSet(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
let isSymbolic = (t: t) =>
|
||||||
|
switch t {
|
||||||
|
| Symbolic(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
|
||||||
let sampleN = (t: t, n) =>
|
let sampleN = (t: t, n) =>
|
||||||
switch t {
|
switch t {
|
||||||
| PointSet(r) => PointSetDist.sampleNRendered(n, r)
|
| PointSet(r) => PointSetDist.sampleNRendered(n, r)
|
||||||
|
@ -150,34 +168,9 @@ let truncate = Truncate.run
|
||||||
of a new variable that is the result of the operation on A and B.
|
of a new variable that is the result of the operation on A and B.
|
||||||
For instance, normal(0, 1) + normal(1, 1) -> normal(1, 2).
|
For instance, normal(0, 1) + normal(1, 1) -> normal(1, 2).
|
||||||
In general, this is implemented via convolution.
|
In general, this is implemented via convolution.
|
||||||
|
|
||||||
TODO: It would be useful to be able to pass in a paramater to get this to run either with convolution or monte carlo.
|
|
||||||
*/
|
*/
|
||||||
module AlgebraicCombination = {
|
module AlgebraicCombination = {
|
||||||
let runConvolution = (
|
module InputValidator = {
|
||||||
toPointSet: toPointSetFn,
|
|
||||||
arithmeticOperation: Operation.convolutionOperation,
|
|
||||||
t1: t,
|
|
||||||
t2: t,
|
|
||||||
) =>
|
|
||||||
E.R.merge(toPointSet(t1), toPointSet(t2))->E.R2.fmap(((a, b)) =>
|
|
||||||
PointSetDist.combineAlgebraically(arithmeticOperation, a, b)
|
|
||||||
)
|
|
||||||
|
|
||||||
let runMonteCarlo = (
|
|
||||||
toSampleSet: toSampleSetFn,
|
|
||||||
arithmeticOperation: Operation.algebraicOperation,
|
|
||||||
t1: t,
|
|
||||||
t2: t,
|
|
||||||
): result<t, error> => {
|
|
||||||
let fn = Operation.Algebraic.toFn(arithmeticOperation)
|
|
||||||
E.R.merge(toSampleSet(t1), toSampleSet(t2))
|
|
||||||
->E.R.bind(((t1, t2)) => {
|
|
||||||
SampleSetDist.map2(~fn, ~t1, ~t2)->E.R2.errMap(x => DistributionTypes.OperationError(x))
|
|
||||||
})
|
|
||||||
->E.R2.fmap(r => DistributionTypes.SampleSet(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
It would be good to also do a check to make sure that probability mass for the second
|
It would be good to also do a check to make sure that probability mass for the second
|
||||||
operand, at value 1.0, is 0 (or approximately 0). However, we'd ideally want to check
|
operand, at value 1.0, is 0 (or approximately 0). However, we'd ideally want to check
|
||||||
|
@ -204,26 +197,63 @@ module AlgebraicCombination = {
|
||||||
switch items {
|
switch items {
|
||||||
| Error(r) => Some(r)
|
| Error(r) => Some(r)
|
||||||
| Ok([true, _]) =>
|
| Ok([true, _]) =>
|
||||||
Some(LogarithmOfDistributionError("First input must completely greater than 0"))
|
Some(LogarithmOfDistributionError("First input must be completely greater than 0"))
|
||||||
| Ok([false, true]) =>
|
| Ok([false, true]) =>
|
||||||
Some(LogarithmOfDistributionError("Second input must completely greater than 0"))
|
Some(LogarithmOfDistributionError("Second input must be completely greater than 0"))
|
||||||
| Ok([false, false]) => None
|
| Ok([false, false]) => None
|
||||||
| Ok(_) => Some(Unreachable)
|
| Ok(_) => Some(Unreachable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let getInvalidOperationError = (
|
let run = (t1: t, t2: t, ~toPointSetFn: toPointSetFn, ~arithmeticOperation): option<error> => {
|
||||||
t1: t,
|
|
||||||
t2: t,
|
|
||||||
~toPointSetFn: toPointSetFn,
|
|
||||||
~arithmeticOperation,
|
|
||||||
): option<error> => {
|
|
||||||
if arithmeticOperation == #Logarithm {
|
if arithmeticOperation == #Logarithm {
|
||||||
getLogarithmInputError(t1, t2, ~toPointSetFn)
|
getLogarithmInputError(t1, t2, ~toPointSetFn)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module StrategyCallOnValidatedInputs = {
|
||||||
|
let convolution = (
|
||||||
|
toPointSet: toPointSetFn,
|
||||||
|
arithmeticOperation: Operation.convolutionOperation,
|
||||||
|
t1: t,
|
||||||
|
t2: t,
|
||||||
|
): result<t, error> =>
|
||||||
|
E.R.merge(toPointSet(t1), toPointSet(t2))
|
||||||
|
->E.R2.fmap(((a, b)) => PointSetDist.combineAlgebraically(arithmeticOperation, a, b))
|
||||||
|
->E.R2.fmap(r => DistributionTypes.PointSet(r))
|
||||||
|
|
||||||
|
let monteCarlo = (
|
||||||
|
toSampleSet: toSampleSetFn,
|
||||||
|
arithmeticOperation: Operation.algebraicOperation,
|
||||||
|
t1: t,
|
||||||
|
t2: t,
|
||||||
|
): result<t, error> => {
|
||||||
|
let fn = Operation.Algebraic.toFn(arithmeticOperation)
|
||||||
|
E.R.merge(toSampleSet(t1), toSampleSet(t2))
|
||||||
|
->E.R.bind(((t1, t2)) => {
|
||||||
|
SampleSetDist.map2(~fn, ~t1, ~t2)->E.R2.errMap(x => DistributionTypes.OperationError(x))
|
||||||
|
})
|
||||||
|
->E.R2.fmap(r => DistributionTypes.SampleSet(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
let symbolic = (
|
||||||
|
arithmeticOperation: Operation.algebraicOperation,
|
||||||
|
t1: t,
|
||||||
|
t2: t,
|
||||||
|
): SymbolicDistTypes.analyticalSimplificationResult => {
|
||||||
|
switch (t1, t2) {
|
||||||
|
| (DistributionTypes.Symbolic(d1), DistributionTypes.Symbolic(d2)) =>
|
||||||
|
SymbolicDist.T.tryAnalyticalSimplification(d1, d2, arithmeticOperation)
|
||||||
|
| _ => #NoSolution
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module StrategyChooser = {
|
||||||
|
type specificStrategy = [#AsSymbolic | #AsMonteCarlo | #AsConvolution]
|
||||||
|
|
||||||
//I'm (Ozzie) really just guessing here, very little idea what's best
|
//I'm (Ozzie) really just guessing here, very little idea what's best
|
||||||
let expectedConvolutionCost: t => int = x =>
|
let expectedConvolutionCost: t => int = x =>
|
||||||
|
@ -236,58 +266,49 @@ module AlgebraicCombination = {
|
||||||
| _ => MagicNumbers.OpCost.wildcardCost
|
| _ => MagicNumbers.OpCost.wildcardCost
|
||||||
}
|
}
|
||||||
|
|
||||||
type calculationStrategy = MonteCarloStrat | ConvolutionStrat(Operation.convolutionOperation)
|
let hasSampleSetDist = (t1: t, t2: t): bool => isSampleSetSet(t1) || isSampleSetSet(t2)
|
||||||
|
|
||||||
let chooseConvolutionOrMonteCarloDefault = (
|
let convolutionIsFasterThanMonteCarlo = (t1: t, t2: t): bool =>
|
||||||
op: Operation.algebraicOperation,
|
expectedConvolutionCost(t1) * expectedConvolutionCost(t2) < MagicNumbers.OpCost.monteCarloCost
|
||||||
t2: t,
|
|
||||||
t1: t,
|
let preferConvolutionToMonteCarlo = (t1, t2, arithmeticOperation) => {
|
||||||
): calculationStrategy =>
|
!hasSampleSetDist(t1, t2) &&
|
||||||
switch op {
|
Operation.Convolution.canDoAlgebraicOperation(arithmeticOperation) &&
|
||||||
| #Divide
|
convolutionIsFasterThanMonteCarlo(t1, t2)
|
||||||
| #Power
|
|
||||||
| #Logarithm =>
|
|
||||||
MonteCarloStrat
|
|
||||||
| (#Add | #Subtract | #Multiply) as convOp =>
|
|
||||||
expectedConvolutionCost(t1) * expectedConvolutionCost(t2) > MagicNumbers.OpCost.monteCarloCost
|
|
||||||
? MonteCarloStrat
|
|
||||||
: ConvolutionStrat(convOp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tryAnalyticalSimplification = (
|
let run = (~t1: t, ~t2: t, ~arithmeticOperation): specificStrategy => {
|
||||||
arithmeticOperation: Operation.algebraicOperation,
|
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||||
t1: t,
|
| #AnalyticalSolution(_)
|
||||||
t2: t,
|
| #Error(_) =>
|
||||||
): option<SymbolicDistTypes.analyticalSimplificationResult> => {
|
#AsSymbolic
|
||||||
switch (t1, t2) {
|
| #NoSolution =>
|
||||||
| (DistributionTypes.Symbolic(d1), DistributionTypes.Symbolic(d2)) =>
|
preferConvolutionToMonteCarlo(t1, t2, arithmeticOperation) ? #AsConvolution : #AsMonteCarlo
|
||||||
Some(SymbolicDist.T.tryAnalyticalSimplification(d1, d2, arithmeticOperation))
|
}
|
||||||
| _ => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let runDefault = (
|
let runStrategyOnValidatedInputs = (
|
||||||
t1: t,
|
~t1: t,
|
||||||
|
~t2: t,
|
||||||
|
~arithmeticOperation,
|
||||||
|
~strategy: StrategyChooser.specificStrategy,
|
||||||
~toPointSetFn: toPointSetFn,
|
~toPointSetFn: toPointSetFn,
|
||||||
~toSampleSetFn: toSampleSetFn,
|
~toSampleSetFn: toSampleSetFn,
|
||||||
~arithmeticOperation,
|
|
||||||
~t2: t,
|
|
||||||
): result<t, error> => {
|
): result<t, error> => {
|
||||||
switch tryAnalyticalSimplification(arithmeticOperation, t1, t2) {
|
switch strategy {
|
||||||
| Some(#AnalyticalSolution(symbolicDist)) => Ok(Symbolic(symbolicDist))
|
| #AsMonteCarlo =>
|
||||||
| Some(#Error(e)) => Error(OperationError(e))
|
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
||||||
| Some(#NoSolution)
|
| #AsSymbolic =>
|
||||||
| None =>
|
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||||
switch getInvalidOperationError(t1, t2, ~toPointSetFn, ~arithmeticOperation) {
|
| #AnalyticalSolution(symbolicDist) => Ok(Symbolic(symbolicDist))
|
||||||
| Some(e) => Error(e)
|
| #Error(e) => Error(OperationError(e))
|
||||||
| None =>
|
| #NoSolution => Error(Unreachable)
|
||||||
switch chooseConvolutionOrMonteCarloDefault(arithmeticOperation, t1, t2) {
|
|
||||||
| MonteCarloStrat => runMonteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
|
||||||
| ConvolutionStrat(convOp) =>
|
|
||||||
runConvolution(toPointSetFn, convOp, t1, t2)->E.R2.fmap(r => DistributionTypes.PointSet(
|
|
||||||
r,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
| #AsConvolution =>
|
||||||
|
switch Operation.Convolution.fromAlgebraicOperation(arithmeticOperation) {
|
||||||
|
| Some(convOp) => StrategyCallOnValidatedInputs.convolution(toPointSetFn, convOp, t1, t2)
|
||||||
|
| None => Error(Unreachable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,27 +321,38 @@ module AlgebraicCombination = {
|
||||||
~arithmeticOperation: Operation.algebraicOperation,
|
~arithmeticOperation: Operation.algebraicOperation,
|
||||||
~t2: t,
|
~t2: t,
|
||||||
): result<t, error> => {
|
): result<t, error> => {
|
||||||
switch strategy {
|
let invalidOperationError = InputValidator.run(t1, t2, ~arithmeticOperation, ~toPointSetFn)
|
||||||
| AsDefault => runDefault(t1, ~toPointSetFn, ~toSampleSetFn, ~arithmeticOperation, ~t2)
|
switch (invalidOperationError, strategy) {
|
||||||
| AsSymbolic =>
|
| (Some(e), _) => Error(e)
|
||||||
switch tryAnalyticalSimplification(arithmeticOperation, t1, t2) {
|
| (None, AsDefault) => {
|
||||||
| Some(#AnalyticalSolution(symbolicDist)) => Ok(Symbolic(symbolicDist))
|
let chooseStrategy = StrategyChooser.run(~arithmeticOperation, ~t1, ~t2)
|
||||||
| Some(#NoSolution) => Error(RequestedStrategyInvalidError(`No analytical solution`))
|
runStrategyOnValidatedInputs(
|
||||||
| None => Error(RequestedStrategyInvalidError("Inputs were not even symbolic"))
|
~t1,
|
||||||
| Some(#Error(err)) => Error(OperationError(err))
|
~t2,
|
||||||
|
~strategy=chooseStrategy,
|
||||||
|
~arithmeticOperation,
|
||||||
|
~toPointSetFn,
|
||||||
|
~toSampleSetFn,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
| AsConvolution => {
|
| (None, AsMonteCarlo) =>
|
||||||
let errString = opString => `Can't convolve on ${opString}`
|
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
||||||
switch arithmeticOperation {
|
| (None, AsSymbolic) =>
|
||||||
| (#Add | #Subtract | #Multiply) as convOp =>
|
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||||
runConvolution(toPointSetFn, convOp, t1, t2)->E.R2.fmap(r => DistributionTypes.PointSet(
|
| #AnalyticalSolution(symbolicDist) => Ok(Symbolic(symbolicDist))
|
||||||
r,
|
| #NoSolution => Error(RequestedStrategyInvalidError(`No analytic solution for inputs`))
|
||||||
))
|
| #Error(err) => Error(OperationError(err))
|
||||||
| (#Divide | #Power | #Logarithm) as op =>
|
|
||||||
op->Operation.Algebraic.toString->errString->RequestedStrategyInvalidError->Error
|
|
||||||
}
|
}
|
||||||
|
| (None, AsConvolution) =>
|
||||||
|
switch Operation.Convolution.fromAlgebraicOperation(arithmeticOperation) {
|
||||||
|
| None => {
|
||||||
|
let errString = `Convolution not supported for ${Operation.Algebraic.toString(
|
||||||
|
arithmeticOperation,
|
||||||
|
)}`
|
||||||
|
Error(RequestedStrategyInvalidError(errString))
|
||||||
|
}
|
||||||
|
| Some(convOp) => StrategyCallOnValidatedInputs.convolution(toPointSetFn, convOp, t1, t2)
|
||||||
}
|
}
|
||||||
| AsMonteCarlo => runMonteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,3 +69,6 @@ let mixture: (
|
||||||
~scaleMultiplyFn: scaleMultiplyFn,
|
~scaleMultiplyFn: scaleMultiplyFn,
|
||||||
~pointwiseAddFn: pointwiseAddFn,
|
~pointwiseAddFn: pointwiseAddFn,
|
||||||
) => result<t, error>
|
) => result<t, error>
|
||||||
|
|
||||||
|
let isSymbolic: t => bool
|
||||||
|
let isPointSet: t => bool
|
||||||
|
|
|
@ -263,4 +263,4 @@ let combineShapesContinuousDiscrete = (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let isOrdered = (a: XYShape.T.t): bool => E.A.Sorted.Floats.isSorted(a.xs)
|
let isOrdered = (a: XYShape.T.t): bool => E.A.Floats.isSorted(a.xs)
|
||||||
|
|
|
@ -39,28 +39,6 @@ module Internals = {
|
||||||
module T = {
|
module T = {
|
||||||
type t = array<float>
|
type t = array<float>
|
||||||
|
|
||||||
let splitContinuousAndDiscrete = (sortedArray: t) => {
|
|
||||||
let continuous = []
|
|
||||||
let discrete = E.FloatFloatMap.empty()
|
|
||||||
Belt.Array.forEachWithIndex(sortedArray, (index, element) => {
|
|
||||||
let maxIndex = (sortedArray |> Array.length) - 1
|
|
||||||
let possiblySimilarElements = switch index {
|
|
||||||
| 0 => [index + 1]
|
|
||||||
| n if n == maxIndex => [index - 1]
|
|
||||||
| _ => [index - 1, index + 1]
|
|
||||||
} |> Belt.Array.map(_, r => sortedArray[r])
|
|
||||||
let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
|
||||||
hasSimilarElement
|
|
||||||
? E.FloatFloatMap.increment(element, discrete)
|
|
||||||
: {
|
|
||||||
let _ = Js.Array.push(element, continuous)
|
|
||||||
}
|
|
||||||
|
|
||||||
()
|
|
||||||
})
|
|
||||||
(continuous, discrete)
|
|
||||||
}
|
|
||||||
|
|
||||||
let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => {
|
let xWidthToUnitWidth = (samples, outputXYPoints, xWidth) => {
|
||||||
let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0)
|
let xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0)
|
||||||
let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints)
|
let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints)
|
||||||
|
@ -85,7 +63,11 @@ let toPointSetDist = (
|
||||||
(),
|
(),
|
||||||
): Internals.Types.outputs => {
|
): Internals.Types.outputs => {
|
||||||
Array.fast_sort(compare, samples)
|
Array.fast_sort(compare, samples)
|
||||||
let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples)
|
let minDiscreteToKeep = MagicNumbers.ToPointSet.minDiscreteToKeep(samples)
|
||||||
|
let (continuousPart, discretePart) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(
|
||||||
|
samples,
|
||||||
|
~minDiscreteWeight=minDiscreteToKeep,
|
||||||
|
)
|
||||||
let length = samples |> E.A.length |> float_of_int
|
let length = samples |> E.A.length |> float_of_int
|
||||||
let discrete: PointSetTypes.discreteShape =
|
let discrete: PointSetTypes.discreteShape =
|
||||||
discretePart
|
discretePart
|
||||||
|
|
|
@ -22,3 +22,16 @@ module OpCost = {
|
||||||
let wildcardCost = 1000
|
let wildcardCost = 1000
|
||||||
let monteCarloCost = Environment.defaultSampleCount
|
let monteCarloCost = Environment.defaultSampleCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module ToPointSet = {
|
||||||
|
/*
|
||||||
|
This function chooses the minimum amount of duplicate samples that need
|
||||||
|
to exist in order for this to be considered discrete. The tricky thing
|
||||||
|
is that there are some operations that create duplicate continuous samples,
|
||||||
|
so we can't guarantee that these only will occur because the fundamental
|
||||||
|
structure is meant to be discrete. I chose this heuristic because I think
|
||||||
|
it would strike a reasonable trade-off, but I’m really unsure what’s
|
||||||
|
best right now.
|
||||||
|
*/
|
||||||
|
let minDiscreteToKeep = samples => max(20, E.A.length(samples) / 50)
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,5 @@ type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
let evaluate = Expression.evaluate
|
let evaluate = Expression.evaluate
|
||||||
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
||||||
|
let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings
|
||||||
let parse = Expression.parse
|
let parse = Expression.parse
|
||||||
let parseOuter = Expression.parseOuter
|
|
||||||
let parsePartial = Expression.parsePartial
|
|
||||||
|
|
|
@ -18,12 +18,15 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
let evaluateUsingOptions: (
|
let evaluateUsingOptions: (
|
||||||
~environment: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.environment>,
|
~environment: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.environment>,
|
||||||
~externalBindings: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings>,
|
~externalBindings: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings>,
|
||||||
~isPartial: option<bool>,
|
|
||||||
string,
|
string,
|
||||||
) => result<expressionValue, errorValue>
|
) => result<expressionValue, errorValue>
|
||||||
@genType
|
@genType
|
||||||
|
let evaluatePartialUsingExternalBindings: (
|
||||||
|
string,
|
||||||
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings,
|
||||||
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.environment,
|
||||||
|
) => result<externalBindings, errorValue>
|
||||||
|
@genType
|
||||||
let evaluate: string => result<expressionValue, errorValue>
|
let evaluate: string => result<expressionValue, errorValue>
|
||||||
|
|
||||||
let parse: string => result<Expression.expression, errorValue>
|
let parse: string => result<Expression.expression, errorValue>
|
||||||
let parseOuter: string => result<Expression.expression, errorValue>
|
|
||||||
let parsePartial: string => result<Expression.expression, errorValue>
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
open ReducerInterface.ExpressionValue
|
open ReducerInterface.ExpressionValue
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
|
@ -20,12 +21,12 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> =>
|
||||||
}
|
}
|
||||||
|
|
||||||
let constructRecord = arrayOfPairs => {
|
let constructRecord = arrayOfPairs => {
|
||||||
Belt.Array.map(arrayOfPairs, pairValue => {
|
Belt.Array.map(arrayOfPairs, pairValue =>
|
||||||
switch pairValue {
|
switch pairValue {
|
||||||
| EvArray([EvString(key), valueValue]) => (key, valueValue)
|
| EvArray([EvString(key), valueValue]) => (key, valueValue)
|
||||||
| _ => ("wrong key type", pairValue->toStringWithType->EvString)
|
| _ => ("wrong key type", pairValue->toStringWithType->EvString)
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
->Js.Dict.fromArray
|
->Js.Dict.fromArray
|
||||||
->EvRecord
|
->EvRecord
|
||||||
->Ok
|
->Ok
|
||||||
|
@ -68,6 +69,20 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> =>
|
||||||
value->Ok
|
value->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let doSetBindings = (
|
||||||
|
externalBindings: externalBindings,
|
||||||
|
symbol: string,
|
||||||
|
value: expressionValue,
|
||||||
|
) => {
|
||||||
|
Bindings.fromExternalBindings(externalBindings)
|
||||||
|
->Belt.Map.String.set(symbol, value)
|
||||||
|
->Bindings.toExternalBindings
|
||||||
|
->EvRecord
|
||||||
|
->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok
|
||||||
|
|
||||||
switch call {
|
switch call {
|
||||||
| ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) =>
|
| ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) =>
|
||||||
arrayAtIndex(aValueArray, fIndex)
|
arrayAtIndex(aValueArray, fIndex)
|
||||||
|
@ -78,6 +93,9 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> =>
|
||||||
| ("inspect", [value, EvString(label)]) => inspectLabel(value, label)
|
| ("inspect", [value, EvString(label)]) => inspectLabel(value, label)
|
||||||
| ("inspect", [value]) => inspect(value)
|
| ("inspect", [value]) => inspect(value)
|
||||||
| ("inspectPerformance", [value, EvString(label)]) => inspectPerformance(value, label)
|
| ("inspectPerformance", [value, EvString(label)]) => inspectPerformance(value, label)
|
||||||
|
| ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) =>
|
||||||
|
doSetBindings(externalBindings, symbol, value)
|
||||||
|
| ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings)
|
||||||
| call => callMathJs(call)
|
| call => callMathJs(call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,179 +3,137 @@
|
||||||
they take expressions as parameters and return a new expression.
|
they take expressions as parameters and return a new expression.
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
Macros are used to define language building blocks. They are like Lisp macros.
|
||||||
*/
|
*/
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
open Reducer_Expression_ExpressionBuilder
|
||||||
open Reducer_ErrorValue
|
|
||||||
|
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type environment = ExpressionValue.environment
|
type environment = ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type reducerFn = (
|
|
||||||
expression,
|
|
||||||
ExpressionT.bindings,
|
|
||||||
environment,
|
|
||||||
) => result<ExpressionValue.expressionValue, errorValue>
|
|
||||||
|
|
||||||
let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
|
|
||||||
expression,
|
|
||||||
errorValue,
|
|
||||||
> => {
|
|
||||||
let getParameters = (bindings: ExpressionT.bindings): array<string> => {
|
|
||||||
let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([]))
|
|
||||||
switch eParameters {
|
|
||||||
| EParameters(parameters) => parameters
|
|
||||||
| _ => []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let putParameters = (
|
|
||||||
bindings: ExpressionT.bindings,
|
|
||||||
parameters: array<string>,
|
|
||||||
): ExpressionT.bindings =>
|
|
||||||
Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters))
|
|
||||||
|
|
||||||
let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) =>
|
|
||||||
switch Js.Array2.some(parameters, a => a == aSymbol) {
|
|
||||||
| true => defaultExpression->Ok // We cannot bind the parameters with global values
|
|
||||||
| false =>
|
|
||||||
switch bindings->Belt.Map.String.get(aSymbol) {
|
|
||||||
| Some(boundExpression) => boundExpression->Ok
|
|
||||||
| None => RESymbolNotFound(aSymbol)->Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) =>
|
|
||||||
switch Js.Array2.some(parameters, a => a == aSymbol) {
|
|
||||||
| true => defaultExpression->Ok // We cannot bind the parameters with global values
|
|
||||||
| false =>
|
|
||||||
switch bindings->Belt.Map.String.get(aSymbol) {
|
|
||||||
| Some(boundExpression) => boundExpression->Ok
|
|
||||||
| None => defaultExpression->Ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch expression {
|
|
||||||
| ExpressionT.EValue(EvSymbol(aSymbol)) => {
|
|
||||||
let parameters = getParameters(bindings)
|
|
||||||
answerBindingIfNotParameter(aSymbol, expression, parameters, bindings)
|
|
||||||
}
|
|
||||||
| ExpressionT.EValue(EvCall(aSymbol)) => {
|
|
||||||
let parameters = getParameters(bindings)
|
|
||||||
answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings)
|
|
||||||
}
|
|
||||||
| ExpressionT.EValue(_) => expression->Ok
|
|
||||||
| ExpressionT.EBindings(_) => expression->Ok
|
|
||||||
| ExpressionT.EParameters(_) => expression->Ok
|
|
||||||
| ExpressionT.EList(list{
|
|
||||||
ExpressionT.EValue(EvCall("$lambda")),
|
|
||||||
ExpressionT.EParameters(parameters),
|
|
||||||
expr,
|
|
||||||
}) => {
|
|
||||||
let oldParameters = getParameters(bindings)
|
|
||||||
let newParameters = oldParameters->Js.Array2.concat(parameters)
|
|
||||||
let newBindings = putParameters(bindings, newParameters)
|
|
||||||
let rNewExpr = replaceSymbols(expr, newBindings)
|
|
||||||
rNewExpr->Result.flatMap(newExpr =>
|
|
||||||
ExpressionT.EList(list{
|
|
||||||
ExpressionT.EValue(EvCall("$lambda")),
|
|
||||||
ExpressionT.EParameters(parameters),
|
|
||||||
newExpr,
|
|
||||||
})->Ok
|
|
||||||
)
|
|
||||||
}
|
|
||||||
| ExpressionT.EList(list) => {
|
|
||||||
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->replaceSymbols(bindings)
|
|
||||||
->Result.flatMap(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
racc->Result.map(acc => acc->ExpressionT.EList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let dispatchMacroCall = (
|
let dispatchMacroCall = (
|
||||||
list: list<expression>,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
environment,
|
environment,
|
||||||
reduceExpression: reducerFn,
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
): result<expression, 'e> => {
|
): result<expression, errorValue> => {
|
||||||
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
|
let doBindStatement = (bindingExpr: expression, statement: expression, environment) =>
|
||||||
switch statement {
|
switch statement {
|
||||||
| ExpressionT.EList(list{
|
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||||
ExpressionT.EValue(EvCall("$let")),
|
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||||
ExpressionT.EValue(EvSymbol(aSymbol)),
|
|
||||||
expressionToReduce,
|
|
||||||
}) => {
|
|
||||||
let rNewExpressionToReduce = replaceSymbols(expressionToReduce, bindings)
|
|
||||||
|
|
||||||
let rNewValue =
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
reduceExpression(newExpressionToReduce, bindings, environment)
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
|
rNewStatement->Result.map(newStatement =>
|
||||||
|
eFunction(
|
||||||
|
"$setBindings",
|
||||||
|
list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement},
|
||||||
)
|
)
|
||||||
|
|
||||||
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
|
||||||
rNewExpression->Result.map(newExpression =>
|
|
||||||
Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
|
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
| _ => REAssignmentExpected->Error
|
| _ => REAssignmentExpected->Error
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
|
|
||||||
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
|
let doBindExpression = (bindingExpr: expression, statement: expression, environment) =>
|
||||||
let reducedBindings = bindings->Belt.Map.String.keep((_key, value) =>
|
switch statement {
|
||||||
switch value {
|
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||||
| ExpressionT.EValue(_) => true
|
let rExternalBindingsValue = reduceExpression(
|
||||||
| _ => false
|
bindingExpr,
|
||||||
}
|
Belt.Map.String.fromArray([("x", ExpressionValue.EvNumber(666.))]),
|
||||||
|
// bindingsToHandDown,
|
||||||
|
environment,
|
||||||
|
)
|
||||||
|
|
||||||
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
|
rNewStatement->Result.map(newStatement =>
|
||||||
|
eFunction(
|
||||||
|
"$exportBindings",
|
||||||
|
list{
|
||||||
|
eFunction(
|
||||||
|
"$setBindings",
|
||||||
|
list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
let externalBindings = reducedBindings->Belt.Map.String.reduce(emptyDictionary, (
|
|
||||||
acc,
|
|
||||||
key,
|
|
||||||
expressionValue,
|
|
||||||
) => {
|
|
||||||
let value = switch expressionValue {
|
|
||||||
| ExpressionT.EValue(aValue) => aValue
|
|
||||||
| _ => EvSymbol("internal")
|
|
||||||
}
|
|
||||||
Js.Dict.set(acc, key, value)
|
|
||||||
acc
|
|
||||||
})
|
})
|
||||||
externalBindings->ExpressionValue.EvRecord->ExpressionT.EValue->Ok
|
}
|
||||||
|
| _ => {
|
||||||
|
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||||
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
|
rNewStatement
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) =>
|
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _environment): result<
|
||||||
switch expression {
|
expression,
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) =>
|
errorValue,
|
||||||
REExpressionExpected->Error
|
> => {
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$exportVariablesExpression"))}) =>
|
let exprsArray = Belt.List.toArray(exprs)
|
||||||
doExportVariableExpression(bindings)
|
let maxIndex = Js.Array2.length(exprsArray) - 1
|
||||||
| _ => replaceSymbols(expression, bindings)
|
exprsArray->Js.Array2.reducei((acc, statement, index) =>
|
||||||
|
if index == 0 {
|
||||||
|
if index == maxIndex {
|
||||||
|
eBindExpressionDefault(statement)
|
||||||
|
} else {
|
||||||
|
eBindStatementDefault(statement)
|
||||||
|
}
|
||||||
|
} else if index == maxIndex {
|
||||||
|
eBindExpression(acc, statement)
|
||||||
|
} else {
|
||||||
|
eBindStatement(acc, statement)
|
||||||
|
}
|
||||||
|
, eSymbol("undefined block"))->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
switch list {
|
let doLambdaDefinition = (
|
||||||
| list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok
|
bindings: ExpressionT.bindings,
|
||||||
|
parameters: array<string>,
|
||||||
|
lambdaDefinition: ExpressionT.expression,
|
||||||
|
) => eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition)->Ok
|
||||||
|
|
||||||
|
let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment) =>
|
||||||
|
switch aList {
|
||||||
| list{
|
| list{
|
||||||
ExpressionT.EValue(EvCall("$$bindStatement")),
|
ExpressionT.EValue(EvCall("$$bindStatement")),
|
||||||
ExpressionT.EBindings(bindings),
|
bindingExpr: ExpressionT.expression,
|
||||||
statement,
|
statement,
|
||||||
} =>
|
} =>
|
||||||
doBindStatement(statement, bindings)
|
doBindStatement(bindingExpr, statement, environment)
|
||||||
|
| list{ExpressionT.EValue(EvCall("$$bindStatement")), statement} =>
|
||||||
|
// bindings of the context are used when there is no binding expression
|
||||||
|
doBindStatement(eRecord(Bindings.toExternalBindings(bindings)), statement, environment)
|
||||||
| list{
|
| list{
|
||||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||||
ExpressionT.EBindings(bindings),
|
bindingExpr: ExpressionT.expression,
|
||||||
expression,
|
expression,
|
||||||
} =>
|
} =>
|
||||||
doBindExpression(expression, bindings)
|
doBindExpression(bindingExpr, expression, environment)
|
||||||
| _ => list->ExpressionT.EList->Ok
|
| list{ExpressionT.EValue(EvCall("$$bindExpression")), expression} =>
|
||||||
|
// bindings of the context are used when there is no binding expression
|
||||||
|
doBindExpression(eRecord(Bindings.toExternalBindings(bindings)), expression, environment)
|
||||||
|
| list{ExpressionT.EValue(EvCall("$$block")), ...exprs} => doBlock(exprs, bindings, environment)
|
||||||
|
| list{
|
||||||
|
ExpressionT.EValue(EvCall("$$lambda")),
|
||||||
|
ExpressionT.EValue(EvArrayString(parameters)),
|
||||||
|
lambdaDefinition,
|
||||||
|
} =>
|
||||||
|
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
||||||
|
| _ => ExpressionT.EList(aList)->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
switch macroExpression {
|
||||||
|
| EList(aList) => expandExpressionList(aList, bindings, environment)
|
||||||
|
| _ => macroExpression->Ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
module Builder = Reducer_Expression_Builder
|
module Bindings = Reducer_Expression_Bindings
|
||||||
module BuiltIn = Reducer_Dispatch_BuiltIn
|
module BuiltIn = Reducer_Dispatch_BuiltIn
|
||||||
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module Extra = Reducer_Extra
|
module Extra = Reducer_Extra
|
||||||
|
module Lambda = Reducer_Expression_Lambda
|
||||||
|
module Macro = Reducer_Expression_Macro
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module T = Reducer_Expression_T
|
module T = Reducer_Expression_T
|
||||||
|
|
||||||
open Reducer_ErrorValue
|
|
||||||
|
|
||||||
type environment = ReducerInterface_ExpressionValue.environment
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = T.expression
|
type expression = T.expression
|
||||||
|
@ -16,30 +17,6 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
type t = expression
|
type t = expression
|
||||||
|
|
||||||
external castExpressionToInternalCode: expression => internalCode = "%identity"
|
|
||||||
external castInternalCodeToExpression: internalCode => expression = "%identity"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Shows the expression as text of expression
|
|
||||||
*/
|
|
||||||
let rec toString = expression =>
|
|
||||||
switch expression {
|
|
||||||
| T.EBindings(_) => "$$bound"
|
|
||||||
| T.EParameters(params) => `(${Js.Array2.toString(params)})`
|
|
||||||
| T.EList(aList) =>
|
|
||||||
`(${Belt.List.map(aList, aValue => toString(aValue))
|
|
||||||
->Extra.List.interperse(" ")
|
|
||||||
->Belt.List.toArray
|
|
||||||
->Js.String.concatMany("")})`
|
|
||||||
| EValue(aValue) => ExpressionValue.toString(aValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
let toStringResult = codeResult =>
|
|
||||||
switch codeResult {
|
|
||||||
| Ok(a) => `Ok(${toString(a)})`
|
|
||||||
| Error(m) => `Error(${Js.String.make(m)})`
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Converts a MathJs code to expression
|
Converts a MathJs code to expression
|
||||||
*/
|
*/
|
||||||
|
@ -49,159 +26,70 @@ let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
|
||||||
let parse = (mathJsCode: string): result<t, errorValue> =>
|
let parse = (mathJsCode: string): result<t, errorValue> =>
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
|
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
|
||||||
|
|
||||||
let parsePartial = (mathJsCode: string): result<t, errorValue> =>
|
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromPartialNode)
|
|
||||||
|
|
||||||
let parseOuter = (mathJsCode: string): result<t, errorValue> =>
|
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromOuterNode)
|
|
||||||
|
|
||||||
let defaultBindings: T.bindings = Belt.Map.String.empty
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recursively evaluate/reduce the expression (Lisp AST)
|
Recursively evaluate/reduce the expression (Lisp AST)
|
||||||
*/
|
*/
|
||||||
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
||||||
expressionValue,
|
expressionValue,
|
||||||
'e,
|
'e,
|
||||||
> => {
|
> =>
|
||||||
/*
|
|
||||||
Macros are like functions but instead of taking values as parameters,
|
|
||||||
they take expressions as parameters and return a new expression.
|
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
|
||||||
*/
|
|
||||||
let doMacroCall = (list: list<t>, bindings: T.bindings, environment: environment): result<
|
|
||||||
t,
|
|
||||||
'e,
|
|
||||||
> =>
|
|
||||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, reduceExpression)
|
|
||||||
|
|
||||||
let applyParametersToLambda = (
|
|
||||||
internal: internalCode,
|
|
||||||
parameters: array<string>,
|
|
||||||
args: list<expressionValue>,
|
|
||||||
environment,
|
|
||||||
): result<expressionValue, 'e> => {
|
|
||||||
let expr = castInternalCodeToExpression(internal)
|
|
||||||
let parameterList = parameters->Belt.List.fromArray
|
|
||||||
let zippedParameterList = parameterList->Belt.List.zip(args)
|
|
||||||
let bindings = Belt.List.reduce(zippedParameterList, defaultBindings, (a, (p, e)) =>
|
|
||||||
a->Belt.Map.String.set(p, e->T.EValue)
|
|
||||||
)
|
|
||||||
let newExpression = Builder.passToFunction(
|
|
||||||
"$$bindExpression",
|
|
||||||
list{Builder.passToFunction("$$bindings", list{}), expr},
|
|
||||||
)
|
|
||||||
reduceExpression(newExpression, bindings, environment)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
|
||||||
*/
|
|
||||||
let reduceValueList = (valueList: list<expressionValue>, environment): result<
|
|
||||||
expressionValue,
|
|
||||||
'e,
|
|
||||||
> =>
|
|
||||||
switch valueList {
|
|
||||||
| list{EvCall(fName), ...args} =>
|
|
||||||
(fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment)
|
|
||||||
// "(lambda(x=>internal) param)"
|
|
||||||
| list{EvLambda((parameters, internal)), ...args} =>
|
|
||||||
applyParametersToLambda(internal, parameters, args, environment)
|
|
||||||
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
let rec seekMacros = (expression: t, bindings: T.bindings, environment): result<t, 'e> =>
|
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EValue(_value) => expression->Ok
|
|
||||||
| T.EBindings(_value) => expression->Ok
|
|
||||||
| T.EParameters(_value) => expression->Ok
|
|
||||||
| T.EList(list) => {
|
|
||||||
let racc: result<list<t>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
|
|
||||||
racc,
|
|
||||||
each: expression,
|
|
||||||
) =>
|
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->seekMacros(bindings, environment)
|
|
||||||
->Result.flatMap(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
racc->Result.flatMap(acc => acc->doMacroCall(bindings, environment))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rec reduceExpandedExpression = (expression: t, environment): result<expressionValue, 'e> =>
|
|
||||||
switch expression {
|
|
||||||
| T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) =>
|
|
||||||
EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok
|
|
||||||
| T.EValue(value) => value->Ok
|
| T.EValue(value) => value->Ok
|
||||||
| T.EList(list) => {
|
| T.EList(list) =>
|
||||||
let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
|
switch list {
|
||||||
|
| list{EValue(EvCall(fName)), ..._args} =>
|
||||||
|
switch Macro.isMacroName(fName) {
|
||||||
|
// A macro expands then reduces itself
|
||||||
|
| true => Macro.doMacroCall(expression, bindings, environment, reduceExpression)
|
||||||
|
| false => reduceExpressionList(list, bindings, environment)
|
||||||
|
}
|
||||||
|
| _ => reduceExpressionList(list, bindings, environment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
and reduceExpressionList = (
|
||||||
|
expressions: list<t>,
|
||||||
|
bindings: T.bindings,
|
||||||
|
environment: environment,
|
||||||
|
): result<expressionValue, 'e> => {
|
||||||
|
let racc: result<list<expressionValue>, 'e> = expressions->Belt.List.reduceReverse(Ok(list{}), (
|
||||||
racc,
|
racc,
|
||||||
each: expression,
|
each: expression,
|
||||||
) =>
|
) =>
|
||||||
racc->Result.flatMap(acc => {
|
racc->Result.flatMap(acc => {
|
||||||
each
|
each
|
||||||
->reduceExpandedExpression(environment)
|
->reduceExpression(bindings, environment)
|
||||||
->Result.flatMap(newNode => {
|
->Result.map(newNode => {
|
||||||
acc->Belt.List.add(newNode)->Ok
|
acc->Belt.List.add(newNode)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
racc->Result.flatMap(acc => acc->reduceValueList(environment))
|
racc->Result.flatMap(acc => acc->reduceValueList(environment))
|
||||||
}
|
|
||||||
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
|
|
||||||
| EParameters(_parameters) =>
|
|
||||||
RETodo("Error: Lambda Parameters cannot be reduced to values")->Error
|
|
||||||
}
|
|
||||||
|
|
||||||
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings, environment)
|
|
||||||
rExpandedExpression->Result.flatMap(expandedExpression =>
|
|
||||||
expandedExpression->reduceExpandedExpression(environment)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result<
|
/*
|
||||||
|
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
||||||
|
*/
|
||||||
|
and reduceValueList = (valueList: list<expressionValue>, environment): result<
|
||||||
|
expressionValue,
|
||||||
|
'e,
|
||||||
|
> =>
|
||||||
|
switch valueList {
|
||||||
|
| list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment)
|
||||||
|
|
||||||
|
| list{EvLambda(lamdaCall), ...args} =>
|
||||||
|
Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression)
|
||||||
|
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result<
|
||||||
expressionValue,
|
expressionValue,
|
||||||
'e,
|
'e,
|
||||||
> => reduceExpression(aExpression, bindings, environment)
|
> => reduceExpression(aExpression, bindings, environment)
|
||||||
|
|
||||||
/*
|
|
||||||
Evaluates MathJs code via Reducer using bindings and answers the result.
|
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
|
||||||
Therefore all statements are assignments.
|
|
||||||
*/
|
|
||||||
let evalPartial_ = (codeText: string, bindings: T.bindings, environment: environment) => {
|
|
||||||
parsePartial(codeText)->Result.flatMap(expression =>
|
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings, environment)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Evaluates MathJs code via Reducer using bindings and answers the result.
|
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
|
||||||
Therefore all statments are assignments.
|
|
||||||
*/
|
|
||||||
let evalOuter_ = (codeText: string, bindings: T.bindings, environment: environment) => {
|
|
||||||
parseOuter(codeText)->Result.flatMap(expression =>
|
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings, environment)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => {
|
|
||||||
let keys = Js.Dict.keys(externalBindings)
|
|
||||||
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
|
||||||
let value = Js.Dict.unsafeGet(externalBindings, key)
|
|
||||||
acc->Belt.Map.String.set(key, T.EValue(value))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let evaluateUsingOptions = (
|
let evaluateUsingOptions = (
|
||||||
~environment: option<ReducerInterface_ExpressionValue.environment>,
|
~environment: option<ReducerInterface_ExpressionValue.environment>,
|
||||||
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
|
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
|
||||||
~isPartial: option<bool>,
|
|
||||||
code: string,
|
code: string,
|
||||||
): result<expressionValue, errorValue> => {
|
): result<expressionValue, errorValue> => {
|
||||||
let anEnvironment = switch environment {
|
let anEnvironment = switch environment {
|
||||||
|
@ -214,24 +102,27 @@ let evaluateUsingOptions = (
|
||||||
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
|
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
|
||||||
}
|
}
|
||||||
|
|
||||||
let anIsPartial = switch isPartial {
|
let bindings = anExternalBindings->Bindings.fromExternalBindings
|
||||||
| Some(isPartial) => isPartial
|
|
||||||
| None => false
|
|
||||||
}
|
|
||||||
|
|
||||||
let bindings = anExternalBindings->externalBindingsToBindings
|
parse(code)->Result.flatMap(expr => evalUsingBindingsExpression_(expr, bindings, anEnvironment))
|
||||||
|
|
||||||
if anIsPartial {
|
|
||||||
evalPartial_(code, bindings, anEnvironment)
|
|
||||||
} else {
|
|
||||||
evalOuter_(code, bindings, anEnvironment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Evaluates MathJs code and bindings via Reducer and answers the result
|
Evaluates MathJs code and bindings via Reducer and answers the result
|
||||||
*/
|
*/
|
||||||
let evaluate = (code: string): result<expressionValue, errorValue> => {
|
let evaluate = (code: string): result<expressionValue, errorValue> => {
|
||||||
evaluateUsingOptions(~environment=None, ~externalBindings=None, ~isPartial=None, code)
|
evaluateUsingOptions(~environment=None, ~externalBindings=None, code)
|
||||||
}
|
}
|
||||||
let eval = evaluate
|
let eval = evaluate
|
||||||
|
let evaluatePartialUsingExternalBindings = (
|
||||||
|
code: string,
|
||||||
|
externalBindings: ReducerInterface_ExpressionValue.externalBindings,
|
||||||
|
environment: ReducerInterface_ExpressionValue.environment,
|
||||||
|
): result<externalBindings, errorValue> => {
|
||||||
|
let rAnswer = evaluateUsingOptions(~environment=Some(environment), ~externalBindings=Some(externalBindings), code)
|
||||||
|
switch rAnswer {
|
||||||
|
| Ok(EvRecord(externalBindings)) => Ok(externalBindings)
|
||||||
|
| Ok(_) => Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`))
|
||||||
|
| Error(err) => err->Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
|
||||||
|
let defaultBindings: ExpressionT.bindings = Belt.Map.String.empty
|
||||||
|
|
||||||
|
let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => {
|
||||||
|
let keys = Js.Dict.keys(externalBindings)
|
||||||
|
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
||||||
|
let value = Js.Dict.unsafeGet(externalBindings, key)
|
||||||
|
acc->Belt.Map.String.set(key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => {
|
||||||
|
let keys = Belt.Map.String.keysToArray(bindings)
|
||||||
|
keys->Belt.Array.reduce(Js.Dict.empty(), (acc, key) => {
|
||||||
|
let value = bindings->Belt.Map.String.getExn(key)
|
||||||
|
Js.Dict.set(acc, key, value)
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let fromValue = (aValue: expressionValue) =>
|
||||||
|
switch aValue {
|
||||||
|
| EvRecord(externalBindings) => fromExternalBindings(externalBindings)
|
||||||
|
| _ => defaultBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
let externalFromArray = anArray => Js.Dict.fromArray(anArray)
|
||||||
|
|
||||||
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||||
|
|
||||||
|
let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression): result<
|
||||||
|
expression,
|
||||||
|
errorValue,
|
||||||
|
> =>
|
||||||
|
switch expression {
|
||||||
|
| ExpressionT.EValue(value) =>
|
||||||
|
replaceSymbolOnValue(bindings, value)->Result.map(evValue => evValue->ExpressionT.EValue)
|
||||||
|
| ExpressionT.EList(list) =>
|
||||||
|
switch list {
|
||||||
|
| list{EValue(EvCall(fName)), ..._args} =>
|
||||||
|
switch isMacroName(fName) {
|
||||||
|
// A macro reduces itself so we dont dive in it
|
||||||
|
| true => expression->Ok
|
||||||
|
| false => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
|
}
|
||||||
|
| _ => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
and replaceSymbolsOnExpressionList = (bindings, list) => {
|
||||||
|
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
||||||
|
racc->Result.flatMap(acc => {
|
||||||
|
replaceSymbols(bindings, each)->Result.flatMap(newNode => {
|
||||||
|
acc->Belt.List.add(newNode)->Ok
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
racc->Result.map(acc => acc->ExpressionT.EList)
|
||||||
|
}
|
||||||
|
and replaceSymbolOnValue = (bindings, evValue: expressionValue) =>
|
||||||
|
switch evValue {
|
||||||
|
| EvSymbol(symbol) | EvCall(symbol) =>
|
||||||
|
Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok
|
||||||
|
| _ => evValue->Ok
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
module ErrorValue = Reducer_ErrorValue
|
|
||||||
module ExpressionT = Reducer_Expression_T
|
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
|
||||||
module Result = Belt.Result
|
|
||||||
|
|
||||||
type errorValue = ErrorValue.errorValue
|
|
||||||
type expression = ExpressionT.expression
|
|
||||||
|
|
||||||
let passToFunction = (fName: string, lispArgs: list<expression>): expression => {
|
|
||||||
let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue
|
|
||||||
let fn = fName->toEvCallValue
|
|
||||||
list{fn, ...lispArgs}->ExpressionT.EList
|
|
||||||
}
|
|
||||||
|
|
||||||
let toEvSymbolValue = (name: string): expression =>
|
|
||||||
name->ExpressionValue.EvSymbol->ExpressionT.EValue
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
module BBindings = Reducer_Expression_Bindings
|
||||||
|
module BErrorValue = Reducer_ErrorValue
|
||||||
|
module BExpressionT = Reducer_Expression_T
|
||||||
|
module BExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
|
||||||
|
type errorValue = BErrorValue.errorValue
|
||||||
|
type expression = BExpressionT.expression
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
|
|
||||||
|
external castExpressionToInternalCode: expression => internalCode = "%identity"
|
||||||
|
|
||||||
|
let eArray = anArray => anArray->BExpressionValue.EvArray->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eArrayString = anArray => anArray->BExpressionValue.EvArrayString->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eBindings = (anArray: array<(string, BExpressionValue.expressionValue)>) =>
|
||||||
|
anArray->Js.Dict.fromArray->EvRecord->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eBool = aBool => aBool->BExpressionValue.EvBool->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eCall = (name: string): expression => name->BExpressionValue.EvCall->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eFunction = (fName: string, lispArgs: list<expression>): expression => {
|
||||||
|
let fn = fName->eCall
|
||||||
|
list{fn, ...lispArgs}->BExpressionT.EList
|
||||||
|
}
|
||||||
|
|
||||||
|
let eLambda = (parameters: array<string>, context, expr) =>
|
||||||
|
BExpressionValue.EvLambda(
|
||||||
|
parameters,
|
||||||
|
context,
|
||||||
|
expr->castExpressionToInternalCode,
|
||||||
|
)->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eRecord = aRecord => aRecord->BExpressionValue.EvRecord->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eString = aString => aString->BExpressionValue.EvString->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eSymbol = (name: string): expression => name->BExpressionValue.EvSymbol->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eList = (list: list<expression>): expression => list->BExpressionT.EList
|
||||||
|
|
||||||
|
let eBlock = (exprs: list<expression>): expression => eFunction("$$block", exprs)
|
||||||
|
|
||||||
|
let eLetStatement = (symbol: string, valueExpression: expression): expression =>
|
||||||
|
eFunction("$let", list{eSymbol(symbol), valueExpression})
|
||||||
|
|
||||||
|
let eBindStatement = (bindingExpr: expression, letStatement: expression): expression =>
|
||||||
|
eFunction("$$bindStatement", list{bindingExpr, letStatement})
|
||||||
|
|
||||||
|
let eBindStatementDefault = (letStatement: expression): expression =>
|
||||||
|
eFunction("$$bindStatement", list{letStatement})
|
||||||
|
|
||||||
|
let eBindExpression = (bindingExpr: expression, expression: expression): expression =>
|
||||||
|
eFunction("$$bindExpression", list{bindingExpr, expression})
|
||||||
|
|
||||||
|
let eBindExpressionDefault = (expression: expression): expression =>
|
||||||
|
eFunction("$$bindExpression", list{expression})
|
|
@ -0,0 +1,35 @@
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
|
|
||||||
|
external castInternalCodeToExpression: internalCode => expression = "%identity"
|
||||||
|
|
||||||
|
let applyParametersToLambda = (
|
||||||
|
internal: internalCode,
|
||||||
|
parameters: array<string>,
|
||||||
|
args: list<expressionValue>,
|
||||||
|
context: externalBindings,
|
||||||
|
environment,
|
||||||
|
reducer: ExpressionT.reducerFn,
|
||||||
|
): result<expressionValue, 'e> => {
|
||||||
|
let expr = castInternalCodeToExpression(internal)
|
||||||
|
let parameterList = parameters->Belt.List.fromArray
|
||||||
|
let zippedParameterList = parameterList->Belt.List.zip(args)
|
||||||
|
let bindings = Belt.List.reduce(zippedParameterList, context->Bindings.fromExternalBindings, (
|
||||||
|
acc,
|
||||||
|
(variable, variableValue),
|
||||||
|
) => acc->Belt.Map.String.set(variable, variableValue))
|
||||||
|
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||||
|
reducer(newExpression, bindings, environment)
|
||||||
|
}
|
||||||
|
|
||||||
|
let doLambdaCall = ((parameters, context, internal), args, environment, reducer) => {
|
||||||
|
applyParametersToLambda(internal, parameters, args, context, environment, reducer)
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
|
||||||
|
let expandMacroCall = (
|
||||||
|
macroExpression: expression,
|
||||||
|
bindings: ExpressionT.bindings,
|
||||||
|
environment: environment,
|
||||||
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
|
): result<expression, 'e> =>
|
||||||
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||||
|
macroExpression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
reduceExpression,
|
||||||
|
)
|
||||||
|
|
||||||
|
let doMacroCall = (
|
||||||
|
macroExpression: expression,
|
||||||
|
bindings: ExpressionT.bindings,
|
||||||
|
environment: environment,
|
||||||
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
|
): result<expressionValue, 'e> =>
|
||||||
|
expandMacroCall(
|
||||||
|
macroExpression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
reduceExpression,
|
||||||
|
)->Result.flatMap(expression => reduceExpression(expression, bindings, environment))
|
||||||
|
|
||||||
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
|
@ -1,5 +1,3 @@
|
||||||
open ReducerInterface.ExpressionValue
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
|
An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
|
||||||
In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
|
In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
|
||||||
|
@ -8,9 +6,51 @@ open ReducerInterface.ExpressionValue
|
||||||
A Lisp AST contains only expressions/primitive values to apply to their left.
|
A Lisp AST contains only expressions/primitive values to apply to their left.
|
||||||
The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
|
The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
|
||||||
*/
|
*/
|
||||||
|
module Extra = Reducer_Extra
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
|
||||||
type rec expression =
|
type rec expression =
|
||||||
| EList(list<expression>) // A list to map-reduce
|
| EList(list<expression>) // A list to map-reduce
|
||||||
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
||||||
| EBindings(bindings) // $let kind of statements return bindings; for internal use only
|
and bindings = Belt.Map.String.t<expressionValue>
|
||||||
| EParameters(array<string>) // for $defun; for internal use only
|
|
||||||
and bindings = Belt.Map.String.t<expression>
|
type reducerFn = (
|
||||||
|
expression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
) => result<expressionValue, Reducer_ErrorValue.errorValue>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Converts the expression to String
|
||||||
|
*/
|
||||||
|
let rec toString = expression =>
|
||||||
|
switch expression {
|
||||||
|
| EList(aList) =>
|
||||||
|
`(${Belt.List.map(aList, aValue => toString(aValue))
|
||||||
|
->Extra.List.interperse(" ")
|
||||||
|
->Belt.List.toArray
|
||||||
|
->Js.String.concatMany("")})`
|
||||||
|
| EValue(aValue) => ExpressionValue.toString(aValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
let toStringResult = codeResult =>
|
||||||
|
switch codeResult {
|
||||||
|
| Ok(a) => `Ok(${toString(a)})`
|
||||||
|
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
||||||
|
}
|
||||||
|
|
||||||
|
let inspect = (expr: expression): expression => {
|
||||||
|
Js.log(toString(expr))
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
||||||
|
let inspectResult = (r: result<expression, Reducer_ErrorValue.errorValue>): result<
|
||||||
|
expression,
|
||||||
|
Reducer_ErrorValue.errorValue,
|
||||||
|
> => {
|
||||||
|
Js.log(toStringResult(r))
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ external castString: unit => string = "%identity"
|
||||||
/*
|
/*
|
||||||
As JavaScript returns us any type, we need to type check and cast type propertype before using it
|
As JavaScript returns us any type, we need to type check and cast type propertype before using it
|
||||||
*/
|
*/
|
||||||
let jsToEv = (jsValue): result<expressionValue, errorValue> => {
|
let jsToEv = (jsValue): result<expressionValue, errorValue> =>
|
||||||
switch Js.typeof(jsValue) {
|
switch Js.typeof(jsValue) {
|
||||||
| "boolean" => jsValue->castBool->EvBool->Ok
|
| "boolean" => jsValue->castBool->EvBool->Ok
|
||||||
| "number" => jsValue->castNumber->EvNumber->Ok
|
| "number" => jsValue->castNumber->EvNumber->Ok
|
||||||
| "string" => jsValue->castString->EvString->Ok
|
| "string" => jsValue->castString->EvString->Ok
|
||||||
| other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error
|
| other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,37 +1,34 @@
|
||||||
module Builder = Reducer_Expression_Builder
|
/* * WARNING. DO NOT EDIT, BEAUTIFY, COMMENT ON OR REFACTOR THIS CODE.
|
||||||
|
We will stop using MathJs parser and
|
||||||
|
this whole file will go to trash
|
||||||
|
**/
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module JavaScript = Reducer_Js
|
module JavaScript = Reducer_Js
|
||||||
module Parse = Reducer_MathJs_Parse
|
module Parse = Reducer_MathJs_Parse
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type errorValue = ErrorValue.errorValue
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type expressionValue = ExpressionValue.expressionValue
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
type errorValue = ErrorValue.errorValue
|
|
||||||
|
|
||||||
type blockTag =
|
let blockToNode = block => block["node"]
|
||||||
| ImportVariablesStatement
|
|
||||||
| ExportVariablesExpression
|
|
||||||
type tagOrNode =
|
|
||||||
| BlockTag(blockTag)
|
|
||||||
| BlockNode(Parse.node)
|
|
||||||
|
|
||||||
let toTagOrNode = block => BlockNode(block["node"])
|
let rec fromInnerNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
|
|
||||||
let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
||||||
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
|
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
|
||||||
Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) =>
|
Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let caseFunctionNode = fNode => {
|
let caseFunctionNode = fNode => {
|
||||||
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
||||||
rLispArgs->Result.flatMap(lispArgs =>
|
rLispArgs->Result.map(lispArgs =>
|
||||||
Builder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok
|
ExpressionBuilder.eFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,18 +39,15 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
(key: string, value: Parse.node),
|
(key: string, value: Parse.node),
|
||||||
) =>
|
) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(value)->Result.map(valueExpression => {
|
fromInnerNode(value)->Result.map(valueExpression => {
|
||||||
let entryCode =
|
let entryCode =
|
||||||
list{
|
list{ExpressionBuilder.eString(key), valueExpression}->ExpressionT.EList
|
||||||
key->ExpressionValue.EvString->ExpressionT.EValue,
|
|
||||||
valueExpression,
|
|
||||||
}->ExpressionT.EList
|
|
||||||
list{entryCode, ...acc}
|
list{entryCode, ...acc}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
rargs->Result.flatMap(args =>
|
rargs->Result.flatMap(args =>
|
||||||
Builder.passToFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok
|
ExpressionBuilder.eFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok
|
||||||
) // $constructRecord gets a single argument: List of key-value paiers
|
) // $constructRecord gets a single argument: List of key-value paiers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +60,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
Ok(list{}),
|
Ok(list{}),
|
||||||
(racc, currentPropertyMathJsNode) =>
|
(racc, currentPropertyMathJsNode) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
fromInnerNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
||||||
propertyCode,
|
propertyCode,
|
||||||
...acc,
|
...acc,
|
||||||
})
|
})
|
||||||
|
@ -77,28 +71,41 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
|
|
||||||
let caseAccessorNode = (objectNode, indexNode) => {
|
let caseAccessorNode = (objectNode, indexNode) => {
|
||||||
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
||||||
fromNode(objectNode)->Result.flatMap(objectCode =>
|
fromInnerNode(objectNode)->Result.flatMap(objectCode =>
|
||||||
Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok
|
ExpressionBuilder.eFunction("$atIndex", list{objectCode, indexCode})->Ok
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let caseBlock = (nodesArray: array<Parse.node>): result<expression, errorValue> => {
|
||||||
|
let rStatements: result<list<expression>, 'a> =
|
||||||
|
nodesArray
|
||||||
|
->Belt.List.fromArray
|
||||||
|
->Belt.List.reduceReverse(Ok(list{}), (racc, currNode) =>
|
||||||
|
racc->Result.flatMap(acc =>
|
||||||
|
fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rStatements->Result.map(statements => ExpressionBuilder.eBlock(statements))
|
||||||
|
}
|
||||||
|
|
||||||
let caseAssignmentNode = aNode => {
|
let caseAssignmentNode = aNode => {
|
||||||
let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue
|
let symbolName = aNode["object"]["name"]
|
||||||
let rValueExpression = fromNode(aNode["value"])
|
let rValueExpression = fromInnerNode(aNode["value"])
|
||||||
rValueExpression->Result.flatMap(valueExpression =>
|
rValueExpression->Result.map(valueExpression =>
|
||||||
Builder.passToFunction("$let", list{symbol, valueExpression})->Ok
|
ExpressionBuilder.eLetStatement(symbolName, valueExpression)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let caseFunctionAssignmentNode = faNode => {
|
let caseFunctionAssignmentNode = faNode => {
|
||||||
let symbol = faNode["name"]->Builder.toEvSymbolValue
|
let symbol = faNode["name"]->ExpressionBuilder.eSymbol
|
||||||
let rValueExpression = fromNode(faNode["expr"])
|
let rValueExpression = fromInnerNode(faNode["expr"])
|
||||||
|
|
||||||
rValueExpression->Result.flatMap(valueExpression => {
|
rValueExpression->Result.flatMap(valueExpression => {
|
||||||
let lispParams = faNode["params"]->ExpressionT.EParameters
|
let lispParams = ExpressionBuilder.eArrayString(faNode["params"])
|
||||||
let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression})
|
let valueBlock = ExpressionBuilder.eBlock(list{valueExpression})
|
||||||
Builder.passToFunction("$let", list{symbol, lambda})->Ok
|
let lambda = ExpressionBuilder.eFunction("$$lambda", list{lispParams, valueBlock})
|
||||||
|
ExpressionBuilder.eFunction("$let", list{symbol, lambda})->Ok
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +118,11 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
| MjArrayNode(aNode) => caseArrayNode(aNode)
|
| MjArrayNode(aNode) => caseArrayNode(aNode)
|
||||||
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
||||||
| MjSymbolNode(sNode) => {
|
| MjSymbolNode(sNode) => {
|
||||||
let expr: expression = Builder.toEvSymbolValue(sNode["name"])
|
let expr: expression = ExpressionBuilder.eSymbol(sNode["name"])
|
||||||
let rExpr: result<expression, errorValue> = expr->Ok
|
let rExpr: result<expression, errorValue> = expr->Ok
|
||||||
rExpr
|
rExpr
|
||||||
}
|
}
|
||||||
| MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes
|
| MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock
|
||||||
| MjConstantNode(cNode) =>
|
| MjConstantNode(cNode) =>
|
||||||
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
|
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
|
||||||
| MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode)
|
| MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode)
|
||||||
|
@ -123,78 +130,10 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
| MjIndexNode(iNode) => caseIndexNode(iNode)
|
| MjIndexNode(iNode) => caseIndexNode(iNode)
|
||||||
| MjObjectNode(oNode) => caseObjectNode(oNode)
|
| MjObjectNode(oNode) => caseObjectNode(oNode)
|
||||||
| MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
|
| MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
|
||||||
| MjParenthesisNode(pNode) => pNode["content"]->fromNode
|
| MjParenthesisNode(pNode) => pNode["content"]->fromInnerNode
|
||||||
}
|
}
|
||||||
rFinalExpression
|
rFinalExpression
|
||||||
})
|
})
|
||||||
and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
|
|
||||||
let initialBindings = Builder.passToFunction("$$bindings", list{})->Ok
|
|
||||||
let lastIndex = Belt.Array.length(tagOrNodes) - 1
|
|
||||||
tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => {
|
|
||||||
rPreviousBindings->Result.flatMap(previousBindings => {
|
|
||||||
let rStatement: result<expression, errorValue> = switch tagOrNode {
|
|
||||||
| BlockNode(node) => fromNode(node)
|
|
||||||
| BlockTag(tag) =>
|
|
||||||
switch tag {
|
|
||||||
| ImportVariablesStatement =>
|
|
||||||
Builder.passToFunction("$importVariablesStatement", list{})->Ok
|
|
||||||
| ExportVariablesExpression =>
|
|
||||||
Builder.passToFunction("$exportVariablesExpression", list{})->Ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let bindName = if i == lastIndex {
|
let fromNode = (node: Parse.node): result<expression, errorValue> =>
|
||||||
"$$bindExpression"
|
fromInnerNode(node)->Result.map(expr => ExpressionBuilder.eBlock(list{expr}))
|
||||||
} else {
|
|
||||||
"$$bindStatement"
|
|
||||||
}
|
|
||||||
|
|
||||||
rStatement->Result.flatMap((statement: expression) => {
|
|
||||||
Builder.passToFunction(bindName, list{previousBindings, statement})->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromPartialNode = (mathJsNode: Parse.node): result<expression, errorValue> => {
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
|
||||||
let casePartialBlockNode = (bNode: Parse.blockNode) => {
|
|
||||||
let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode)
|
|
||||||
let completed = Js.Array2.concat(blocksOrTags, [BlockTag(ExportVariablesExpression)])
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let casePartialExpression = (node: Parse.node) => {
|
|
||||||
let completed = [BlockNode(node), BlockTag(ExportVariablesExpression)]
|
|
||||||
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
|
|
||||||
| MjBlockNode(bNode) => casePartialBlockNode(bNode)
|
|
||||||
| _ => casePartialExpression(mathJsNode)
|
|
||||||
}
|
|
||||||
rFinalExpression
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromOuterNode = (mathJsNode: Parse.node): result<expression, errorValue> => {
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
|
||||||
let casePartialBlockNode = (bNode: Parse.blockNode) => {
|
|
||||||
let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode)
|
|
||||||
let completed = blocksOrTags
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let casePartialExpression = (node: Parse.node) => {
|
|
||||||
let completed = [BlockNode(node)]
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
|
|
||||||
| MjBlockNode(bNode) => casePartialBlockNode(bNode)
|
|
||||||
| _ => casePartialExpression(mathJsNode)
|
|
||||||
}
|
|
||||||
rFinalExpression
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,17 +11,19 @@ type internalCode = Object
|
||||||
@genType
|
@genType
|
||||||
type rec expressionValue =
|
type rec expressionValue =
|
||||||
| EvArray(array<expressionValue>)
|
| EvArray(array<expressionValue>)
|
||||||
|
| EvArrayString(array<string>)
|
||||||
| EvBool(bool)
|
| EvBool(bool)
|
||||||
| EvCall(string) // External function call
|
| EvCall(string) // External function call
|
||||||
| EvDistribution(DistributionTypes.genericDist)
|
| EvDistribution(DistributionTypes.genericDist)
|
||||||
| EvLambda((array<string>, internalCode))
|
| EvLambda((array<string>, record, internalCode))
|
||||||
| EvNumber(float)
|
| EvNumber(float)
|
||||||
| EvRecord(Js.Dict.t<expressionValue>)
|
| EvRecord(record)
|
||||||
| EvString(string)
|
| EvString(string)
|
||||||
| EvSymbol(string)
|
| EvSymbol(string)
|
||||||
|
and record = Js.Dict.t<expressionValue>
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = Js.Dict.t<expressionValue>
|
type externalBindings = record
|
||||||
@genType
|
@genType
|
||||||
let defaultExternalBindings: externalBindings = Js.Dict.empty()
|
let defaultExternalBindings: externalBindings = Js.Dict.empty()
|
||||||
|
|
||||||
|
@ -29,20 +31,21 @@ type functionCall = (string, array<expressionValue>)
|
||||||
|
|
||||||
let rec toString = aValue =>
|
let rec toString = aValue =>
|
||||||
switch aValue {
|
switch aValue {
|
||||||
|
| EvArray(anArray) => {
|
||||||
|
let args = anArray->Js.Array2.map(each => toString(each))->Js.Array2.toString
|
||||||
|
`[${args}]`
|
||||||
|
}
|
||||||
|
| EvArrayString(anArray) => {
|
||||||
|
let args = anArray->Js.Array2.toString
|
||||||
|
`[${args}]`
|
||||||
|
}
|
||||||
| EvBool(aBool) => Js.String.make(aBool)
|
| EvBool(aBool) => Js.String.make(aBool)
|
||||||
| EvCall(fName) => `:${fName}`
|
| EvCall(fName) => `:${fName}`
|
||||||
| EvLambda((parameters, _internalCode)) => `lambda(${Js.Array2.toString(parameters)}=>internal)`
|
| EvLambda((parameters, _context, _internalCode)) =>
|
||||||
|
`lambda(${Js.Array2.toString(parameters)}=>internal)`
|
||||||
| EvNumber(aNumber) => Js.String.make(aNumber)
|
| EvNumber(aNumber) => Js.String.make(aNumber)
|
||||||
| EvString(aString) => `'${aString}'`
|
| EvString(aString) => `'${aString}'`
|
||||||
| EvSymbol(aString) => `:${aString}`
|
| EvSymbol(aString) => `:${aString}`
|
||||||
| EvArray(anArray) => {
|
|
||||||
let args =
|
|
||||||
anArray
|
|
||||||
->Belt.Array.map(each => toString(each))
|
|
||||||
->Extra_Array.interperse(", ")
|
|
||||||
->Js.String.concatMany("")
|
|
||||||
`[${args}]`
|
|
||||||
}
|
|
||||||
| EvRecord(aRecord) => aRecord->toStringRecord
|
| EvRecord(aRecord) => aRecord->toStringRecord
|
||||||
| EvDistribution(dist) => GenericDist.toString(dist)
|
| EvDistribution(dist) => GenericDist.toString(dist)
|
||||||
}
|
}
|
||||||
|
@ -50,19 +53,19 @@ and toStringRecord = aRecord => {
|
||||||
let pairs =
|
let pairs =
|
||||||
aRecord
|
aRecord
|
||||||
->Js.Dict.entries
|
->Js.Dict.entries
|
||||||
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
||||||
->Extra_Array.interperse(", ")
|
->Js.Array2.toString
|
||||||
->Js.String.concatMany("")
|
|
||||||
`{${pairs}}`
|
`{${pairs}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringWithType = aValue =>
|
let toStringWithType = aValue =>
|
||||||
switch aValue {
|
switch aValue {
|
||||||
| EvArray(_) => `Array::${toString(aValue)}`
|
| EvArray(_) => `Array::${toString(aValue)}`
|
||||||
|
| EvArrayString(_) => `ArrayString::${toString(aValue)}`
|
||||||
| EvBool(_) => `Bool::${toString(aValue)}`
|
| EvBool(_) => `Bool::${toString(aValue)}`
|
||||||
| EvCall(_) => `Call::${toString(aValue)}`
|
| EvCall(_) => `Call::${toString(aValue)}`
|
||||||
| EvDistribution(_) => `Distribution::${toString(aValue)}`
|
| EvDistribution(_) => `Distribution::${toString(aValue)}`
|
||||||
| EvLambda((_parameters, _internalCode)) => `Lambda::${toString(aValue)}`
|
| EvLambda((_parameters, _context, _internalCode)) => `Lambda::${toString(aValue)}`
|
||||||
| EvNumber(_) => `Number::${toString(aValue)}`
|
| EvNumber(_) => `Number::${toString(aValue)}`
|
||||||
| EvRecord(_) => `Record::${toString(aValue)}`
|
| EvRecord(_) => `Record::${toString(aValue)}`
|
||||||
| EvString(_) => `String::${toString(aValue)}`
|
| EvString(_) => `String::${toString(aValue)}`
|
||||||
|
@ -70,7 +73,7 @@ let toStringWithType = aValue =>
|
||||||
}
|
}
|
||||||
|
|
||||||
let argsToString = (args: array<expressionValue>): string => {
|
let argsToString = (args: array<expressionValue>): string => {
|
||||||
args->Belt.Array.map(arg => arg->toString)->Extra_Array.interperse(", ")->Js.String.concatMany("")
|
args->Js.Array2.map(arg => arg->toString)->Js.Array2.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})`
|
let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})`
|
||||||
|
|
|
@ -28,14 +28,14 @@ module Helpers = {
|
||||||
let catchAndConvertTwoArgsToDists = (args: array<expressionValue>): option<(
|
let catchAndConvertTwoArgsToDists = (args: array<expressionValue>): option<(
|
||||||
DistributionTypes.genericDist,
|
DistributionTypes.genericDist,
|
||||||
DistributionTypes.genericDist,
|
DistributionTypes.genericDist,
|
||||||
)> => {
|
)> =>
|
||||||
switch args {
|
switch args {
|
||||||
| [EvDistribution(a), EvDistribution(b)] => Some((a, b))
|
| [EvDistribution(a), EvDistribution(b)] => Some((a, b))
|
||||||
| [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b))
|
| [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b))
|
||||||
| [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b)))
|
| [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b)))
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let toFloatFn = (
|
let toFloatFn = (
|
||||||
fnCall: DistributionTypes.DistributionOperation.toFloat,
|
fnCall: DistributionTypes.DistributionOperation.toFloat,
|
||||||
|
@ -119,7 +119,7 @@ module Helpers = {
|
||||||
mixtureWithGivenWeights(distributions, weights)
|
mixtureWithGivenWeights(distributions, weights)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mixture = (args: array<expressionValue>): DistributionOperation.outputType => {
|
let mixture = (args: array<expressionValue>): DistributionOperation.outputType =>
|
||||||
switch E.A.last(args) {
|
switch E.A.last(args) {
|
||||||
| Some(EvArray(b)) => {
|
| Some(EvArray(b)) => {
|
||||||
let weights = parseNumberArray(b)
|
let weights = parseNumberArray(b)
|
||||||
|
@ -138,7 +138,7 @@ module Helpers = {
|
||||||
}
|
}
|
||||||
| _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution"))
|
| _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution"))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module SymbolicConstructors = {
|
module SymbolicConstructors = {
|
||||||
|
|
|
@ -13,6 +13,12 @@ type samplingParams = DistributionOperation.env
|
||||||
@genType
|
@genType
|
||||||
type genericDist = DistributionTypes.genericDist
|
type genericDist = DistributionTypes.genericDist
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type sampleSetDist = SampleSetDist.t
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type symbolicDist = SymbolicDistTypes.symbolicDist
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type distributionError = DistributionTypes.error
|
type distributionError = DistributionTypes.error
|
||||||
|
|
||||||
|
@ -34,6 +40,12 @@ let evaluate = Reducer.evaluate
|
||||||
@genType
|
@genType
|
||||||
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type externalBindings = Reducer.externalBindings
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
open Rationale.Function.Infix
|
/*
|
||||||
|
Some functions from modules `L`, `O`, and `R` below were copied directly from
|
||||||
|
running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale
|
||||||
|
*/
|
||||||
module FloatFloatMap = {
|
module FloatFloatMap = {
|
||||||
module Id = Belt.Id.MakeComparable({
|
module Id = Belt.Id.MakeComparable({
|
||||||
type t = float
|
type t = float
|
||||||
|
@ -8,7 +11,7 @@ module FloatFloatMap = {
|
||||||
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
||||||
|
|
||||||
let fromArray = (ar: array<(float, float)>) => Belt.MutableMap.fromArray(ar, ~id=module(Id))
|
let fromArray = (ar: array<(float, float)>) => Belt.MutableMap.fromArray(ar, ~id=module(Id))
|
||||||
let toArray = (t: t) => Belt.MutableMap.toArray(t)
|
let toArray = (t: t): array<(float, float)> => Belt.MutableMap.toArray(t)
|
||||||
let empty = () => Belt.MutableMap.make(~id=module(Id))
|
let empty = () => Belt.MutableMap.make(~id=module(Id))
|
||||||
let increment = (el, t: t) =>
|
let increment = (el, t: t) =>
|
||||||
Belt.MutableMap.update(t, el, x =>
|
Belt.MutableMap.update(t, el, x =>
|
||||||
|
@ -20,6 +23,10 @@ module FloatFloatMap = {
|
||||||
|
|
||||||
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
||||||
let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn)
|
let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn)
|
||||||
|
let partition = (fn, t: t) => {
|
||||||
|
let (match, noMatch) = Belt.Array.partition(toArray(t), fn)
|
||||||
|
(fromArray(match), fromArray(noMatch))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module Int = {
|
module Int = {
|
||||||
|
@ -51,17 +58,59 @@ module O = {
|
||||||
| None => rFn()
|
| None => rFn()
|
||||||
}
|
}
|
||||||
()
|
()
|
||||||
let fmap = Rationale.Option.fmap
|
let fmap = (f: 'a => 'b, x: option<'a>): option<'b> => {
|
||||||
let bind = Rationale.Option.bind
|
switch x {
|
||||||
let default = Rationale.Option.default
|
| None => None
|
||||||
let isSome = Rationale.Option.isSome
|
| Some(x') => Some(f(x'))
|
||||||
let isNone = Rationale.Option.isNone
|
}
|
||||||
let toExn = Rationale.Option.toExn
|
}
|
||||||
let some = Rationale.Option.some
|
let bind = (o, f) =>
|
||||||
let firstSome = Rationale.Option.firstSome
|
switch o {
|
||||||
let toExt = Rationale.Option.toExn // wanna flag this-- looks like a typo but `Rationale.OptiontoExt` doesn't exist.
|
| None => None
|
||||||
let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten
|
| Some(a) => f(a)
|
||||||
let flatten = Rationale.Option.flatten
|
}
|
||||||
|
let default = (d, o) =>
|
||||||
|
switch o {
|
||||||
|
| None => d
|
||||||
|
| Some(a) => a
|
||||||
|
}
|
||||||
|
let isSome = o =>
|
||||||
|
switch o {
|
||||||
|
| Some(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
let isNone = o =>
|
||||||
|
switch o {
|
||||||
|
| None => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
let toExn = (err, o) =>
|
||||||
|
switch o {
|
||||||
|
| None => raise(Failure(err))
|
||||||
|
| Some(a) => a
|
||||||
|
}
|
||||||
|
|
||||||
|
let some = a => Some(a)
|
||||||
|
let firstSome = (a, b) =>
|
||||||
|
switch a {
|
||||||
|
| None => b
|
||||||
|
| _ => a
|
||||||
|
}
|
||||||
|
|
||||||
|
let toExt = toExn
|
||||||
|
|
||||||
|
let flatten = o =>
|
||||||
|
switch o {
|
||||||
|
| None => None
|
||||||
|
| Some(x) => x
|
||||||
|
}
|
||||||
|
|
||||||
|
let apply = (o, a) =>
|
||||||
|
switch o {
|
||||||
|
| Some(f) => bind(a, b => some(f(b)))
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
let flatApply = (fn, b) => apply(fn, Some(b)) |> flatten
|
||||||
|
|
||||||
let toBool = opt =>
|
let toBool = opt =>
|
||||||
switch opt {
|
switch opt {
|
||||||
|
@ -109,6 +158,11 @@ module O2 = {
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
module F = {
|
module F = {
|
||||||
|
let pipe = (f, g, x) => g(f(x))
|
||||||
|
let compose = (f, g, x) => f(g(x))
|
||||||
|
let flip = (f, a, b) => f(b, a)
|
||||||
|
let always = (x, _y) => x
|
||||||
|
|
||||||
let apply = (a, e) => a |> e
|
let apply = (a, e) => a |> e
|
||||||
|
|
||||||
let flatten2Callbacks = (fn1, fn2, fnlast) =>
|
let flatten2Callbacks = (fn1, fn2, fnlast) =>
|
||||||
|
@ -156,10 +210,31 @@ exception Assertion(string)
|
||||||
|
|
||||||
/* R for Result */
|
/* R for Result */
|
||||||
module R = {
|
module R = {
|
||||||
let result = Rationale.Result.result
|
open Belt.Result
|
||||||
|
let result = (okF, errF, r) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(a) => okF(a)
|
||||||
|
| Error(err) => errF(err)
|
||||||
|
}
|
||||||
let id = e => e |> result(U.id, U.id)
|
let id = e => e |> result(U.id, U.id)
|
||||||
let fmap = Rationale.Result.fmap
|
let isOk = Belt.Result.isOk
|
||||||
let bind = Rationale.Result.bind
|
let getError = (r: result<'a, 'b>) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(_) => None
|
||||||
|
| Error(e) => Some(e)
|
||||||
|
}
|
||||||
|
let fmap = (f: 'a => 'b, r: result<'a, 'c>): result<'b, 'c> => {
|
||||||
|
switch r {
|
||||||
|
| Ok(r') => Ok(f(r'))
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let bind = (r, f) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(a) => f(a)
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
let toExn = (msg: string, x: result<'a, 'b>): 'a =>
|
let toExn = (msg: string, x: result<'a, 'b>): 'a =>
|
||||||
switch x {
|
switch x {
|
||||||
| Ok(r) => r
|
| Ok(r) => r
|
||||||
|
@ -186,14 +261,17 @@ module R = {
|
||||||
let errorIfCondition = (errorCondition, errorMessage, r) =>
|
let errorIfCondition = (errorCondition, errorMessage, r) =>
|
||||||
errorCondition(r) ? Error(errorMessage) : Ok(r)
|
errorCondition(r) ? Error(errorMessage) : Ok(r)
|
||||||
|
|
||||||
let ap = Rationale.Result.ap
|
let ap = (r, a) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(f) => Ok(f(a))
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
let ap' = (r, a) =>
|
let ap' = (r, a) =>
|
||||||
switch r {
|
switch r {
|
||||||
| Ok(f) => fmap(f, a)
|
| Ok(f) => fmap(f, a)
|
||||||
| Error(err) => Error(err)
|
| Error(err) => Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// (a1 -> a2 -> r) -> m a1 -> m a2 -> m r // not in Rationale
|
|
||||||
let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => {
|
let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => {
|
||||||
ap'(fmap(op, xR), yR)
|
ap'(fmap(op, xR), yR)
|
||||||
}
|
}
|
||||||
|
@ -243,7 +321,7 @@ module S = {
|
||||||
}
|
}
|
||||||
|
|
||||||
module J = {
|
module J = {
|
||||||
let toString = \"||>"(Js.Json.decodeString, O.default(""))
|
let toString = F.pipe(Js.Json.decodeString, O.default(""))
|
||||||
let fromString = Js.Json.string
|
let fromString = Js.Json.string
|
||||||
let fromNumber = Js.Json.number
|
let fromNumber = Js.Json.number
|
||||||
|
|
||||||
|
@ -256,7 +334,7 @@ module J = {
|
||||||
|
|
||||||
let toString = (str: option<'a>) =>
|
let toString = (str: option<'a>) =>
|
||||||
switch str {
|
switch str {
|
||||||
| Some(str) => Some(str |> \"||>"(Js.Json.decodeString, O.default("")))
|
| Some(str) => Some(str |> F.pipe(Js.Json.decodeString, O.default("")))
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,34 +349,132 @@ module JsDate = {
|
||||||
|
|
||||||
/* List */
|
/* List */
|
||||||
module L = {
|
module L = {
|
||||||
|
module Util = {
|
||||||
|
let eq = (a, b) => a == b
|
||||||
|
}
|
||||||
let fmap = List.map
|
let fmap = List.map
|
||||||
let get = Belt.List.get
|
let get = Belt.List.get
|
||||||
let toArray = Array.of_list
|
let toArray = Array.of_list
|
||||||
let fmapi = List.mapi
|
let fmapi = List.mapi
|
||||||
let concat = List.concat
|
let concat = List.concat
|
||||||
let drop = Rationale.RList.drop
|
let concat' = (xs, ys) => List.append(ys, xs)
|
||||||
let remove = Rationale.RList.remove
|
|
||||||
|
let rec drop = (i, xs) =>
|
||||||
|
switch (i, xs) {
|
||||||
|
| (_, list{}) => list{}
|
||||||
|
| (i, _) if i <= 0 => xs
|
||||||
|
| (i, list{_, ...b}) => drop(i - 1, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
let append = (a, xs) => List.append(xs, list{a})
|
||||||
|
let take = {
|
||||||
|
let rec loop = (i, xs, acc) =>
|
||||||
|
switch (i, xs) {
|
||||||
|
| (i, _) if i <= 0 => acc
|
||||||
|
| (_, list{}) => acc
|
||||||
|
| (i, list{a, ...b}) => loop(i - 1, b, append(a, acc))
|
||||||
|
}
|
||||||
|
(i, xs) => loop(i, xs, list{})
|
||||||
|
}
|
||||||
|
let takeLast = (i, xs) => List.rev(xs) |> take(i) |> List.rev
|
||||||
|
|
||||||
|
let splitAt = (i, xs) => (take(i, xs), takeLast(List.length(xs) - i, xs))
|
||||||
|
let remove = (i, n, xs) => {
|
||||||
|
let (a, b) = splitAt(i, xs)
|
||||||
|
\"@"(a, drop(n, b))
|
||||||
|
}
|
||||||
|
|
||||||
let find = List.find
|
let find = List.find
|
||||||
let filter = List.filter
|
let filter = List.filter
|
||||||
let for_all = List.for_all
|
let for_all = List.for_all
|
||||||
let exists = List.exists
|
let exists = List.exists
|
||||||
let sort = List.sort
|
let sort = List.sort
|
||||||
let length = List.length
|
let length = List.length
|
||||||
let filter_opt = Rationale.RList.filter_opt
|
|
||||||
let uniqBy = Rationale.RList.uniqBy
|
let filter_opt = xs => {
|
||||||
let join = Rationale.RList.join
|
let rec loop = (l, acc) =>
|
||||||
let head = Rationale.RList.head
|
switch l {
|
||||||
let uniq = Rationale.RList.uniq
|
| list{} => acc
|
||||||
|
| list{hd, ...tl} =>
|
||||||
|
switch hd {
|
||||||
|
| None => loop(tl, acc)
|
||||||
|
| Some(x) => loop(tl, list{x, ...acc})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List.rev(loop(xs, list{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
let containsWith = f => List.exists(f)
|
||||||
|
|
||||||
|
let uniqWithBy = (eq, f, xs) =>
|
||||||
|
List.fold_left(
|
||||||
|
((acc, tacc), v) =>
|
||||||
|
containsWith(eq(f(v)), tacc) ? (acc, tacc) : (append(v, acc), append(f(v), tacc)),
|
||||||
|
(list{}, list{}),
|
||||||
|
xs,
|
||||||
|
) |> fst
|
||||||
|
|
||||||
|
let uniqBy = (f, xs) => uniqWithBy(Util.eq, f, xs)
|
||||||
|
let join = j => List.fold_left((acc, v) => String.length(acc) == 0 ? v : acc ++ (j ++ v), "")
|
||||||
|
|
||||||
|
let head = xs =>
|
||||||
|
switch List.hd(xs) {
|
||||||
|
| exception _ => None
|
||||||
|
| a => Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
let uniq = xs => uniqBy(x => x, xs)
|
||||||
let flatten = List.flatten
|
let flatten = List.flatten
|
||||||
let last = Rationale.RList.last
|
let last = xs => xs |> List.rev |> head
|
||||||
let append = List.append
|
let append = List.append
|
||||||
let getBy = Belt.List.getBy
|
let getBy = Belt.List.getBy
|
||||||
let dropLast = Rationale.RList.dropLast
|
let dropLast = (i, xs) => take(List.length(xs) - i, xs)
|
||||||
let contains = Rationale.RList.contains
|
let containsWith = f => List.exists(f)
|
||||||
let without = Rationale.RList.without
|
let contains = x => containsWith(Util.eq(x))
|
||||||
let update = Rationale.RList.update
|
|
||||||
|
let reject = pred => List.filter(x => !pred(x))
|
||||||
|
let tail = xs =>
|
||||||
|
switch List.tl(xs) {
|
||||||
|
| exception _ => None
|
||||||
|
| a => Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
let init = xs => {
|
||||||
|
O.fmap(List.rev, xs |> List.rev |> tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
let singleton = (x: 'a): list<'a> => list{x}
|
||||||
|
|
||||||
|
let adjust = (f, i, xs) => {
|
||||||
|
let (a, b) = splitAt(i + 1, xs)
|
||||||
|
switch a {
|
||||||
|
| _ if i < 0 => xs
|
||||||
|
| _ if i >= List.length(xs) => xs
|
||||||
|
| list{} => b
|
||||||
|
| list{a} => list{f(a), ...b}
|
||||||
|
| a =>
|
||||||
|
O.fmap(
|
||||||
|
concat'(b),
|
||||||
|
O.bind(init(a), x =>
|
||||||
|
O.fmap(F.flip(append, x), O.fmap(fmap(f), O.fmap(singleton, last(a))))
|
||||||
|
),
|
||||||
|
) |> O.default(xs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let without = (exclude, xs) => reject(x => contains(x, exclude), xs)
|
||||||
|
let update = (x, i, xs) => adjust(F.always(x), i, xs)
|
||||||
let iter = List.iter
|
let iter = List.iter
|
||||||
let findIndex = Rationale.RList.findIndex
|
|
||||||
|
let findIndex = {
|
||||||
|
let rec loop = (pred, xs, i) =>
|
||||||
|
switch xs {
|
||||||
|
| list{} => None
|
||||||
|
| list{a, ...b} => pred(a) ? Some(i) : loop(pred, b, i + 1)
|
||||||
|
}
|
||||||
|
(pred, xs) => loop(pred, xs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
let headSafe = Belt.List.head
|
let headSafe = Belt.List.head
|
||||||
let tailSafe = Belt.List.tail
|
let tailSafe = Belt.List.tail
|
||||||
let headExn = Belt.List.headExn
|
let headExn = Belt.List.headExn
|
||||||
|
@ -360,7 +536,7 @@ module A = {
|
||||||
Belt.Array.getUnsafe(a, index),
|
Belt.Array.getUnsafe(a, index),
|
||||||
Belt.Array.getUnsafe(a, index + 1),
|
Belt.Array.getUnsafe(a, index + 1),
|
||||||
))
|
))
|
||||||
|> Rationale.Result.return
|
|> (x => Ok(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
let tail = Belt.Array.sliceToEnd(_, 1)
|
let tail = Belt.Array.sliceToEnd(_, 1)
|
||||||
|
@ -424,8 +600,8 @@ module A = {
|
||||||
module O = {
|
module O = {
|
||||||
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
||||||
optionals
|
optionals
|
||||||
|> Js.Array.filter(Rationale.Option.isSome)
|
|> Js.Array.filter(O.isSome)
|
||||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||||
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
||||||
switch o {
|
switch o {
|
||||||
| Some(o) => o
|
| Some(o) => o
|
||||||
|
@ -475,76 +651,8 @@ module A = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module Sorted = {
|
|
||||||
let min = first
|
|
||||||
let max = last
|
|
||||||
let range = (~min=min, ~max=max, a) =>
|
|
||||||
switch (min(a), max(a)) {
|
|
||||||
| (Some(min), Some(max)) => Some(max -. min)
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let floatCompare: (float, float) => int = compare
|
|
||||||
|
|
||||||
let binarySearchFirstElementGreaterIndex = (ar: array<'a>, el: 'a) => {
|
|
||||||
let el = Belt.SortArray.binarySearchBy(ar, el, floatCompare)
|
|
||||||
let el = el < 0 ? el * -1 - 1 : el
|
|
||||||
switch el {
|
|
||||||
| e if e >= length(ar) => #overMax
|
|
||||||
| e if e == 0 => #underMin
|
|
||||||
| e => #firstHigher(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let concat = (t1: array<'a>, t2: array<'a>) => {
|
|
||||||
let ts = Belt.Array.concat(t1, t2)
|
|
||||||
ts |> Array.fast_sort(floatCompare)
|
|
||||||
ts
|
|
||||||
}
|
|
||||||
|
|
||||||
let concatMany = (t1: array<array<'a>>) => {
|
|
||||||
let ts = Belt.Array.concatMany(t1)
|
|
||||||
ts |> Array.fast_sort(floatCompare)
|
|
||||||
ts
|
|
||||||
}
|
|
||||||
|
|
||||||
module Floats = {
|
|
||||||
let isSorted = (ar: array<float>): bool =>
|
|
||||||
reduce(zip(ar, tail(ar)), true, (acc, (first, second)) => acc && first < second)
|
|
||||||
|
|
||||||
let makeIncrementalUp = (a, b) =>
|
|
||||||
Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
let makeIncrementalDown = (a, b) =>
|
|
||||||
Array.make(a - b + 1, a) |> Array.mapi((i, c) => c - i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
let split = (sortedArray: array<float>) => {
|
|
||||||
let continuous = []
|
|
||||||
let discrete = FloatFloatMap.empty()
|
|
||||||
Belt.Array.forEachWithIndex(sortedArray, (_, element) => {
|
|
||||||
// let maxIndex = (sortedArray |> Array.length) - 1
|
|
||||||
// let possiblySimilarElements = switch index {
|
|
||||||
// | 0 => [index + 1]
|
|
||||||
// | n if n == maxIndex => [index - 1]
|
|
||||||
// | _ => [index - 1, index + 1]
|
|
||||||
// } |> Belt.Array.map(_, r => sortedArray[r])
|
|
||||||
// let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
|
||||||
let hasSimilarElement = false
|
|
||||||
hasSimilarElement
|
|
||||||
? FloatFloatMap.increment(element, discrete)
|
|
||||||
: {
|
|
||||||
let _ = Js.Array.push(element, continuous)
|
|
||||||
}
|
|
||||||
|
|
||||||
()
|
|
||||||
})
|
|
||||||
|
|
||||||
(continuous, discrete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Floats = {
|
module Floats = {
|
||||||
|
type t = array<float>
|
||||||
let mean = Jstat.mean
|
let mean = Jstat.mean
|
||||||
let geomean = Jstat.geomean
|
let geomean = Jstat.geomean
|
||||||
let mode = Jstat.mode
|
let mode = Jstat.mode
|
||||||
|
@ -553,14 +661,31 @@ module A = {
|
||||||
let sum = Jstat.sum
|
let sum = Jstat.sum
|
||||||
let random = Js.Math.random_int
|
let random = Js.Math.random_int
|
||||||
|
|
||||||
|
let floatCompare: (float, float) => int = compare
|
||||||
|
let sort = t => {
|
||||||
|
let r = t
|
||||||
|
r |> Array.fast_sort(floatCompare)
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
let getNonFinite = (t: t) => Belt.Array.getBy(t, r => !Js.Float.isFinite(r))
|
||||||
|
let getBelowZero = (t: t) => Belt.Array.getBy(t, r => r < 0.0)
|
||||||
|
|
||||||
|
let isSorted = (t: t): bool =>
|
||||||
|
if Array.length(t) < 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
reduce(zip(t, tail(t)), true, (acc, (first, second)) => acc && first < second)
|
||||||
|
}
|
||||||
|
|
||||||
//Passing true for the exclusive parameter excludes both endpoints of the range.
|
//Passing true for the exclusive parameter excludes both endpoints of the range.
|
||||||
//https://jstat.github.io/all.html
|
//https://jstat.github.io/all.html
|
||||||
let percentile = (a, b) => Jstat.percentile(a, b, false)
|
let percentile = (a, b) => Jstat.percentile(a, b, false)
|
||||||
|
|
||||||
// Gives an array with all the differences between values
|
// Gives an array with all the differences between values
|
||||||
// diff([1,5,3,7]) = [4,-2,4]
|
// diff([1,5,3,7]) = [4,-2,4]
|
||||||
let diff = (arr: array<float>): array<float> =>
|
let diff = (t: t): array<float> =>
|
||||||
Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left)
|
Belt.Array.zipBy(t, Belt.Array.sliceToEnd(t, 1), (left, right) => right -. left)
|
||||||
|
|
||||||
exception RangeError(string)
|
exception RangeError(string)
|
||||||
let range = (min: float, max: float, n: int): array<float> =>
|
let range = (min: float, max: float, n: int): array<float> =>
|
||||||
|
@ -578,18 +703,104 @@ module A = {
|
||||||
|
|
||||||
let min = Js.Math.minMany_float
|
let min = Js.Math.minMany_float
|
||||||
let max = Js.Math.maxMany_float
|
let max = Js.Math.maxMany_float
|
||||||
|
|
||||||
|
module Sorted = {
|
||||||
|
let min = first
|
||||||
|
let max = last
|
||||||
|
let range = (~min=min, ~max=max, a) =>
|
||||||
|
switch (min(a), max(a)) {
|
||||||
|
| (Some(min), Some(max)) => Some(max -. min)
|
||||||
|
| _ => None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let binarySearchFirstElementGreaterIndex = (ar: array<'a>, el: 'a) => {
|
||||||
|
let el = Belt.SortArray.binarySearchBy(ar, el, floatCompare)
|
||||||
|
let el = el < 0 ? el * -1 - 1 : el
|
||||||
|
switch el {
|
||||||
|
| e if e >= length(ar) => #overMax
|
||||||
|
| e if e == 0 => #underMin
|
||||||
|
| e => #firstHigher(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let concat = (t1: array<'a>, t2: array<'a>) => Belt.Array.concat(t1, t2)->sort
|
||||||
|
|
||||||
|
let concatMany = (t1: array<array<'a>>) => Belt.Array.concatMany(t1)->sort
|
||||||
|
|
||||||
|
let makeIncrementalUp = (a, b) =>
|
||||||
|
Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)
|
||||||
|
|
||||||
|
let makeIncrementalDown = (a, b) =>
|
||||||
|
Array.make(a - b + 1, a) |> Array.mapi((i, c) => c - i) |> Belt.Array.map(_, float_of_int)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function goes through a sorted array and divides it into two different clusters:
|
||||||
|
continuous samples and discrete samples. The discrete samples are stored in a mutable map.
|
||||||
|
Samples are thought to be discrete if they have any duplicates.
|
||||||
|
*/
|
||||||
|
let _splitContinuousAndDiscreteForDuplicates = (sortedArray: array<float>) => {
|
||||||
|
let continuous: array<float> = []
|
||||||
|
let discrete = FloatFloatMap.empty()
|
||||||
|
Belt.Array.forEachWithIndex(sortedArray, (index, element) => {
|
||||||
|
let maxIndex = (sortedArray |> Array.length) - 1
|
||||||
|
let possiblySimilarElements = switch index {
|
||||||
|
| 0 => [index + 1]
|
||||||
|
| n if n == maxIndex => [index - 1]
|
||||||
|
| _ => [index - 1, index + 1]
|
||||||
|
} |> Belt.Array.map(_, r => sortedArray[r])
|
||||||
|
let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
||||||
|
hasSimilarElement
|
||||||
|
? FloatFloatMap.increment(element, discrete)
|
||||||
|
: {
|
||||||
|
let _ = Js.Array.push(element, continuous)
|
||||||
|
}
|
||||||
|
|
||||||
|
()
|
||||||
|
})
|
||||||
|
|
||||||
|
(continuous, discrete)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function works very similarly to splitContinuousAndDiscreteForDuplicates. The one major difference
|
||||||
|
is that you can specify a minDiscreteWeight. If the min discreet weight is 4, that would mean that
|
||||||
|
at least four elements needed from a specific value for that to be kept as discrete. This is important
|
||||||
|
because in some cases, we can expect that some common elements will be generated by regular operations.
|
||||||
|
The final continous array will be sorted.
|
||||||
|
*/
|
||||||
|
let splitContinuousAndDiscreteForMinWeight = (
|
||||||
|
sortedArray: array<float>,
|
||||||
|
~minDiscreteWeight: int,
|
||||||
|
) => {
|
||||||
|
let (continuous, discrete) = _splitContinuousAndDiscreteForDuplicates(sortedArray)
|
||||||
|
let keepFn = v => Belt.Float.toInt(v) >= minDiscreteWeight
|
||||||
|
let (discreteToKeep, discreteToIntegrate) = FloatFloatMap.partition(
|
||||||
|
((_, v)) => keepFn(v),
|
||||||
|
discrete,
|
||||||
|
)
|
||||||
|
let newContinousSamples =
|
||||||
|
discreteToIntegrate->FloatFloatMap.toArray
|
||||||
|
|> fmap(((k, v)) => Belt.Array.makeBy(Belt.Float.toInt(v), _ => k))
|
||||||
|
|> Belt.Array.concatMany
|
||||||
|
let newContinuous = concat(continuous, newContinousSamples)
|
||||||
|
newContinuous |> Array.fast_sort(floatCompare)
|
||||||
|
(newContinuous, discreteToKeep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module Sorted = Floats.Sorted
|
||||||
}
|
}
|
||||||
|
|
||||||
module A2 = {
|
module A2 = {
|
||||||
let fmap = (a, b) => A.fmap(b, a)
|
let fmap = (a, b) => A.fmap(b, a)
|
||||||
let joinWith = (a, b) => A.joinWith(b, a)
|
let joinWith = (a, b) => A.joinWith(b, a)
|
||||||
|
let filter = (a, b) => A.filter(b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
module JsArray = {
|
module JsArray = {
|
||||||
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
||||||
optionals
|
optionals
|
||||||
|> Js.Array.filter(Rationale.Option.isSome)
|
|> Js.Array.filter(O.isSome)
|
||||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||||
let filter = Js.Array.filter
|
let filter = Js.Array.filter
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,18 @@ type distToFloatOperation = [
|
||||||
|
|
||||||
module Convolution = {
|
module Convolution = {
|
||||||
type t = convolutionOperation
|
type t = convolutionOperation
|
||||||
|
//Only a selection of operations are supported by convolution.
|
||||||
|
let fromAlgebraicOperation = (op: algebraicOperation): option<convolutionOperation> =>
|
||||||
|
switch op {
|
||||||
|
| #Add => Some(#Add)
|
||||||
|
| #Subtract => Some(#Subtract)
|
||||||
|
| #Multiply => Some(#Multiply)
|
||||||
|
| #Divide | #Power | #Logarithm => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let canDoAlgebraicOperation = (op: algebraicOperation): bool =>
|
||||||
|
fromAlgebraicOperation(op)->E.O.isSome
|
||||||
|
|
||||||
let toFn: (t, float, float) => float = x =>
|
let toFn: (t, float, float) => float = x =>
|
||||||
switch x {
|
switch x {
|
||||||
| #Add => \"+."
|
| #Add => \"+."
|
||||||
|
|
|
@ -4,6 +4,42 @@ type xyShape = {
|
||||||
ys: array<float>,
|
ys: array<float>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type propertyName = string
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type rec error =
|
||||||
|
| NotSorted(propertyName)
|
||||||
|
| IsEmpty(propertyName)
|
||||||
|
| NotFinite(propertyName, float)
|
||||||
|
| DifferentLengths({p1Name: string, p2Name: string, p1Length: int, p2Length: int})
|
||||||
|
| MultipleErrors(array<error>)
|
||||||
|
|
||||||
|
@genType
|
||||||
|
module Error = {
|
||||||
|
let mapErrorArrayToError = (errors: array<error>): option<error> => {
|
||||||
|
switch errors {
|
||||||
|
| [] => None
|
||||||
|
| [error] => Some(error)
|
||||||
|
| _ => Some(MultipleErrors(errors))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rec toString = (t: error) =>
|
||||||
|
switch t {
|
||||||
|
| NotSorted(propertyName) => `${propertyName} is not sorted`
|
||||||
|
| IsEmpty(propertyName) => `${propertyName} is empty`
|
||||||
|
| NotFinite(propertyName, exampleValue) =>
|
||||||
|
`${propertyName} is not finite. Example value: ${E.Float.toString(exampleValue)}`
|
||||||
|
| DifferentLengths({p1Name, p2Name, p1Length, p2Length}) =>
|
||||||
|
`${p1Name} and ${p2Name} have different lengths. ${p1Name} has length ${E.I.toString(
|
||||||
|
p1Length,
|
||||||
|
)} and ${p2Name} has length ${E.I.toString(p2Length)}`
|
||||||
|
| MultipleErrors(errors) =>
|
||||||
|
`Multiple Errors: ${E.A2.fmap(errors, toString)->E.A2.fmap(r => `[${r}]`)
|
||||||
|
|> E.A.joinWith(", ")}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type interpolationStrategy = [
|
type interpolationStrategy = [
|
||||||
| #Stepwise
|
| #Stepwise
|
||||||
|
@ -60,6 +96,44 @@ module T = {
|
||||||
let fromZippedArray = (pairs: array<(float, float)>): t => pairs |> Belt.Array.unzip |> fromArray
|
let fromZippedArray = (pairs: array<(float, float)>): t => pairs |> Belt.Array.unzip |> fromArray
|
||||||
let equallyDividedXs = (t: t, newLength) => E.A.Floats.range(minX(t), maxX(t), newLength)
|
let equallyDividedXs = (t: t, newLength) => E.A.Floats.range(minX(t), maxX(t), newLength)
|
||||||
let toJs = (t: t) => {"xs": t.xs, "ys": t.ys}
|
let toJs = (t: t) => {"xs": t.xs, "ys": t.ys}
|
||||||
|
|
||||||
|
module Validator = {
|
||||||
|
let fnName = "XYShape validate"
|
||||||
|
let notSortedError = (p: string): error => NotSorted(p)
|
||||||
|
let notFiniteError = (p, exampleValue): error => NotFinite(p, exampleValue)
|
||||||
|
let isEmptyError = (propertyName): error => IsEmpty(propertyName)
|
||||||
|
let differentLengthsError = (t): error => DifferentLengths({
|
||||||
|
p1Name: "Xs",
|
||||||
|
p2Name: "Ys",
|
||||||
|
p1Length: E.A.length(xs(t)),
|
||||||
|
p2Length: E.A.length(ys(t)),
|
||||||
|
})
|
||||||
|
|
||||||
|
let areXsSorted = (t: t) => E.A.Floats.isSorted(xs(t))
|
||||||
|
let areXsEmpty = (t: t) => E.A.length(xs(t)) == 0
|
||||||
|
let getNonFiniteXs = (t: t) => t->xs->E.A.Floats.getNonFinite
|
||||||
|
let getNonFiniteYs = (t: t) => t->ys->E.A.Floats.getNonFinite
|
||||||
|
|
||||||
|
let validate = (t: t) => {
|
||||||
|
let xsNotSorted = areXsSorted(t) ? None : Some(notSortedError("Xs"))
|
||||||
|
let xsEmpty = areXsEmpty(t) ? Some(isEmptyError("Xs")) : None
|
||||||
|
let differentLengths =
|
||||||
|
E.A.length(xs(t)) !== E.A.length(ys(t)) ? Some(differentLengthsError(t)) : None
|
||||||
|
let xsNotFinite = getNonFiniteXs(t)->E.O2.fmap(notFiniteError("Xs"))
|
||||||
|
let ysNotFinite = getNonFiniteYs(t)->E.O2.fmap(notFiniteError("Ys"))
|
||||||
|
[xsNotSorted, xsEmpty, differentLengths, xsNotFinite, ysNotFinite]
|
||||||
|
->E.A.O.concatSomes
|
||||||
|
->Error.mapErrorArrayToError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let make = (~xs: array<float>, ~ys: array<float>) => {
|
||||||
|
let attempt: t = {xs: xs, ys: ys}
|
||||||
|
switch Validator.validate(attempt) {
|
||||||
|
| Some(error) => Error(error)
|
||||||
|
| None => Ok(attempt)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module Ts = {
|
module Ts = {
|
||||||
|
|
7
packages/website/docs/Discussions/Gallery.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
title: Gallery
|
||||||
|
---
|
||||||
|
|
||||||
|
- [Adjusting probabilities for the passage of time](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3/p/j8o6sgRerE3tqNWdj) by Nuño Sempere
|
||||||
|
- [GiveWell's GiveDirectly cost effectiveness analysis](https://observablehq.com/@hazelfire/givewells-givedirectly-cost-effectiveness-analysis) by Sam Nolan
|
|
@ -1,12 +1,10 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 5
|
sidebar_position: 5
|
||||||
|
title: Three Formats of Distributions
|
||||||
|
author: Ozzie Gooen
|
||||||
|
date: 02-19-2022
|
||||||
---
|
---
|
||||||
|
|
||||||
# Three Formats of Distributions
|
|
||||||
|
|
||||||
_Author: Ozzie Gooen_
|
|
||||||
_Written on: Feb 19, 2022_
|
|
||||||
|
|
||||||
Probability distributions have several subtle possible formats. Three important ones that we deal with in Squiggle are symbolic, sample set, and graph formats.
|
Probability distributions have several subtle possible formats. Three important ones that we deal with in Squiggle are symbolic, sample set, and graph formats.
|
||||||
|
|
||||||
_Symbolic_ formats are just the math equations. `normal(5,3)` is the symbolic representation of a normal distribution.
|
_Symbolic_ formats are just the math equations. `normal(5,3)` is the symbolic representation of a normal distribution.
|
|
@ -1,39 +1,53 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 2
|
sidebar_position: 2
|
||||||
|
title: Language Basics
|
||||||
---
|
---
|
||||||
|
|
||||||
import { SquiggleEditor } from "../../src/components/SquiggleEditor";
|
import { SquiggleEditor } from "../../src/components/SquiggleEditor";
|
||||||
|
|
||||||
# Squiggle Language
|
## Expressions
|
||||||
|
|
||||||
The squiggle language has a very simple syntax. The best way to get to understand
|
A distribution
|
||||||
it is by simply looking at examples.
|
|
||||||
|
|
||||||
## Basic Language
|
<SquiggleEditor initialSquiggleString={`mixture(1 to 2, 3, [0.3, 0.7])`} />
|
||||||
|
|
||||||
As an example:
|
A number
|
||||||
|
|
||||||
|
<SquiggleEditor initialSquiggleString="4.321e-3" />
|
||||||
|
|
||||||
|
Arrays
|
||||||
|
|
||||||
|
<SquiggleEditor
|
||||||
|
initialSquiggleString={`[beta(1,10), 4, isNormalized(toSampleSet(1 to 2))]`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
Records
|
||||||
|
|
||||||
|
<SquiggleEditor
|
||||||
|
initialSquiggleString={`d = {dist: triangular(0, 1, 2), weight: 0.25}
|
||||||
|
d.dist`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
## Statements
|
||||||
|
|
||||||
|
A statement assigns expressions to names. It looks like `<symbol> = <expression>`
|
||||||
|
|
||||||
<SquiggleEditor
|
<SquiggleEditor
|
||||||
initialSquiggleString={`value_of_work = 10 to 70
|
initialSquiggleString={`value_of_work = 10 to 70
|
||||||
value_of_work`}
|
5 + value_of_work / 75`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
Squiggle can declare variables (`value_of_work = 10 to 70`) and declare exports
|
### Functions
|
||||||
(the lone `value_of_work` line). Variables can be used later in a squiggle program
|
|
||||||
and even in other notebooks!
|
|
||||||
|
|
||||||
An export is rendered to the output view so you can see your result.
|
We can define functions
|
||||||
|
|
||||||
the exports can be expressions, such as:
|
|
||||||
|
|
||||||
<SquiggleEditor initialSquiggleString="normal(0,1)" />
|
|
||||||
|
|
||||||
## Functions
|
|
||||||
|
|
||||||
Squiggle supports functions, including the rendering of functions:
|
|
||||||
|
|
||||||
<SquiggleEditor
|
<SquiggleEditor
|
||||||
initialSquiggleString={`ozzie_estimate(t) = lognormal({mean: 3 + (t+.1)^2.5, stdev: 8})
|
initialSquiggleString={`ozzie_estimate(t) = lognormal(1, t ^ 1.01)
|
||||||
ozzie_estimate
|
nuño_estimate(t, m) = mixture(0.5 to 2, normal(m, t ^ 1.25))
|
||||||
`}
|
ozzie_estimate(5) * nuño_estimate(5.01, 1)`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
## See more
|
||||||
|
|
||||||
|
- [Functions reference](https://squiggle-language.com/docs/Features/Functions)
|
||||||
|
- [Gallery](https://squiggle-language.com/docs/Discussions/Gallery)
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 3
|
sidebar_position: 3
|
||||||
|
title: Node Packages
|
||||||
---
|
---
|
||||||
|
|
||||||
# Javascript Libraries
|
|
||||||
|
|
||||||
There are two JavaScript packages currently available for Squiggle:
|
There are two JavaScript packages currently available for Squiggle:
|
||||||
|
|
||||||
- [`@quri/squiggle-lang`](https://www.npmjs.com/package/@quri/squiggle-lang)
|
- [`@quri/squiggle-lang`](https://www.npmjs.com/package/@quri/squiggle-lang) ![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)
|
||||||
- [`@quri/squiggle-components`](https://www.npmjs.com/package/@quri/squiggle-components)
|
- [`@quri/squiggle-components`](https://www.npmjs.com/package/@quri/squiggle-components) ![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)
|
||||||
|
|
||||||
Types are available for both packages.
|
Types are available for both packages.
|
||||||
|
|
||||||
|
@ -23,8 +22,8 @@ argument allows you to pass an environment previously created by another `run`
|
||||||
call. Passing this environment will mean that all previously declared variables
|
call. Passing this environment will mean that all previously declared variables
|
||||||
in the previous environment will be made available.
|
in the previous environment will be made available.
|
||||||
|
|
||||||
The return type of `run` is a bit complicated, and comes from auto generated js
|
The return type of `run` is a bit complicated, and comes from auto generated `js`
|
||||||
code that comes from rescript. I highly recommend using typescript when using
|
code that comes from rescript. We highly recommend using typescript when using
|
||||||
this library to help navigate the return type.
|
this library to help navigate the return type.
|
||||||
|
|
||||||
## Squiggle Components
|
## Squiggle Components
|
|
@ -1,6 +1,9 @@
|
||||||
# Processing confidence intervals
|
---
|
||||||
|
title: Processing Confidence Intervals
|
||||||
|
author: Nuño Sempere
|
||||||
|
---
|
||||||
|
|
||||||
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
|
This page explains what we are doing when we take a 90% confidence interval, and we get a mean and a standard deviation from it.
|
||||||
|
|
||||||
## For normals
|
## For normals
|
||||||
|
|
||||||
|
@ -19,10 +22,7 @@ module Normal = {
|
||||||
We know that for a normal with mean $\mu$ and standard deviation $\sigma$,
|
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)
|
||||||
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$.
|
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$.
|
||||||
|
@ -30,3 +30,5 @@ We can now look at the inverse cdf of a $Normal(0,1)$. We find that the 95% poin
|
||||||
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.
|
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
|
## For lognormals
|
||||||
|
|
||||||
|
TODO
|
|
@ -1,10 +1,16 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 1
|
||||||
|
title: Introduction
|
||||||
---
|
---
|
||||||
|
|
||||||
# Squiggle
|
Squiggle is an _estimation language_, and a syntax for _calculating and expressing beliefs_ involving uncertainty. It has use cases in forecasting and writing evaluations.
|
||||||
|
|
||||||
Squiggle is a language for writing calculations under uncertainty. It has use
|
## Get started
|
||||||
cases in forecasting and writing better evaluations.
|
|
||||||
|
|
||||||
The best way to get started with Squiggle is to [try it out yourself](https://playground.squiggle-language.com/).
|
- [Gallery](https://www.squiggle-language.com/docs/Discussions/Gallery)
|
||||||
|
- [Squiggle playground](https://squiggle-language.com/playground)
|
||||||
|
- [Language basics](https://www.squiggle-language.com/docs/Features/Language)
|
||||||
|
- [Squiggle functions source of truth](https://www.squiggle-language.com/docs/Features/Functions)
|
||||||
|
- [Known bugs](https://www.squiggle-language.com/docs/Discussions/Bugs)
|
||||||
|
- [Original lesswrong sequence](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3)
|
||||||
|
- [Author your squiggle models as Observable notebooks](https://observablehq.com/@hazelfire/squiggle)
|
||||||
|
|
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 12 KiB |
|
@ -1,170 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1088" height="687.962" viewBox="0 0 1088 687.962">
|
|
||||||
<g id="Group_12" data-name="Group 12" transform="translate(-57 -56)">
|
|
||||||
<g id="Group_11" data-name="Group 11" transform="translate(57 56)">
|
|
||||||
<path id="Path_83" data-name="Path 83" d="M1017.81,560.461c-5.27,45.15-16.22,81.4-31.25,110.31-20,38.52-54.21,54.04-84.77,70.28a193.275,193.275,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.282,657.282,0,0,0-104.09-13.16q-14.97-.675-29.97-.67c-15.42.02-293.07,5.29-360.67-131.57-16.69-33.76-28.13-75-32.24-125.27-11.63-142.12,52.29-235.46,134.74-296.47,155.97-115.41,369.76-110.57,523.43,7.88C941.15,276.621,1036.99,396.031,1017.81,560.461Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_84" data-name="Path 84" d="M986.56,670.771c-20,38.52-47.21,64.04-77.77,80.28a193.272,193.272,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.3,657.3,0,0,0-104.09-13.16q-14.97-.675-29.97-.67-23.13.03-46.25,1.72c-100.17,7.36-253.82-6.43-321.42-143.29L382,283.981,444.95,445.6l20.09,51.59,55.37-75.98L549,381.981l130.2,149.27,36.8-81.27L970.78,657.9l14.21,11.59Z" transform="translate(-56 -106.019)" fill="#f2f2f2"/>
|
|
||||||
<path id="Path_85" data-name="Path 85" d="M302,282.962l26-57,36,83-31-60Z" opacity="0.1"/>
|
|
||||||
<path id="Path_86" data-name="Path 86" d="M610.5,753.821q-14.97-.675-29.97-.67L465.04,497.191Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
|
||||||
<path id="Path_87" data-name="Path 87" d="M464.411,315.191,493,292.962l130,150-132-128Z" opacity="0.1"/>
|
|
||||||
<path id="Path_88" data-name="Path 88" d="M908.79,751.051a193.265,193.265,0,0,1-27.46,11.94L679.2,531.251Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
|
||||||
<circle id="Ellipse_11" data-name="Ellipse 11" cx="3" cy="3" r="3" transform="translate(479 98.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_12" data-name="Ellipse 12" cx="3" cy="3" r="3" transform="translate(396 201.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_13" data-name="Ellipse 13" cx="2" cy="2" r="2" transform="translate(600 220.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_14" data-name="Ellipse 14" cx="2" cy="2" r="2" transform="translate(180 265.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_15" data-name="Ellipse 15" cx="2" cy="2" r="2" transform="translate(612 96.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_16" data-name="Ellipse 16" cx="2" cy="2" r="2" transform="translate(736 192.962)" fill="#f2f2f2"/>
|
|
||||||
<circle id="Ellipse_17" data-name="Ellipse 17" cx="2" cy="2" r="2" transform="translate(858 344.962)" fill="#f2f2f2"/>
|
|
||||||
<path id="Path_89" data-name="Path 89" d="M306,121.222h-2.76v-2.76h-1.48v2.76H299V122.7h2.76v2.759h1.48V122.7H306Z" fill="#f2f2f2"/>
|
|
||||||
<path id="Path_90" data-name="Path 90" d="M848,424.222h-2.76v-2.76h-1.48v2.76H841V425.7h2.76v2.759h1.48V425.7H848Z" fill="#f2f2f2"/>
|
|
||||||
<path id="Path_91" data-name="Path 91" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_92" data-name="Path 92" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
|
||||||
<ellipse id="Ellipse_18" data-name="Ellipse 18" cx="544" cy="30" rx="544" ry="30" transform="translate(0 583.962)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_93" data-name="Path 93" d="M624,677.981c0,33.137-14.775,24-33,24s-33,9.137-33-24,33-96,33-96S624,644.844,624,677.981Z" transform="translate(-56 -106.019)" fill="#ff6584"/>
|
|
||||||
<path id="Path_94" data-name="Path 94" d="M606,690.66c0,15.062-6.716,10.909-15,10.909s-15,4.153-15-10.909,15-43.636,15-43.636S606,675.6,606,690.66Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_97" data-name="Rectangle 97" width="92" height="18" rx="9" transform="translate(489 604.962)" fill="#2f2e41"/>
|
|
||||||
<rect id="Rectangle_98" data-name="Rectangle 98" width="92" height="18" rx="9" transform="translate(489 586.962)" fill="#2f2e41"/>
|
|
||||||
<path id="Path_95" data-name="Path 95" d="M193,596.547c0,55.343,34.719,100.126,77.626,100.126" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_96" data-name="Path 96" d="M270.626,696.673c0-55.965,38.745-101.251,86.626-101.251" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
|
||||||
<path id="Path_97" data-name="Path 97" d="M221.125,601.564c0,52.57,22.14,95.109,49.5,95.109" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
|
||||||
<path id="Path_98" data-name="Path 98" d="M270.626,696.673c0-71.511,44.783-129.377,100.126-129.377" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_99" data-name="Path 99" d="M254.3,697.379s11.009-.339,14.326-2.7,16.934-5.183,17.757-1.395,16.544,18.844,4.115,18.945-28.879-1.936-32.19-3.953S254.3,697.379,254.3,697.379Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
|
||||||
<path id="Path_100" data-name="Path 100" d="M290.716,710.909c-12.429.1-28.879-1.936-32.19-3.953-2.522-1.536-3.527-7.048-3.863-9.591l-.368.014s.7,8.879,4.009,10.9,19.761,4.053,32.19,3.953c3.588-.029,4.827-1.305,4.759-3.2C294.755,710.174,293.386,710.887,290.716,710.909Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
|
||||||
<path id="Path_101" data-name="Path 101" d="M777.429,633.081c0,38.029,23.857,68.8,53.341,68.8" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_102" data-name="Path 102" d="M830.769,701.882c0-38.456,26.623-69.575,59.525-69.575" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
|
||||||
<path id="Path_103" data-name="Path 103" d="M796.755,636.528c0,36.124,15.213,65.354,34.014,65.354" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
|
||||||
<path id="Path_104" data-name="Path 104" d="M830.769,701.882c0-49.139,30.773-88.9,68.8-88.9" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_105" data-name="Path 105" d="M819.548,702.367s7.565-.233,9.844-1.856,11.636-3.562,12.2-.958,11.368,12.949,2.828,13.018-19.844-1.33-22.119-2.716S819.548,702.367,819.548,702.367Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
|
||||||
<path id="Path_106" data-name="Path 106" d="M844.574,711.664c-8.54.069-19.844-1.33-22.119-2.716-1.733-1.056-2.423-4.843-2.654-6.59l-.253.01s.479,6.1,2.755,7.487,13.579,2.785,22.119,2.716c2.465-.02,3.317-.9,3.27-2.2C847.349,711.159,846.409,711.649,844.574,711.664Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
|
||||||
<path id="Path_107" data-name="Path 107" d="M949.813,724.718s11.36-1.729,14.5-4.591,16.89-7.488,18.217-3.667,19.494,17.447,6.633,19.107-30.153,1.609-33.835-.065S949.813,724.718,949.813,724.718Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
|
||||||
<path id="Path_108" data-name="Path 108" d="M989.228,734.173c-12.86,1.659-30.153,1.609-33.835-.065-2.8-1.275-4.535-6.858-5.2-9.45l-.379.061s1.833,9.109,5.516,10.783,20.975,1.725,33.835.065c3.712-.479,4.836-1.956,4.529-3.906C993.319,732.907,991.991,733.817,989.228,734.173Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
|
||||||
<path id="Path_109" data-name="Path 109" d="M670.26,723.9s9.587-1.459,12.237-3.875,14.255-6.32,15.374-3.095,16.452,14.725,5.6,16.125-25.448,1.358-28.555-.055S670.26,723.9,670.26,723.9Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
|
||||||
<path id="Path_110" data-name="Path 110" d="M703.524,731.875c-10.853,1.4-25.448,1.358-28.555-.055-2.367-1.076-3.827-5.788-4.39-7.976l-.32.051s1.547,7.687,4.655,9.1,17.7,1.456,28.555.055c3.133-.4,4.081-1.651,3.822-3.3C706.977,730.807,705.856,731.575,703.524,731.875Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
|
||||||
<path id="Path_111" data-name="Path 111" d="M178.389,719.109s7.463-1.136,9.527-3.016,11.1-4.92,11.969-2.409,12.808,11.463,4.358,12.553-19.811,1.057-22.23-.043S178.389,719.109,178.389,719.109Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
|
||||||
<path id="Path_112" data-name="Path 112" d="M204.285,725.321c-8.449,1.09-19.811,1.057-22.23-.043-1.842-.838-2.979-4.506-3.417-6.209l-.249.04s1.2,5.984,3.624,7.085,13.781,1.133,22.23.043c2.439-.315,3.177-1.285,2.976-2.566C206.973,724.489,206.1,725.087,204.285,725.321Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
|
||||||
<path id="Path_113" data-name="Path 113" d="M439.7,707.337c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873,42.118-36.793,93.694-36.793S439.7,677.117,439.7,707.337Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
|
||||||
<path id="Path_114" data-name="Path 114" d="M439.7,699.9c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873S295.04,663.1,346.616,663.1,439.7,669.676,439.7,699.9Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
|
||||||
</g>
|
|
||||||
<g id="docusaurus_keytar" transform="translate(312.271 493.733)">
|
|
||||||
<path id="Path_40" data-name="Path 40" d="M99,52h91.791V89.153H99Z" transform="translate(5.904 -14.001)" fill="#fff" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_41" data-name="Path 41" d="M24.855,163.927A21.828,21.828,0,0,1,5.947,153a21.829,21.829,0,0,0,18.908,32.782H46.71V163.927Z" transform="translate(-3 -4.634)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_42" data-name="Path 42" d="M121.861,61.1l76.514-4.782V45.39A21.854,21.854,0,0,0,176.52,23.535H78.173L75.441,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L64.513,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L53.586,18.8a3.154,3.154,0,0,0-5.464,0L45.39,23.535c-.024,0-.046,0-.071,0l-4.526-4.525a3.153,3.153,0,0,0-5.276,1.414l-1.5,5.577-5.674-1.521a3.154,3.154,0,0,0-3.863,3.864L26,34.023l-5.575,1.494a3.155,3.155,0,0,0-1.416,5.278l4.526,4.526c0,.023,0,.046,0,.07L18.8,48.122a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,59.05a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,69.977a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,80.9a3.154,3.154,0,0,0,0,5.464L23.535,89.1,18.8,91.832a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,102.76a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,113.687a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,124.615a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,135.542a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,146.469a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,157.4a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,168.324a3.154,3.154,0,0,0,0,5.464l4.732,2.732A21.854,21.854,0,0,0,45.39,198.375H176.52a21.854,21.854,0,0,0,21.855-21.855V89.1l-76.514-4.782a11.632,11.632,0,0,1,0-23.219" transform="translate(-1.681 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_43" data-name="Path 43" d="M143,186.71h32.782V143H143Z" transform="translate(9.984 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_44" data-name="Path 44" d="M196.71,159.855a5.438,5.438,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(10.912 -6.025)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_45" data-name="Path 45" d="M153,124.855h32.782V103H153Z" transform="translate(10.912 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_46" data-name="Path 46" d="M194.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.814,2.814,0,0,0,.349.035" transform="translate(12.767 -9.377)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_47" data-name="Path 47" d="M65.087,56.891a2.732,2.732,0,0,1-2.732-2.732,8.2,8.2,0,0,0-16.391,0,2.732,2.732,0,0,1-5.464,0,13.659,13.659,0,0,1,27.319,0,2.732,2.732,0,0,1-2.732,2.732" transform="translate(0.478 -15.068)" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_48" data-name="Path 48" d="M103,191.347h65.565a21.854,21.854,0,0,0,21.855-21.855V93H124.855A21.854,21.854,0,0,0,103,114.855Z" transform="translate(6.275 -10.199)" fill="#ffff50" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_49" data-name="Path 49" d="M173.216,129.787H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0-54.434H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.652H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186M189.585,61.611c-.013,0-.024-.007-.037-.005-3.377.115-4.974,3.492-6.384,6.472-1.471,3.114-2.608,5.139-4.473,5.078-2.064-.074-3.244-2.406-4.494-4.874-1.436-2.835-3.075-6.049-6.516-5.929-3.329.114-4.932,3.053-6.346,5.646-1.5,2.762-2.529,4.442-4.5,4.364-2.106-.076-3.225-1.972-4.52-4.167-1.444-2.443-3.112-5.191-6.487-5.1-3.272.113-4.879,2.606-6.3,4.808-1.5,2.328-2.552,3.746-4.551,3.662-2.156-.076-3.27-1.65-4.558-3.472-1.447-2.047-3.077-4.363-6.442-4.251-3.2.109-4.807,2.153-6.224,3.954-1.346,1.709-2.4,3.062-4.621,2.977a1.093,1.093,0,0,0-.079,2.186c3.3.11,4.967-1.967,6.417-3.81,1.286-1.635,2.4-3.045,4.582-3.12,2.1-.09,3.091,1.218,4.584,3.327,1.417,2,3.026,4.277,6.263,4.394,3.391.114,5.022-2.42,6.467-4.663,1.292-2,2.406-3.734,4.535-3.807,1.959-.073,3.026,1.475,4.529,4.022,1.417,2.4,3.023,5.121,6.324,5.241,3.415.118,5.064-2.863,6.5-5.5,1.245-2.282,2.419-4.437,4.5-4.509,1.959-.046,2.981,1.743,4.492,4.732,1.412,2.79,3.013,5.95,6.365,6.071l.185,0c3.348,0,4.937-3.36,6.343-6.331,1.245-2.634,2.423-5.114,4.444-5.216Z" transform="translate(7.109 -13.11)" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_50" data-name="Path 50" d="M83,186.71h43.71V143H83Z" transform="translate(4.42 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 109.327, 91.085)">
|
|
||||||
<rect id="Rectangle_3" data-name="Rectangle 3" width="92.361" height="36.462" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
|
|
||||||
<g id="Group_2" data-name="Group 2" transform="translate(1.531 23.03)">
|
|
||||||
<rect id="Rectangle_4" data-name="Rectangle 4" width="5.336" height="5.336" rx="1" transform="translate(16.797 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_5" data-name="Rectangle 5" width="5.336" height="5.336" rx="1" transform="translate(23.12 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_6" data-name="Rectangle 6" width="5.336" height="5.336" rx="1" transform="translate(29.444 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_7" data-name="Rectangle 7" width="5.336" height="5.336" rx="1" transform="translate(35.768 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_8" data-name="Rectangle 8" width="5.336" height="5.336" rx="1" transform="translate(42.091 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_9" data-name="Rectangle 9" width="5.336" height="5.336" rx="1" transform="translate(48.415 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_10" data-name="Rectangle 10" width="5.336" height="5.336" rx="1" transform="translate(54.739 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_11" data-name="Rectangle 11" width="5.336" height="5.336" rx="1" transform="translate(61.063 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_12" data-name="Rectangle 12" width="5.336" height="5.336" rx="1" transform="translate(67.386 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_51" data-name="Path 51" d="M1.093,0H14.518a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0ZM75,0H88.426a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H75a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,75,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_3" data-name="Group 3" transform="translate(1.531 10.261)">
|
|
||||||
<path id="Path_52" data-name="Path 52" d="M1.093,0H6.218A1.093,1.093,0,0,1,7.31,1.093V4.242A1.093,1.093,0,0,1,6.218,5.335H1.093A1.093,1.093,0,0,1,0,4.242V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_13" data-name="Rectangle 13" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_14" data-name="Rectangle 14" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_15" data-name="Rectangle 15" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_16" data-name="Rectangle 16" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_17" data-name="Rectangle 17" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_18" data-name="Rectangle 18" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_19" data-name="Rectangle 19" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_20" data-name="Rectangle 20" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_21" data-name="Rectangle 21" width="5.336" height="5.336" rx="1" transform="translate(58.888 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_22" data-name="Rectangle 22" width="5.336" height="5.336" rx="1" transform="translate(65.212 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_23" data-name="Rectangle 23" width="5.336" height="5.336" rx="1" transform="translate(71.536 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_24" data-name="Rectangle 24" width="5.336" height="5.336" rx="1" transform="translate(77.859 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_25" data-name="Rectangle 25" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_4" data-name="Group 4" transform="translate(91.05 9.546) rotate(180)">
|
|
||||||
<path id="Path_53" data-name="Path 53" d="M1.093,0H6.219A1.093,1.093,0,0,1,7.312,1.093v3.15A1.093,1.093,0,0,1,6.219,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_26" data-name="Rectangle 26" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_27" data-name="Rectangle 27" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_28" data-name="Rectangle 28" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_29" data-name="Rectangle 29" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_30" data-name="Rectangle 30" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_31" data-name="Rectangle 31" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_32" data-name="Rectangle 32" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_33" data-name="Rectangle 33" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_34" data-name="Rectangle 34" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_35" data-name="Rectangle 35" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_36" data-name="Rectangle 36" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_37" data-name="Rectangle 37" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_38" data-name="Rectangle 38" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_39" data-name="Rectangle 39" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_40" data-name="Rectangle 40" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_41" data-name="Rectangle 41" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_42" data-name="Rectangle 42" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_43" data-name="Rectangle 43" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_44" data-name="Rectangle 44" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_45" data-name="Rectangle 45" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_46" data-name="Rectangle 46" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_47" data-name="Rectangle 47" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_48" data-name="Rectangle 48" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_49" data-name="Rectangle 49" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_50" data-name="Rectangle 50" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_51" data-name="Rectangle 51" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_6" data-name="Group 6" transform="translate(1.531 16.584)">
|
|
||||||
<path id="Path_54" data-name="Path 54" d="M1.093,0h7.3A1.093,1.093,0,0,1,9.485,1.093v3.15A1.093,1.093,0,0,1,8.392,5.336h-7.3A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<g id="Group_5" data-name="Group 5" transform="translate(10.671 0)">
|
|
||||||
<rect id="Rectangle_52" data-name="Rectangle 52" width="5.336" height="5.336" rx="1" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_53" data-name="Rectangle 53" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_54" data-name="Rectangle 54" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_55" data-name="Rectangle 55" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_56" data-name="Rectangle 56" width="5.336" height="5.336" rx="1" transform="translate(25.295 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_57" data-name="Rectangle 57" width="5.336" height="5.336" rx="1" transform="translate(31.619 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_58" data-name="Rectangle 58" width="5.336" height="5.336" rx="1" transform="translate(37.942 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_59" data-name="Rectangle 59" width="5.336" height="5.336" rx="1" transform="translate(44.265 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_60" data-name="Rectangle 60" width="5.336" height="5.336" rx="1" transform="translate(50.589 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_61" data-name="Rectangle 61" width="5.336" height="5.336" rx="1" transform="translate(56.912 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_62" data-name="Rectangle 62" width="5.336" height="5.336" rx="1" transform="translate(63.236 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<path id="Path_55" data-name="Path 55" d="M1.094,0H8A1.093,1.093,0,0,1,9.091,1.093v3.15A1.093,1.093,0,0,1,8,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(80.428 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_7" data-name="Group 7" transform="translate(1.531 29.627)">
|
|
||||||
<rect id="Rectangle_63" data-name="Rectangle 63" width="5.336" height="5.336" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_64" data-name="Rectangle 64" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_65" data-name="Rectangle 65" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_66" data-name="Rectangle 66" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_56" data-name="Path 56" d="M1.093,0H31.515a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.244V1.093A1.093,1.093,0,0,1,1.093,0ZM34.687,0h3.942a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H34.687a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,34.687,0Z" transform="translate(25.294 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_67" data-name="Rectangle 67" width="5.336" height="5.336" rx="1" transform="translate(66.003 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_68" data-name="Rectangle 68" width="5.336" height="5.336" rx="1" transform="translate(72.327 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_69" data-name="Rectangle 69" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_57" data-name="Path 57" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(83.59 2.273) rotate(180)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_58" data-name="Path 58" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(78.255 3.063)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<rect id="Rectangle_70" data-name="Rectangle 70" width="88.927" height="2.371" rx="1.085" transform="translate(1.925 1.17)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_71" data-name="Rectangle 71" width="4.986" height="1.581" rx="0.723" transform="translate(4.1 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_72" data-name="Rectangle 72" width="4.986" height="1.581" rx="0.723" transform="translate(10.923 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_73" data-name="Rectangle 73" width="4.986" height="1.581" rx="0.723" transform="translate(16.173 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_74" data-name="Rectangle 74" width="4.986" height="1.581" rx="0.723" transform="translate(21.421 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_75" data-name="Rectangle 75" width="4.986" height="1.581" rx="0.723" transform="translate(26.671 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_76" data-name="Rectangle 76" width="4.986" height="1.581" rx="0.723" transform="translate(33.232 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_77" data-name="Rectangle 77" width="4.986" height="1.581" rx="0.723" transform="translate(38.48 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_78" data-name="Rectangle 78" width="4.986" height="1.581" rx="0.723" transform="translate(43.73 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_79" data-name="Rectangle 79" width="4.986" height="1.581" rx="0.723" transform="translate(48.978 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_80" data-name="Rectangle 80" width="4.986" height="1.581" rx="0.723" transform="translate(55.54 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_81" data-name="Rectangle 81" width="4.986" height="1.581" rx="0.723" transform="translate(60.788 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_82" data-name="Rectangle 82" width="4.986" height="1.581" rx="0.723" transform="translate(66.038 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_83" data-name="Rectangle 83" width="4.986" height="1.581" rx="0.723" transform="translate(72.599 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_84" data-name="Rectangle 84" width="4.986" height="1.581" rx="0.723" transform="translate(77.847 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_85" data-name="Rectangle 85" width="4.986" height="1.581" rx="0.723" transform="translate(83.097 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
</g>
|
|
||||||
<path id="Path_59" data-name="Path 59" d="M146.71,159.855a5.439,5.439,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(6.275 -6.025)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_60" data-name="Path 60" d="M83,124.855h43.71V103H83Z" transform="translate(4.42 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_61" data-name="Path 61" d="M134.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.811,2.811,0,0,0,.349.035" transform="translate(7.202 -9.377)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_62" data-name="Path 62" d="M143.232,42.33a2.967,2.967,0,0,1-.535-.055,2.754,2.754,0,0,1-.514-.153,2.838,2.838,0,0,1-.471-.251,4.139,4.139,0,0,1-.415-.339,3.2,3.2,0,0,1-.338-.415A2.7,2.7,0,0,1,140.5,39.6a2.968,2.968,0,0,1,.055-.535,3.152,3.152,0,0,1,.152-.514,2.874,2.874,0,0,1,.252-.47,2.633,2.633,0,0,1,.753-.754,2.837,2.837,0,0,1,.471-.251,2.753,2.753,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,4.019,4.019,0,0,1,.339.415,2.786,2.786,0,0,1,.251.47,2.864,2.864,0,0,1,.208,1.049,2.77,2.77,0,0,1-.8,1.934,4.139,4.139,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459m21.855-1.366a2.789,2.789,0,0,1-1.935-.8,4.162,4.162,0,0,1-.338-.415,2.7,2.7,0,0,1-.459-1.519,2.789,2.789,0,0,1,.8-1.934,4.139,4.139,0,0,1,.415-.339,2.838,2.838,0,0,1,.471-.251,2.752,2.752,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,2.79,2.79,0,0,1,.8,1.934,3.069,3.069,0,0,1-.055.535,2.779,2.779,0,0,1-.153.514,3.885,3.885,0,0,1-.251.47,4.02,4.02,0,0,1-.339.415,4.138,4.138,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459" transform="translate(9.753 -15.532)" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 31 KiB |
|
@ -1,169 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1041.277" height="554.141" viewBox="0 0 1041.277 554.141">
|
|
||||||
<g id="Group_24" data-name="Group 24" transform="translate(-440 -263)">
|
|
||||||
<g id="Group_23" data-name="Group 23" transform="translate(439.989 262.965)">
|
|
||||||
<path id="Path_299" data-name="Path 299" d="M1040.82,611.12q-1.74,3.75-3.47,7.4-2.7,5.67-5.33,11.12c-.78,1.61-1.56,3.19-2.32,4.77-8.6,17.57-16.63,33.11-23.45,45.89A73.21,73.21,0,0,1,942.44,719l-151.65,1.65h-1.6l-13,.14-11.12.12-34.1.37h-1.38l-17.36.19h-.53l-107,1.16-95.51,1-11.11.12-69,.75H429l-44.75.48h-.48l-141.5,1.53-42.33.46a87.991,87.991,0,0,1-10.79-.54h0c-1.22-.14-2.44-.3-3.65-.49a87.38,87.38,0,0,1-51.29-27.54C116,678.37,102.75,655,93.85,629.64q-1.93-5.49-3.6-11.12C59.44,514.37,97,380,164.6,290.08q4.25-5.64,8.64-11l.07-.08c20.79-25.52,44.1-46.84,68.93-62,44-26.91,92.75-34.49,140.7-11.9,40.57,19.12,78.45,28.11,115.17,30.55,3.71.24,7.42.42,11.11.53,84.23,2.65,163.17-27.7,255.87-47.29,3.69-.78,7.39-1.55,11.12-2.28,66.13-13.16,139.49-20.1,226.73-5.51a189.089,189.089,0,0,1,26.76,6.4q5.77,1.86,11.12,4c41.64,16.94,64.35,48.24,74,87.46q1.37,5.46,2.37,11.11C1134.3,384.41,1084.19,518.23,1040.82,611.12Z" transform="translate(-79.34 -172.91)" fill="#f2f2f2"/>
|
|
||||||
<path id="Path_300" data-name="Path 300" d="M576.36,618.52a95.21,95.21,0,0,1-1.87,11.12h93.7V618.52Zm-78.25,62.81,11.11-.09V653.77c-3.81-.17-7.52-.34-11.11-.52ZM265.19,618.52v11.12h198.5V618.52ZM1114.87,279h-74V191.51q-5.35-2.17-11.12-4V279H776.21V186.58c-3.73.73-7.43,1.5-11.12,2.28V279H509.22V236.15c-3.69-.11-7.4-.29-11.11-.53V279H242.24V217c-24.83,15.16-48.14,36.48-68.93,62h-.07v.08q-4.4,5.4-8.64,11h8.64V618.52h-83q1.66,5.63,3.6,11.12h79.39v93.62a87,87,0,0,0,12.2,2.79c1.21.19,2.43.35,3.65.49h0a87.991,87.991,0,0,0,10.79.54l42.33-.46v-97H498.11v94.21l11.11-.12V629.64H765.09V721l11.12-.12V629.64H1029.7v4.77c.76-1.58,1.54-3.16,2.32-4.77q2.63-5.45,5.33-11.12,1.73-3.64,3.47-7.4v-321h76.42Q1116.23,284.43,1114.87,279ZM242.24,618.52V290.08H498.11V618.52Zm267,0V290.08H765.09V618.52Zm520.48,0H776.21V290.08H1029.7Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_301" data-name="Path 301" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" fill="#65617d"/>
|
|
||||||
<path id="Path_302" data-name="Path 302" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" opacity="0.2"/>
|
|
||||||
<path id="Path_303" data-name="Path 303" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_304" data-name="Path 304" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_305" data-name="Path 305" d="M377.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
|
||||||
<rect id="Rectangle_137" data-name="Rectangle 137" width="47.17" height="31.5" transform="translate(680.92 483.65)" fill="#3f3d56"/>
|
|
||||||
<rect id="Rectangle_138" data-name="Rectangle 138" width="47.17" height="31.5" transform="translate(680.92 483.65)" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_139" data-name="Rectangle 139" width="47.17" height="31.5" transform="translate(678.92 483.65)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_306" data-name="Path 306" d="M298.09,483.65v4.97l-47.17,1.26v-6.23Z" opacity="0.1"/>
|
|
||||||
<path id="Path_307" data-name="Path 307" d="M460.69,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6a4,4,0,0,1,3.95,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
|
||||||
<path id="Path_308" data-name="Path 308" d="M265.19,481.32v181.2h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_309" data-name="Path 309" d="M194.59,319.15h177.5V467.4l-177.5,4Z" fill="#39374d"/>
|
|
||||||
<path id="Path_310" data-name="Path 310" d="M726.09,483.65v6.41l-47.17-1.26v-5.15Z" opacity="0.1"/>
|
|
||||||
<path id="Path_311" data-name="Path 311" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0L672,657.42a4,4,0,0,1-3.85-3.95V485.27a4,4,0,0,1,3.95-3.95H863.7a4,4,0,0,1,3.99,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
|
||||||
<path id="Path_312" data-name="Path 312" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0V481.32h0a4,4,0,0,1,4,3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_313" data-name="Path 313" d="M775.59,319.15H598.09V467.4l177.5,4Z" fill="#39374d"/>
|
|
||||||
<path id="Path_314" data-name="Path 314" d="M663.19,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h0a4,4,0,0,1-4-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6A4,4,0,0,1,663.19,485.27Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
|
||||||
<path id="Path_315" data-name="Path 315" d="M397.09,319.15h177.5V467.4l-177.5,4Z" fill="#4267b2"/>
|
|
||||||
<path id="Path_316" data-name="Path 316" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l202.51-1.33h.48l40.99-.28h.19l283.08-1.87h.29l.17-.01h.47l4.79-.03h1.46l74.49-.5,4.4-.02.98-.01Z" opacity="0.1"/>
|
|
||||||
<circle id="Ellipse_111" data-name="Ellipse 111" cx="51.33" cy="51.33" r="51.33" transform="translate(435.93 246.82)" fill="#fbbebe"/>
|
|
||||||
<path id="Path_317" data-name="Path 317" d="M617.94,550.07s-99.5,12-90,0c3.44-4.34,4.39-17.2,4.2-31.85-.06-4.45-.22-9.06-.45-13.65-1.1-22-3.75-43.5-3.75-43.5s87-41,77-8.5c-4,13.13-2.69,31.57.35,48.88.89,5.05,1.92,10,3,14.7a344.66,344.66,0,0,0,9.65,33.92Z" transform="translate(-79.34 -172.91)" fill="#fbbebe"/>
|
|
||||||
<path id="Path_318" data-name="Path 318" d="M585.47,546c11.51-2.13,23.7-6,34.53-1.54,2.85,1.17,5.47,2.88,8.39,3.86s6.12,1.22,9.16,1.91c10.68,2.42,19.34,10.55,24.9,20s8.44,20.14,11.26,30.72l6.9,25.83c6,22.45,12,45.09,13.39,68.3a2437.506,2437.506,0,0,1-250.84,1.43c5.44-10.34,11-21.31,10.54-33s-7.19-23.22-4.76-34.74c1.55-7.34,6.57-13.39,9.64-20.22,8.75-19.52,1.94-45.79,17.32-60.65,6.92-6.68,17-9.21,26.63-8.89,12.28.41,24.85,4.24,37,6.11C555.09,547.48,569.79,548.88,585.47,546Z" transform="translate(-79.34 -172.91)" fill="#ff6584"/>
|
|
||||||
<path id="Path_319" data-name="Path 319" d="M716.37,657.17l-.1,1.43v.1l-.17,2.3-1.33,18.51-1.61,22.3-.46,6.28-1,13.44v.17l-107,1-175.59,1.9v.84h-.14v-1.12l.45-14.36.86-28.06.74-23.79.07-2.37a10.53,10.53,0,0,1,11.42-10.17c4.72.4,10.85.89,18.18,1.41l3,.22c42.33,2.94,120.56,6.74,199.5,2,1.66-.09,3.33-.19,5-.31,12.24-.77,24.47-1.76,36.58-3a10.53,10.53,0,0,1,11.6,11.23Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_320" data-name="Path 320" d="M429.08,725.44v-.84l175.62-1.91,107-1h.3v-.17l1-13.44.43-6,1.64-22.61,1.29-17.9v-.44a10.617,10.617,0,0,0-.11-2.47.3.3,0,0,0,0-.1,10.391,10.391,0,0,0-2-4.64,10.54,10.54,0,0,0-9.42-4c-12.11,1.24-24.34,2.23-36.58,3-1.67.12-3.34.22-5,.31-78.94,4.69-157.17.89-199.5-2l-3-.22c-7.33-.52-13.46-1-18.18-1.41a10.54,10.54,0,0,0-11.24,8.53,11,11,0,0,0-.18,1.64l-.68,22.16L429.54,710l-.44,14.36v1.12Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_321" data-name="Path 321" d="M716.67,664.18l-1.23,15.33-1.83,22.85-.46,5.72-1,12.81-.06.64v.17h0l-.15,1.48.11-1.48h-.29l-107,1-175.65,1.9v-.28l.49-14.36,1-28.06.64-18.65A6.36,6.36,0,0,1,434.3,658a6.25,6.25,0,0,1,3.78-.9c2.1.17,4.68.37,7.69.59,4.89.36,10.92.78,17.94,1.22,13,.82,29.31,1.7,48,2.42,52,2,122.2,2.67,188.88-3.17,3-.26,6.1-.55,9.13-.84a6.26,6.26,0,0,1,3.48.66,5.159,5.159,0,0,1,.86.54,6.14,6.14,0,0,1,2,2.46,3.564,3.564,0,0,1,.25.61A6.279,6.279,0,0,1,716.67,664.18Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_322" data-name="Path 322" d="M377.44,677.87v3.19a6.13,6.13,0,0,1-3.5,5.54l-40.1.77a6.12,6.12,0,0,1-3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_323" data-name="Path 323" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
|
|
||||||
<path id="Path_324" data-name="Path 324" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" opacity="0.1"/>
|
|
||||||
<path id="Path_325" data-name="Path 325" d="M300.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
|
|
||||||
<path id="Path_326" data-name="Path 326" d="M758.56,679.87v3.19a6.13,6.13,0,0,0,3.5,5.54l40.1.77a6.12,6.12,0,0,0,3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
|
||||||
<path id="Path_327" data-name="Path 327" d="M678.72,517.57l52.25,1V509.9l-52.25-1Z" opacity="0.1"/>
|
|
||||||
<path id="Path_328" data-name="Path 328" d="M676.72,517.57l52.25,1V509.9l-52.25-1Z" fill="#3f3d56"/>
|
|
||||||
<path id="Path_329" data-name="Path 329" d="M534.13,486.79c.08,7-3.16,13.6-5.91,20.07a163.491,163.491,0,0,0-12.66,74.71c.73,11,2.58,22,.73,32.9s-8.43,21.77-19,24.9c17.53,10.45,41.26,9.35,57.76-2.66,8.79-6.4,15.34-15.33,21.75-24.11a97.86,97.86,0,0,1-13.31,44.75A103.43,103.43,0,0,0,637,616.53c4.31-5.81,8.06-12.19,9.72-19.23,3.09-13-1.22-26.51-4.51-39.5a266.055,266.055,0,0,1-6.17-33c-.43-3.56-.78-7.22.1-10.7,1-4.07,3.67-7.51,5.64-11.22,5.6-10.54,5.73-23.3,2.86-34.88s-8.49-22.26-14.06-32.81c-4.46-8.46-9.3-17.31-17.46-22.28-5.1-3.1-11-4.39-16.88-5.64l-25.37-5.43c-5.55-1.19-11.26-2.38-16.87-1.51-9.47,1.48-16.14,8.32-22,15.34-4.59,5.46-15.81,15.71-16.6,22.86-.72,6.59,5.1,17.63,6.09,24.58,1.3,9,2.22,6,7.3,11.52C532,478.05,534.07,482,534.13,486.79Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
|
||||||
</g>
|
|
||||||
<g id="docusaurus_keytar" transform="translate(670.271 615.768)">
|
|
||||||
<path id="Path_40" data-name="Path 40" d="M99,52h43.635V69.662H99Z" transform="translate(-49.132 -33.936)" fill="#fff" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_41" data-name="Path 41" d="M13.389,158.195A10.377,10.377,0,0,1,4.4,153a10.377,10.377,0,0,0,8.988,15.584H23.779V158.195Z" transform="translate(-3 -82.47)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_42" data-name="Path 42" d="M66.967,38.083l36.373-2.273V30.615A10.389,10.389,0,0,0,92.95,20.226H46.2l-1.3-2.249a1.5,1.5,0,0,0-2.6,0L41,20.226l-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-.034,0-2.152-2.151a1.5,1.5,0,0,0-2.508.672L25.21,21.4l-2.7-.723a1.5,1.5,0,0,0-1.836,1.837l.722,2.7-2.65.71a1.5,1.5,0,0,0-.673,2.509l2.152,2.152c0,.011,0,.022,0,.033l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6L20.226,41l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3A10.389,10.389,0,0,0,30.615,103.34H92.95A10.389,10.389,0,0,0,103.34,92.95V51.393L66.967,49.12a5.53,5.53,0,0,1,0-11.038" transform="translate(-9.836 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_43" data-name="Path 43" d="M143,163.779h15.584V143H143Z" transform="translate(-70.275 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_44" data-name="Path 44" d="M173.779,148.389a2.582,2.582,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-75.08 -75.262)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_45" data-name="Path 45" d="M153,113.389h15.584V103H153Z" transform="translate(-75.08 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_46" data-name="Path 46" d="M183.389,108.944a1.3,1.3,0,1,0,0-2.6,1.336,1.336,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.337,1.337,0,0,0,.166.017" transform="translate(-84.691 -57.894)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_47" data-name="Path 47" d="M52.188,48.292a1.3,1.3,0,0,1-1.3-1.3,3.9,3.9,0,0,0-7.792,0,1.3,1.3,0,1,1-2.6,0,6.493,6.493,0,0,1,12.987,0,1.3,1.3,0,0,1-1.3,1.3" transform="translate(-21.02 -28.41)" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_48" data-name="Path 48" d="M103,139.752h31.168a10.389,10.389,0,0,0,10.389-10.389V93H113.389A10.389,10.389,0,0,0,103,103.389Z" transform="translate(-51.054 -53.638)" fill="#ffff50" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_49" data-name="Path 49" d="M141.1,94.017H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0-25.877H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.293H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m7.782-47.993c-.006,0-.011,0-.018,0-1.605.055-2.365,1.66-3.035,3.077-.7,1.48-1.24,2.443-2.126,2.414-.981-.035-1.542-1.144-2.137-2.317-.683-1.347-1.462-2.876-3.1-2.819-1.582.054-2.344,1.451-3.017,2.684-.715,1.313-1.2,2.112-2.141,2.075-1-.036-1.533-.938-2.149-1.981-.686-1.162-1.479-2.467-3.084-2.423-1.555.053-2.319,1.239-2.994,2.286-.713,1.106-1.213,1.781-2.164,1.741-1.025-.036-1.554-.784-2.167-1.65-.688-.973-1.463-2.074-3.062-2.021a3.815,3.815,0,0,0-2.959,1.879c-.64.812-1.14,1.456-2.2,1.415a.52.52,0,0,0-.037,1.039,3.588,3.588,0,0,0,3.05-1.811c.611-.777,1.139-1.448,2.178-1.483,1-.043,1.47.579,2.179,1.582.674.953,1.438,2.033,2.977,2.089,1.612.054,2.387-1.151,3.074-2.217.614-.953,1.144-1.775,2.156-1.81.931-.035,1.438.7,2.153,1.912.674,1.141,1.437,2.434,3.006,2.491,1.623.056,2.407-1.361,3.09-2.616.592-1.085,1.15-2.109,2.14-2.143.931-.022,1.417.829,2.135,2.249.671,1.326,1.432,2.828,3.026,2.886l.088,0c1.592,0,2.347-1.6,3.015-3.01.592-1.252,1.152-2.431,2.113-2.479Z" transform="translate(-55.378 -38.552)" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_50" data-name="Path 50" d="M83,163.779h20.779V143H83Z" transform="translate(-41.443 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 51.971, 43.3)">
|
|
||||||
<rect id="Rectangle_3" data-name="Rectangle 3" width="43.906" height="17.333" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
|
|
||||||
<g id="Group_2" data-name="Group 2" transform="translate(0.728 10.948)">
|
|
||||||
<rect id="Rectangle_4" data-name="Rectangle 4" width="2.537" height="2.537" rx="1" transform="translate(7.985 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_5" data-name="Rectangle 5" width="2.537" height="2.537" rx="1" transform="translate(10.991 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_6" data-name="Rectangle 6" width="2.537" height="2.537" rx="1" transform="translate(13.997 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_7" data-name="Rectangle 7" width="2.537" height="2.537" rx="1" transform="translate(17.003 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_8" data-name="Rectangle 8" width="2.537" height="2.537" rx="1" transform="translate(20.009 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_9" data-name="Rectangle 9" width="2.537" height="2.537" rx="1" transform="translate(23.015 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_10" data-name="Rectangle 10" width="2.537" height="2.537" rx="1" transform="translate(26.021 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_11" data-name="Rectangle 11" width="2.537" height="2.537" rx="1" transform="translate(29.028 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_12" data-name="Rectangle 12" width="2.537" height="2.537" rx="1" transform="translate(32.034 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_51" data-name="Path 51" d="M.519,0H6.9A.519.519,0,0,1,7.421.52v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0ZM35.653,0h6.383a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H35.652a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,35.652,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_3" data-name="Group 3" transform="translate(0.728 4.878)">
|
|
||||||
<path id="Path_52" data-name="Path 52" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_13" data-name="Rectangle 13" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_14" data-name="Rectangle 14" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_15" data-name="Rectangle 15" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_16" data-name="Rectangle 16" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_17" data-name="Rectangle 17" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_18" data-name="Rectangle 18" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_19" data-name="Rectangle 19" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_20" data-name="Rectangle 20" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_21" data-name="Rectangle 21" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_22" data-name="Rectangle 22" width="2.537" height="2.537" rx="1" transform="translate(31 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_23" data-name="Rectangle 23" width="2.537" height="2.537" rx="1" transform="translate(34.006 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_24" data-name="Rectangle 24" width="2.537" height="2.537" rx="1" transform="translate(37.012 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_25" data-name="Rectangle 25" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_4" data-name="Group 4" transform="translate(43.283 4.538) rotate(180)">
|
|
||||||
<path id="Path_53" data-name="Path 53" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_26" data-name="Rectangle 26" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_27" data-name="Rectangle 27" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_28" data-name="Rectangle 28" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_29" data-name="Rectangle 29" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_30" data-name="Rectangle 30" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_31" data-name="Rectangle 31" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_32" data-name="Rectangle 32" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_33" data-name="Rectangle 33" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_34" data-name="Rectangle 34" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_35" data-name="Rectangle 35" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_36" data-name="Rectangle 36" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_37" data-name="Rectangle 37" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_38" data-name="Rectangle 38" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_39" data-name="Rectangle 39" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_40" data-name="Rectangle 40" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_41" data-name="Rectangle 41" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_42" data-name="Rectangle 42" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_43" data-name="Rectangle 43" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_44" data-name="Rectangle 44" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_45" data-name="Rectangle 45" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_46" data-name="Rectangle 46" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_47" data-name="Rectangle 47" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_48" data-name="Rectangle 48" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_49" data-name="Rectangle 49" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_50" data-name="Rectangle 50" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_51" data-name="Rectangle 51" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_6" data-name="Group 6" transform="translate(0.728 7.883)">
|
|
||||||
<path id="Path_54" data-name="Path 54" d="M.519,0h3.47a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<g id="Group_5" data-name="Group 5" transform="translate(5.073 0)">
|
|
||||||
<rect id="Rectangle_52" data-name="Rectangle 52" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_53" data-name="Rectangle 53" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_54" data-name="Rectangle 54" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_55" data-name="Rectangle 55" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_56" data-name="Rectangle 56" width="2.537" height="2.537" rx="1" transform="translate(12.025 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_57" data-name="Rectangle 57" width="2.537" height="2.537" rx="1" transform="translate(15.031 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_58" data-name="Rectangle 58" width="2.537" height="2.537" rx="1" transform="translate(18.037 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_59" data-name="Rectangle 59" width="2.537" height="2.537" rx="1" transform="translate(21.042 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_60" data-name="Rectangle 60" width="2.537" height="2.537" rx="1" transform="translate(24.049 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_61" data-name="Rectangle 61" width="2.537" height="2.537" rx="1" transform="translate(27.055 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_62" data-name="Rectangle 62" width="2.537" height="2.537" rx="1" transform="translate(30.061 0)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<path id="Path_55" data-name="Path 55" d="M.52,0H3.8a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(38.234 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_7" data-name="Group 7" transform="translate(0.728 14.084)">
|
|
||||||
<rect id="Rectangle_63" data-name="Rectangle 63" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_64" data-name="Rectangle 64" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_65" data-name="Rectangle 65" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_66" data-name="Rectangle 66" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_56" data-name="Path 56" d="M.519,0H14.981A.519.519,0,0,1,15.5.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.018V.519A.519.519,0,0,1,.519,0Zm15.97,0h1.874a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H16.489a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,16.489,0Z" transform="translate(12.024 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
|
||||||
<rect id="Rectangle_67" data-name="Rectangle 67" width="2.537" height="2.537" rx="1" transform="translate(31.376 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_68" data-name="Rectangle 68" width="2.537" height="2.537" rx="1" transform="translate(34.382 0)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_69" data-name="Rectangle 69" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_57" data-name="Path 57" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(39.736 1.08) rotate(180)" fill="#4a4a4a"/>
|
|
||||||
<path id="Path_58" data-name="Path 58" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(37.2 1.456)" fill="#4a4a4a"/>
|
|
||||||
</g>
|
|
||||||
<rect id="Rectangle_70" data-name="Rectangle 70" width="42.273" height="1.127" rx="0.564" transform="translate(0.915 0.556)" fill="#4a4a4a"/>
|
|
||||||
<rect id="Rectangle_71" data-name="Rectangle 71" width="2.37" height="0.752" rx="0.376" transform="translate(1.949 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_72" data-name="Rectangle 72" width="2.37" height="0.752" rx="0.376" transform="translate(5.193 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_73" data-name="Rectangle 73" width="2.37" height="0.752" rx="0.376" transform="translate(7.688 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_74" data-name="Rectangle 74" width="2.37" height="0.752" rx="0.376" transform="translate(10.183 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_75" data-name="Rectangle 75" width="2.37" height="0.752" rx="0.376" transform="translate(12.679 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_76" data-name="Rectangle 76" width="2.37" height="0.752" rx="0.376" transform="translate(15.797 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_77" data-name="Rectangle 77" width="2.37" height="0.752" rx="0.376" transform="translate(18.292 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_78" data-name="Rectangle 78" width="2.37" height="0.752" rx="0.376" transform="translate(20.788 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_79" data-name="Rectangle 79" width="2.37" height="0.752" rx="0.376" transform="translate(23.283 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_80" data-name="Rectangle 80" width="2.37" height="0.752" rx="0.376" transform="translate(26.402 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_81" data-name="Rectangle 81" width="2.37" height="0.752" rx="0.376" transform="translate(28.897 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_82" data-name="Rectangle 82" width="2.37" height="0.752" rx="0.376" transform="translate(31.393 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_83" data-name="Rectangle 83" width="2.37" height="0.752" rx="0.376" transform="translate(34.512 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_84" data-name="Rectangle 84" width="2.37" height="0.752" rx="0.376" transform="translate(37.007 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
<rect id="Rectangle_85" data-name="Rectangle 85" width="2.37" height="0.752" rx="0.376" transform="translate(39.502 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
|
||||||
</g>
|
|
||||||
<path id="Path_59" data-name="Path 59" d="M123.779,148.389a2.583,2.583,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-51.054 -75.262)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_60" data-name="Path 60" d="M83,113.389h20.779V103H83Z" transform="translate(-41.443 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_61" data-name="Path 61" d="M123.389,108.944a1.3,1.3,0,1,0,0-2.6,1.338,1.338,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.335,1.335,0,0,0,.166.017" transform="translate(-55.859 -57.894)" fill="#44d860" fill-rule="evenodd"/>
|
|
||||||
<path id="Path_62" data-name="Path 62" d="M141.8,38.745a1.41,1.41,0,0,1-.255-.026,1.309,1.309,0,0,1-.244-.073,1.349,1.349,0,0,1-.224-.119,1.967,1.967,0,0,1-.2-.161,1.52,1.52,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.41,1.41,0,0,1,.026-.255,1.5,1.5,0,0,1,.072-.244,1.364,1.364,0,0,1,.12-.223,1.252,1.252,0,0,1,.358-.358,1.349,1.349,0,0,1,.224-.119,1.309,1.309,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.968,1.968,0,0,1,.2.161,1.908,1.908,0,0,1,.161.2,1.322,1.322,0,0,1,.12.223,1.361,1.361,0,0,1,.1.5,1.317,1.317,0,0,1-.379.919,1.968,1.968,0,0,1-.2.161,1.346,1.346,0,0,1-.223.119,1.332,1.332,0,0,1-.5.1m10.389-.649a1.326,1.326,0,0,1-.92-.379,1.979,1.979,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.326,1.326,0,0,1,.379-.919,1.967,1.967,0,0,1,.2-.161,1.351,1.351,0,0,1,.224-.119,1.308,1.308,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.967,1.967,0,0,1,.2.161,1.326,1.326,0,0,1,.379.919,1.461,1.461,0,0,1-.026.255,1.323,1.323,0,0,1-.073.244,1.847,1.847,0,0,1-.119.223,1.911,1.911,0,0,1-.161.2,1.967,1.967,0,0,1-.2.161,1.294,1.294,0,0,1-.722.218" transform="translate(-69.074 -26.006)" fill-rule="evenodd"/>
|
|
||||||
</g>
|
|
||||||
<g id="React-icon" transform="translate(906.3 541.56)">
|
|
||||||
<path id="Path_330" data-name="Path 330" d="M263.668,117.179c0-5.827-7.3-11.35-18.487-14.775,2.582-11.4,1.434-20.477-3.622-23.382a7.861,7.861,0,0,0-4.016-1v4a4.152,4.152,0,0,1,2.044.466c2.439,1.4,3.5,6.724,2.672,13.574-.2,1.685-.52,3.461-.914,5.272a86.9,86.9,0,0,0-11.386-1.954,87.469,87.469,0,0,0-7.459-8.965c5.845-5.433,11.332-8.41,15.062-8.41V78h0c-4.931,0-11.386,3.514-17.913,9.611-6.527-6.061-12.982-9.539-17.913-9.539v4c3.712,0,9.216,2.959,15.062,8.356a84.687,84.687,0,0,0-7.405,8.947,83.732,83.732,0,0,0-11.4,1.972c-.412-1.793-.717-3.532-.932-5.2-.843-6.85.2-12.175,2.618-13.592a3.991,3.991,0,0,1,2.062-.466v-4h0a8,8,0,0,0-4.052,1c-5.039,2.9-6.168,11.96-3.568,23.328-11.153,3.443-18.415,8.947-18.415,14.757,0,5.828,7.3,11.35,18.487,14.775-2.582,11.4-1.434,20.477,3.622,23.382a7.882,7.882,0,0,0,4.034,1c4.931,0,11.386-3.514,17.913-9.611,6.527,6.061,12.982,9.539,17.913,9.539a8,8,0,0,0,4.052-1c5.039-2.9,6.168-11.96,3.568-23.328C256.406,128.511,263.668,122.988,263.668,117.179Zm-23.346-11.96c-.663,2.313-1.488,4.7-2.421,7.083-.735-1.434-1.506-2.869-2.349-4.3-.825-1.434-1.7-2.833-2.582-4.2C235.517,104.179,237.974,104.645,240.323,105.219Zm-8.212,19.1c-1.4,2.421-2.833,4.716-4.321,6.85-2.672.233-5.379.359-8.1.359-2.708,0-5.415-.126-8.069-.341q-2.232-3.2-4.339-6.814-2.044-3.523-3.73-7.136c1.112-2.4,2.367-4.805,3.712-7.154,1.4-2.421,2.833-4.716,4.321-6.85,2.672-.233,5.379-.359,8.1-.359,2.708,0,5.415.126,8.069.341q2.232,3.2,4.339,6.814,2.044,3.523,3.73,7.136C234.692,119.564,233.455,121.966,232.11,124.315Zm5.792-2.331c.968,2.4,1.793,4.805,2.474,7.136-2.349.574-4.823,1.058-7.387,1.434.879-1.381,1.757-2.8,2.582-4.25C236.4,124.871,237.167,123.419,237.9,121.984ZM219.72,141.116a73.921,73.921,0,0,1-4.985-5.738c1.614.072,3.263.126,4.931.126,1.685,0,3.353-.036,4.985-.126A69.993,69.993,0,0,1,219.72,141.116ZM206.38,130.555c-2.546-.377-5-.843-7.352-1.417.663-2.313,1.488-4.7,2.421-7.083.735,1.434,1.506,2.869,2.349,4.3S205.5,129.192,206.38,130.555ZM219.63,93.241a73.924,73.924,0,0,1,4.985,5.738c-1.614-.072-3.263-.126-4.931-.126-1.686,0-3.353.036-4.985.126A69.993,69.993,0,0,1,219.63,93.241ZM206.362,103.8c-.879,1.381-1.757,2.8-2.582,4.25-.825,1.434-1.6,2.869-2.331,4.3-.968-2.4-1.793-4.805-2.474-7.136C201.323,104.663,203.8,104.179,206.362,103.8Zm-16.227,22.449c-6.348-2.708-10.454-6.258-10.454-9.073s4.106-6.383,10.454-9.073c1.542-.663,3.228-1.255,4.967-1.811a86.122,86.122,0,0,0,4.034,10.92,84.9,84.9,0,0,0-3.981,10.866C193.38,127.525,191.694,126.915,190.134,126.252Zm9.647,25.623c-2.439-1.4-3.5-6.724-2.672-13.574.2-1.686.52-3.461.914-5.272a86.9,86.9,0,0,0,11.386,1.954,87.465,87.465,0,0,0,7.459,8.965c-5.845,5.433-11.332,8.41-15.062,8.41A4.279,4.279,0,0,1,199.781,151.875Zm42.532-13.663c.843,6.85-.2,12.175-2.618,13.592a3.99,3.99,0,0,1-2.062.466c-3.712,0-9.216-2.959-15.062-8.356a84.689,84.689,0,0,0,7.405-8.947,83.731,83.731,0,0,0,11.4-1.972A50.194,50.194,0,0,1,242.313,138.212Zm6.9-11.96c-1.542.663-3.228,1.255-4.967,1.811a86.12,86.12,0,0,0-4.034-10.92,84.9,84.9,0,0,0,3.981-10.866c1.775.556,3.461,1.165,5.039,1.829,6.348,2.708,10.454,6.258,10.454,9.073C259.67,119.994,255.564,123.562,249.216,126.252Z" fill="#61dafb"/>
|
|
||||||
<path id="Path_331" data-name="Path 331" d="M320.8,78.4Z" transform="translate(-119.082 -0.328)" fill="#61dafb"/>
|
|
||||||
<circle id="Ellipse_112" data-name="Ellipse 112" cx="8.194" cy="8.194" r="8.194" transform="translate(211.472 108.984)" fill="#61dafb"/>
|
|
||||||
<path id="Path_332" data-name="Path 332" d="M520.5,78.1Z" transform="translate(-282.975 -0.082)" fill="#61dafb"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 12 KiB |