Merge branch 'Umur-reducer-dev' into reducer-dev
18
README.md
|
@ -1,12 +1,22 @@
|
|||
# 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)
|
||||
[![npm version](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 - lang](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||
[![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)
|
||||
[![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
|
||||
|
||||
|
@ -27,7 +37,7 @@ the packages can be found in `packages`.
|
|||
- `@quri/squiggle-components` in `packages/components` contains React components that
|
||||
can be passed squiggle strings as props, and return a presentation of the result
|
||||
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`.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
@ -24,6 +42,5 @@ yarn start
|
|||
And build artefacts for production,
|
||||
|
||||
```sh
|
||||
yarn bundle # builds components library
|
||||
yarn build # builds storybook app
|
||||
```
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
{
|
||||
"name": "@quri/squiggle-components",
|
||||
"version": "0.2.9",
|
||||
"licence": "MIT",
|
||||
"version": "0.2.14",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"antd": "^4.20.1",
|
||||
"react-ace": "10.1.0",
|
||||
"@quri/squiggle-lang": "^0.2.7",
|
||||
"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",
|
||||
"lodash": "^4.17.21",
|
||||
"styled-components": "^5.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -26,31 +32,25 @@
|
|||
"webpack": "^5.72.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.8.1",
|
||||
"@quri/squiggle-lang": "0.2.5",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.1.1",
|
||||
"@testing-library/user-event": "^14.1.1",
|
||||
"@types/jest": "^27.4.0",
|
||||
"web-vitals": "^2.1.4",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "^17.0.29",
|
||||
"@types/react": "^18.0.3",
|
||||
"@types/react-dom": "^18.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.1.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-vega": "^7.5.0",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"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"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||
"build": "tsc -b && build-storybook -s public",
|
||||
"build:package": "tsc -b",
|
||||
"bundle": "webpack",
|
||||
"all": "yarn bundle && yarn build",
|
||||
"lint": "prettier --check .",
|
||||
|
@ -88,6 +88,7 @@
|
|||
"@types/react": "17.0.43"
|
||||
},
|
||||
"source": "./src/index.ts",
|
||||
"main": "dist/bundle.js",
|
||||
"browser": "dist/bundle.js",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { distributionErrorToString } from "@quri/squiggle-lang";
|
|||
import { createClassFromSpec } from "react-vega";
|
||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||
import { ErrorBox } from "./ErrorBox";
|
||||
import styled from "styled-components";
|
||||
|
||||
let SquiggleVegaChart = createClassFromSpec({
|
||||
spec: chartSpecification as Spec,
|
||||
|
@ -24,19 +25,21 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
|||
}: DistributionChartProps) => {
|
||||
let shape = distribution.pointSet();
|
||||
if (shape.tag === "Ok") {
|
||||
return (
|
||||
let widthProp = width ? width - 20 : undefined;
|
||||
var result = (
|
||||
<SquiggleVegaChart
|
||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||
width={width - 20}
|
||||
width={widthProp}
|
||||
height={height}
|
||||
actions={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
var result = (
|
||||
<ErrorBox heading="Distribution Error">
|
||||
{distributionErrorToString(shape.value)}
|
||||
</ErrorBox>
|
||||
);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -3,10 +3,12 @@ import _ from "lodash";
|
|||
import styled from "styled-components";
|
||||
import {
|
||||
run,
|
||||
runPartial,
|
||||
errorValueToString,
|
||||
squiggleExpression,
|
||||
bindings,
|
||||
samplingParams,
|
||||
} from "@quri/squiggle-lang";
|
||||
import type { samplingParams } from "@quri/squiggle-lang";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { DistributionChart } from "./DistributionChart";
|
||||
import { ErrorBox } from "./ErrorBox";
|
||||
|
@ -44,6 +46,8 @@ export const VariableBox: React.FC<{
|
|||
);
|
||||
};
|
||||
|
||||
let RecordKeyHeader = styled.h3``;
|
||||
|
||||
export interface SquiggleItemProps {
|
||||
/** The input string for squiggle */
|
||||
expression: squiggleExpression;
|
||||
|
@ -104,6 +108,17 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
|||
))}
|
||||
</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:
|
||||
return (
|
||||
<ErrorBox heading="No Viewer">
|
||||
|
@ -135,40 +150,43 @@ export interface SquiggleChartProps {
|
|||
/** CSS width of the element */
|
||||
width?: 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> = ({
|
||||
squiggleString = "",
|
||||
sampleCount = 1000,
|
||||
outputXYPoints = 1000,
|
||||
onChange = () => {},
|
||||
height = 60,
|
||||
bindings = {},
|
||||
width = NaN,
|
||||
}: SquiggleChartProps) => {
|
||||
const target = React.useRef(null);
|
||||
const [componentWidth] = useSize(target);
|
||||
// I would have wanted to just use componentWidth, but this created infinite loops with SquiggleChart.stories.
|
||||
//So you can manually add a width, as an escape hatch.
|
||||
let _width = width || componentWidth;
|
||||
let samplingInputs: samplingParams = {
|
||||
sampleCount: sampleCount,
|
||||
xyPointLength: outputXYPoints,
|
||||
};
|
||||
let expressionResult = run(squiggleString, samplingInputs);
|
||||
let expressionResult = run(squiggleString, bindings, samplingInputs);
|
||||
let internal: JSX.Element;
|
||||
if (expressionResult.tag === "Ok") {
|
||||
let expression = expressionResult.value;
|
||||
onChange(expression);
|
||||
internal = (
|
||||
<SquiggleItem expression={expression} width={_width} height={height} />
|
||||
<SquiggleItem expression={expression} width={width} height={height} />
|
||||
);
|
||||
} else {
|
||||
// At this point, we came across an error. What was our error?
|
||||
internal = (
|
||||
<ErrorBox heading={"Parse Error"}>
|
||||
{errorValueToString(expressionResult.value)}
|
||||
</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 { CodeEditor } from "./CodeEditor";
|
||||
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 {
|
||||
/** The input string for squiggle */
|
||||
|
@ -26,6 +28,8 @@ export interface SquiggleEditorProps {
|
|||
onChange?(expr: squiggleExpression): void;
|
||||
/** The width of the element */
|
||||
width: number;
|
||||
/** Previous variable declarations */
|
||||
bindings: bindings;
|
||||
}
|
||||
|
||||
const Input = styled.div`
|
||||
|
@ -46,6 +50,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
|||
diagramCount,
|
||||
onChange,
|
||||
environment,
|
||||
bindings = {},
|
||||
}: SquiggleEditorProps) => {
|
||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||
return (
|
||||
|
@ -71,6 +76,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
|||
diagramCount={diagramCount}
|
||||
environment={environment}
|
||||
onChange={onChange}
|
||||
bindings={bindings}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -107,3 +113,76 @@ export function renderSquiggleEditorToDom(props: SquiggleEditorProps) {
|
|||
);
|
||||
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 React, { FC, useState } from "react";
|
||||
import React, { FC, ReactElement, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { SquiggleChart } from "./SquiggleChart";
|
||||
import CodeEditor from "./CodeEditor";
|
||||
import { Form, Input, Row, Col } from "antd";
|
||||
import styled from "styled-components";
|
||||
import "antd/dist/antd.css";
|
||||
|
||||
interface FieldFloatProps {
|
||||
label: string;
|
||||
|
@ -14,10 +12,19 @@ interface FieldFloatProps {
|
|||
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) {
|
||||
let [contents, setContents] = useState(Props.value + "");
|
||||
return (
|
||||
<Form.Item label={Props.label}>
|
||||
<FormItem label={Props.label}>
|
||||
<Input
|
||||
value={contents}
|
||||
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;
|
||||
`;
|
||||
|
||||
const Row = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
`;
|
||||
const Col = styled.div``;
|
||||
|
||||
let SquigglePlayground: FC<Props> = ({
|
||||
initialSquiggleString = "",
|
||||
height = 300,
|
||||
|
@ -79,7 +92,7 @@ let SquigglePlayground: FC<Props> = ({
|
|||
return (
|
||||
<ShowBox height={height}>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Col>
|
||||
<CodeEditor
|
||||
value={squiggleString}
|
||||
onChange={setSquiggleString}
|
||||
|
@ -88,7 +101,7 @@ let SquigglePlayground: FC<Props> = ({
|
|||
height={height - 3}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Col>
|
||||
<Display maxHeight={height - 3}>
|
||||
<SquiggleChart
|
||||
squiggleString={squiggleString}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
export { SquiggleChart } from "./components/SquiggleChart";
|
||||
export {
|
||||
SquiggleEditor,
|
||||
SquigglePartial,
|
||||
renderSquiggleEditorToDom,
|
||||
renderSquigglePartialToDom,
|
||||
} from "./components/SquiggleEditor";
|
||||
import SquigglePlayground, {
|
||||
renderSquigglePlaygroundToDom,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"description": "A basic area chart example",
|
||||
"width": 500,
|
||||
"height": 100,
|
||||
"autosize": "fit",
|
||||
"padding": 5,
|
||||
"data": [
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@ node_modules
|
|||
shell.nix
|
||||
.cache
|
||||
.direnv
|
||||
src
|
||||
__tests__
|
||||
lib
|
||||
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
|
||||
|
||||
## Build for development
|
||||
|
@ -15,13 +18,16 @@ Other:
|
|||
```sh
|
||||
yarn start # listens to files and recompiles at every mutation
|
||||
yarn test
|
||||
yarn test:watch # keeps an active session and runs all tests at every mutation
|
||||
|
||||
# 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.
|
||||
|
||||
|
@ -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`.
|
||||
|
||||
`.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 ErrorValue = Reducer_ErrorValue
|
||||
|
||||
|
@ -14,47 +14,18 @@ let unwrapRecord = rValue =>
|
|||
)
|
||||
|
||||
let expectParseToBe = (expr: string, answer: string) =>
|
||||
Reducer.parse(expr)->Expression.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)
|
||||
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||
|
||||
let expectEvalToBe = (expr: string, answer: string) =>
|
||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
||||
|
||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
||||
Reducer.evaluateUsingOptions(
|
||||
expr,
|
||||
~externalBindings=Some(bindings),
|
||||
~isPartial=None,
|
||||
~environment=None,
|
||||
)
|
||||
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None)
|
||||
->ExpressionValue.toStringResult
|
||||
->expect
|
||||
->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 testParseOuterToBe = (expr, answer) => test(expr, () => expectParseOuterToBe(expr, answer))
|
||||
let testParsePartialToBe = (expr, answer) => test(expr, () => expectParsePartialToBe(expr, answer))
|
||||
let testDescriptionParseToBe = (desc, 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 testEvalBindingsToBe = (expr, bindingsList, 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 = {
|
||||
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 testEvalBindingsToBe = (expr, bindingsList, 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 = {
|
||||
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 testEvalBindingsToBe = (expr, bindingsList, 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 Reducer_TestHelpers
|
||||
|
||||
describe("Parse for Bindings", () => {
|
||||
testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
||||
testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
||||
testParseOuterToBe(
|
||||
"y = x+1; y",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
||||
)
|
||||
})
|
||||
// describe("Parse for Bindings", () => {
|
||||
// testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
||||
// testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
||||
// testParseOuterToBe(
|
||||
// "y = x+1; y",
|
||||
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
||||
// )
|
||||
// })
|
||||
|
||||
describe("Parse Partial", () => {
|
||||
testParsePartialToBe(
|
||||
"x",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
||||
)
|
||||
testParsePartialToBe(
|
||||
"y=x",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
||||
)
|
||||
testParsePartialToBe(
|
||||
"y=x+1",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
||||
)
|
||||
testParsePartialToBe(
|
||||
"y = x+1; z = y",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
||||
)
|
||||
})
|
||||
// describe("Parse Partial", () => {
|
||||
// testParsePartialToBe(
|
||||
// "x",
|
||||
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
||||
// )
|
||||
// testParsePartialToBe(
|
||||
// "y=x",
|
||||
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
||||
// )
|
||||
// testParsePartialToBe(
|
||||
// "y=x+1",
|
||||
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
||||
// )
|
||||
// testParsePartialToBe(
|
||||
// "y = x+1; z = y",
|
||||
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
||||
// )
|
||||
// })
|
||||
|
||||
describe("Eval with Bindings", () => {
|
||||
testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)")
|
||||
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", 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.
|
||||
Therefore it does not end with an expression.
|
||||
*/
|
||||
describe("Eval Partial", () => {
|
||||
testEvalPartialBindingsToBe(
|
||||
// A partial cannot end with an expression
|
||||
"x",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"Error(Assignment expected)",
|
||||
)
|
||||
testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1, y: 1})")
|
||||
testEvalPartialBindingsToBe(
|
||||
"y=x+1",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"Ok({x: 1, y: 2})",
|
||||
)
|
||||
testEvalPartialBindingsToBe(
|
||||
"y = x+1; z = y",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"Ok({x: 1, y: 2, z: 2})",
|
||||
)
|
||||
})
|
||||
// describe("Eval Partial", () => {
|
||||
// testEvalPartialBindingsToBe(
|
||||
// // A partial cannot end with an expression
|
||||
// "x",
|
||||
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||
// "Error(Assignment expected)",
|
||||
// )
|
||||
// testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 1})")
|
||||
// testEvalPartialBindingsToBe(
|
||||
// "y=x+1",
|
||||
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||
// "Ok({x: 1,y: 2})",
|
||||
// )
|
||||
// testEvalPartialBindingsToBe(
|
||||
// "y = x+1; z = y",
|
||||
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||
// "Ok({x: 1,y: 2,z: 2})",
|
||||
// )
|
||||
// })
|
||||
|
|
|
@ -2,8 +2,8 @@ open Jest
|
|||
open Reducer_TestHelpers
|
||||
|
||||
describe("Parse function assignment", () => {
|
||||
testParseToBe("f(x)=x", "Ok((:$let :f (:$lambda (x) :x)))")
|
||||
testParseToBe("f(x)=2*x", "Ok((:$let :f (:$lambda (x) (:multiply 2 :x))))")
|
||||
testParseToBe("f(x)=x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block :x)))))")
|
||||
testParseToBe("f(x)=2*x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block (:multiply 2 :x))))))")
|
||||
//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
|
||||
|
||||
describe("expressions", () => {
|
||||
testParseToBe("1", "Ok(1)")
|
||||
testParseToBe("(1)", "Ok(1)")
|
||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
||||
testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")
|
||||
testParseToBe("1", "Ok((:$$block 1))")
|
||||
testParseToBe("(1)", "Ok((:$$block 1))")
|
||||
testParseToBe("1+2", "Ok((:$$block (:add 1 2)))")
|
||||
testParseToBe("1+2*3", "Ok((:$$block (:add 1 (:multiply 2 3))))")
|
||||
})
|
||||
describe("arrays", () => {
|
||||
//Note. () is a empty list in Lisp
|
||||
// The only builtin structure in Lisp is list. There are no arrays
|
||||
// [1,2,3] becomes (1 2 3)
|
||||
testDescriptionParseToBe("empty", "[]", "Ok(())")
|
||||
testParseToBe("[1, 2, 3]", "Ok((1 2 3))")
|
||||
testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")
|
||||
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")
|
||||
testDescriptionParseToBe("empty", "[]", "Ok((:$$block ()))")
|
||||
testParseToBe("[1, 2, 3]", "Ok((:$$block (1 2 3)))")
|
||||
testParseToBe("['hello', 'world']", "Ok((:$$block ('hello' 'world')))")
|
||||
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$$block (:$atIndex (0 1 2) (1))))")
|
||||
})
|
||||
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(
|
||||
"use",
|
||||
"{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", () => {
|
||||
testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))")
|
||||
testParseToBe(
|
||||
"1+1; 2+1",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))",
|
||||
)
|
||||
testParseToBe("1; 2", "Ok((:$$block (:$$block 1 2)))")
|
||||
testParseToBe("1+1; 2+1", "Ok((:$$block (:$$block (:add 1 1) (:add 2 1))))")
|
||||
})
|
||||
describe("assignment", () => {
|
||||
testParseToBe(
|
||||
"x=1; x",
|
||||
"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)))",
|
||||
)
|
||||
testParseToBe("x=1; x", "Ok((:$$block (:$$block (:$let :x 1) :x)))")
|
||||
testParseToBe("x=1+1; x+1", "Ok((:$$block (:$$block (:$let :x (:add 1 1)) (:add :x 1))))")
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -70,13 +63,13 @@ describe("eval", () => {
|
|||
})
|
||||
describe("arrays", () => {
|
||||
test("empty array", () => expectEvalToBe("[]", "Ok([])"))
|
||||
testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")
|
||||
testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")
|
||||
testEvalToBe("[1, 2, 3]", "Ok([1,2,3])")
|
||||
testEvalToBe("['hello', 'world']", "Ok(['hello','world'])")
|
||||
testEvalToBe("([0,1,2])[1]", "Ok(1)")
|
||||
testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
|
||||
})
|
||||
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 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("1; x=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(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(
|
||||
"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("log10(uniform(5,8))", "Ok(Sample Set Distribution)")
|
||||
|
@ -119,27 +119,33 @@ describe("eval on distribution functions", () => {
|
|||
|
||||
describe("parse on distribution functions", () => {
|
||||
describe("power", () => {
|
||||
testParse("normal(5,2) ^ normal(5,1)", "Ok((:pow (:normal 5 2) (:normal 5 1)))")
|
||||
testParse("3 ^ normal(5,1)", "Ok((:pow 3 (:normal 5 1)))")
|
||||
testParse("normal(5,2) ^ 3", "Ok((:pow (:normal 5 2) 3))")
|
||||
testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$block (:pow (:normal 5 2) (:normal 5 1))))")
|
||||
testParse("3 ^ normal(5,1)", "Ok((:$$block (:pow 3 (:normal 5 1))))")
|
||||
testParse("normal(5,2) ^ 3", "Ok((:$$block (:pow (:normal 5 2) 3)))")
|
||||
})
|
||||
describe("subtraction", () => {
|
||||
testParse("10 - normal(5,1)", "Ok((:subtract 10 (:normal 5 1)))")
|
||||
testParse("normal(5,1) - 10", "Ok((:subtract (:normal 5 1) 10))")
|
||||
testParse("10 - normal(5,1)", "Ok((:$$block (:subtract 10 (:normal 5 1))))")
|
||||
testParse("normal(5,1) - 10", "Ok((:$$block (:subtract (:normal 5 1) 10)))")
|
||||
})
|
||||
describe("pointwise arithmetic expressions", () => {
|
||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||
testParse(
|
||||
~skip=true,
|
||||
"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("normal(5,2) ./ normal(5,1)", "Ok((:dotDivide (:normal 5 2) (:normal 5 1)))")
|
||||
testParse("normal(5,2) .^ normal(5,1)", "Ok((:dotPow (:normal 5 2) (:normal 5 1)))")
|
||||
testParse(
|
||||
"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", () => {
|
||||
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", () => {
|
||||
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
|
||||
|
||||
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", () =>
|
||||
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 {
|
||||
run,
|
||||
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)
|
||||
);
|
||||
}
|
||||
};
|
||||
import { Distribution, resultMap } from "../../src/js/index";
|
||||
import { testRun, testRunPartial } from "./TestHelpers";
|
||||
|
||||
function Ok<b>(x: b) {
|
||||
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", () => {
|
||||
//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.
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import {
|
||||
run,
|
||||
// Distribution,
|
||||
runPartial,
|
||||
bindings,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
// errorValue,
|
||||
// result,
|
||||
} from "../../src/js/index";
|
||||
|
||||
export function testRun(x: string): squiggleExpression {
|
||||
let squiggleResult = run(x, { sampleCount: 1000, xyPointLength: 100 });
|
||||
export function testRun(x: string, bindings = {}): squiggleExpression {
|
||||
let squiggleResult = run(x, bindings, {
|
||||
sampleCount: 1000,
|
||||
xyPointLength: 100,
|
||||
});
|
||||
// return squiggleResult.value
|
||||
if (squiggleResult.tag === "Ok") {
|
||||
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() {
|
||||
expect("be reached").toBe("codepath should never");
|
||||
}
|
||||
|
|
|
@ -18,7 +18,26 @@ let pointSetDist3: PointSetTypes.xyShape = {
|
|||
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("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", () => {
|
||||
makeTest("When identical", XYShape.logScorePoint(30, pointSetDist1, pointSetDist1), Some(0.0))
|
||||
makeTest(
|
||||
|
@ -32,16 +51,6 @@ describe("XYShapes", () => {
|
|||
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", () =>
|
||||
makeTest(
|
||||
"integrates correctly",
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
],
|
||||
"suffix": ".bs.js",
|
||||
"namespace": true,
|
||||
"bs-dependencies": ["@glennsl/rescript-jest", "rationale", "bisect_ppx"],
|
||||
"bs-dependencies": ["@glennsl/rescript-jest", "bisect_ppx"],
|
||||
"gentypeconfig": {
|
||||
"language": "typescript",
|
||||
"module": "commonjs",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "@quri/squiggle-lang",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7",
|
||||
"homepage": "https://squiggle-language.com",
|
||||
"licence": "MIT",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rescript build -with-deps",
|
||||
"build": "rescript build -with-deps && tsc",
|
||||
"bundle": "webpack",
|
||||
"start": "rescript build -w -with-deps",
|
||||
"clean": "rescript clean",
|
||||
"clean": "rescript clean && rm -r dist",
|
||||
"test:reducer": "jest __tests__/Reducer*/",
|
||||
"benchmark": "ts-node benchmark/conversion_tests.ts",
|
||||
"test": "jest",
|
||||
|
@ -31,34 +31,28 @@
|
|||
],
|
||||
"author": "Quantified Uncertainty Research Institute",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"rescript": "^9.1.4",
|
||||
"jstat": "^1.9.5",
|
||||
"pdfast": "^0.2.0",
|
||||
"mathjs": "10.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bisect_ppx": "^2.7.1",
|
||||
"jstat": "^1.9.5",
|
||||
"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",
|
||||
"@glennsl/rescript-jest": "^0.9.0",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"bisect_ppx": "^2.7.1",
|
||||
"chalk": "^4.1.2",
|
||||
"chalk": "^5.0.1",
|
||||
"codecov": "3.8.3",
|
||||
"fast-check": "2.25.0",
|
||||
"gentype": "^4.3.0",
|
||||
"jest": "^27.5.1",
|
||||
"jstat": "^1.9.5",
|
||||
"lodash": "4.17.21",
|
||||
"mathjs": "10.5.0",
|
||||
"moduleserve": "0.9.1",
|
||||
"nyc": "^15.1.0",
|
||||
"pdfast": "^0.2.0",
|
||||
"rationale": "0.2.0",
|
||||
"reanalyze": "^2.19.0",
|
||||
"rescript": "^9.1.4",
|
||||
"ts-jest": "^27.1.4",
|
||||
"ts-loader": "^9.2.8",
|
||||
"ts-node": "^10.7.0",
|
||||
|
@ -67,6 +61,6 @@
|
|||
"webpack-cli": "^4.9.2"
|
||||
},
|
||||
"source": "./src/js/index.ts",
|
||||
"main": "./dist/bundle.js",
|
||||
"types": "./dist/js/index.d.ts"
|
||||
"main": "./dist/src/js/index.js",
|
||||
"types": "./dist/src/js/index.d.ts"
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as _ from "lodash";
|
|||
import {
|
||||
genericDist,
|
||||
samplingParams,
|
||||
evaluate,
|
||||
evaluatePartialUsingExternalBindings,
|
||||
externalBindings,
|
||||
expressionValue,
|
||||
errorValue,
|
||||
distributionError,
|
||||
|
@ -11,6 +12,9 @@ import {
|
|||
discreteShape,
|
||||
distributionErrorToString,
|
||||
internalCode,
|
||||
mixedShape,
|
||||
sampleSetDist,
|
||||
symbolicDist,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
export {
|
||||
makeSampleSetDist,
|
||||
|
@ -44,7 +48,7 @@ import {
|
|||
Constructors_pointwiseLogarithm,
|
||||
Constructors_pointwisePower,
|
||||
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
||||
export type { samplingParams, errorValue };
|
||||
export type { samplingParams, errorValue, externalBindings as bindings };
|
||||
|
||||
export let defaultSamplingInputs: samplingParams = {
|
||||
sampleCount: 10000,
|
||||
|
@ -92,26 +96,67 @@ export type squiggleExpression =
|
|||
| tagged<"distribution", Distribution>
|
||||
| tagged<"number", number>
|
||||
| tagged<"record", { [key: string]: squiggleExpression }>;
|
||||
|
||||
export function run(
|
||||
squiggleString: string,
|
||||
bindings?: externalBindings,
|
||||
samplingInputs?: samplingParams
|
||||
): result<squiggleExpression, errorValue> {
|
||||
let b = bindings ? bindings : {};
|
||||
let si: samplingParams = samplingInputs
|
||||
? samplingInputs
|
||||
: defaultSamplingInputs;
|
||||
let result: result<expressionValue, errorValue> = evaluate(squiggleString);
|
||||
|
||||
let result: result<expressionValue, errorValue> =
|
||||
evaluateUsingExternalBindings(squiggleString, b);
|
||||
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(
|
||||
x: expressionValue,
|
||||
sampEnv: samplingParams
|
||||
): squiggleExpression {
|
||||
switch (x.tag) {
|
||||
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(
|
||||
"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":
|
||||
return tag("boolean", x.value);
|
||||
|
@ -124,10 +169,14 @@ function createTsExport(
|
|||
case "EvNumber":
|
||||
return tag("number", x.value);
|
||||
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",
|
||||
_.mapValues(x.value, (x) => createTsExport(x, sampEnv))
|
||||
_.mapValues(x.value, (x: unknown) =>
|
||||
convertRawToTypescript(x as rescriptExport, sampEnv)
|
||||
)
|
||||
);
|
||||
return result;
|
||||
case "EvString":
|
||||
return tag("string", x.value);
|
||||
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 {
|
||||
return r.value;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ type error =
|
|||
| RequestedStrategyInvalidError(string)
|
||||
| LogarithmOfDistributionError(string)
|
||||
| OtherError(string)
|
||||
| XYShapeError(XYShape.error)
|
||||
|
||||
@genType
|
||||
module Error = {
|
||||
|
@ -39,6 +40,7 @@ module Error = {
|
|||
| PointSetConversionError(err) => SampleSetDist.pointsetConversionErrorToString(err)
|
||||
| SparklineError(err) => PointSetTypes.sparklineErrorToString(err)
|
||||
| RequestedStrategyInvalidError(err) => `Requested strategy invalid: ${err}`
|
||||
| XYShapeError(err) => `XY Shape Error: ${XYShape.Error.toString(err)}`
|
||||
| OtherError(s) => s
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,24 @@ type toSampleSetFn = t => result<SampleSetDist.t, error>
|
|||
type scaleMultiplyFn = (t, float) => 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) =>
|
||||
switch t {
|
||||
| PointSet(r) => PointSetDist.sampleNRendered(n, r)
|
||||
|
@ -150,144 +168,147 @@ let truncate = Truncate.run
|
|||
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).
|
||||
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 = {
|
||||
let runConvolution = (
|
||||
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))
|
||||
}
|
||||
|
||||
/*
|
||||
module InputValidator = {
|
||||
/*
|
||||
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
|
||||
that both the probability mass and the probability density are greater than zero.
|
||||
Right now we don't yet have a way of getting probability mass, so I'll leave this for later.
|
||||
*/
|
||||
let getLogarithmInputError = (t1: t, t2: t, ~toPointSetFn: toPointSetFn): option<error> => {
|
||||
let firstOperandIsGreaterThanZero =
|
||||
toFloatOperation(
|
||||
t1,
|
||||
~toPointSetFn,
|
||||
~distToFloatOperation=#Cdf(MagicNumbers.Epsilon.ten),
|
||||
) |> E.R.fmap(r => r > 0.)
|
||||
let secondOperandIsGreaterThanZero =
|
||||
toFloatOperation(
|
||||
t2,
|
||||
~toPointSetFn,
|
||||
~distToFloatOperation=#Cdf(MagicNumbers.Epsilon.ten),
|
||||
) |> E.R.fmap(r => r > 0.)
|
||||
let items = E.A.R.firstErrorOrOpen([
|
||||
firstOperandIsGreaterThanZero,
|
||||
secondOperandIsGreaterThanZero,
|
||||
])
|
||||
switch items {
|
||||
| Error(r) => Some(r)
|
||||
| Ok([true, _]) =>
|
||||
Some(LogarithmOfDistributionError("First input must completely greater than 0"))
|
||||
| Ok([false, true]) =>
|
||||
Some(LogarithmOfDistributionError("Second input must completely greater than 0"))
|
||||
| Ok([false, false]) => None
|
||||
| Ok(_) => Some(Unreachable)
|
||||
let getLogarithmInputError = (t1: t, t2: t, ~toPointSetFn: toPointSetFn): option<error> => {
|
||||
let firstOperandIsGreaterThanZero =
|
||||
toFloatOperation(
|
||||
t1,
|
||||
~toPointSetFn,
|
||||
~distToFloatOperation=#Cdf(MagicNumbers.Epsilon.ten),
|
||||
) |> E.R.fmap(r => r > 0.)
|
||||
let secondOperandIsGreaterThanZero =
|
||||
toFloatOperation(
|
||||
t2,
|
||||
~toPointSetFn,
|
||||
~distToFloatOperation=#Cdf(MagicNumbers.Epsilon.ten),
|
||||
) |> E.R.fmap(r => r > 0.)
|
||||
let items = E.A.R.firstErrorOrOpen([
|
||||
firstOperandIsGreaterThanZero,
|
||||
secondOperandIsGreaterThanZero,
|
||||
])
|
||||
switch items {
|
||||
| Error(r) => Some(r)
|
||||
| Ok([true, _]) =>
|
||||
Some(LogarithmOfDistributionError("First input must be completely greater than 0"))
|
||||
| Ok([false, true]) =>
|
||||
Some(LogarithmOfDistributionError("Second input must be completely greater than 0"))
|
||||
| Ok([false, false]) => None
|
||||
| Ok(_) => Some(Unreachable)
|
||||
}
|
||||
}
|
||||
|
||||
let run = (t1: t, t2: t, ~toPointSetFn: toPointSetFn, ~arithmeticOperation): option<error> => {
|
||||
if arithmeticOperation == #Logarithm {
|
||||
getLogarithmInputError(t1, t2, ~toPointSetFn)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let getInvalidOperationError = (
|
||||
t1: t,
|
||||
t2: t,
|
||||
~toPointSetFn: toPointSetFn,
|
||||
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
|
||||
let expectedConvolutionCost: t => int = x =>
|
||||
switch x {
|
||||
| Symbolic(#Float(_)) => MagicNumbers.OpCost.floatCost
|
||||
| Symbolic(_) => MagicNumbers.OpCost.symbolicCost
|
||||
| PointSet(Discrete(m)) => m.xyShape->XYShape.T.length
|
||||
| PointSet(Mixed(_)) => MagicNumbers.OpCost.mixedCost
|
||||
| PointSet(Continuous(_)) => MagicNumbers.OpCost.continuousCost
|
||||
| _ => MagicNumbers.OpCost.wildcardCost
|
||||
}
|
||||
|
||||
let hasSampleSetDist = (t1: t, t2: t): bool => isSampleSetSet(t1) || isSampleSetSet(t2)
|
||||
|
||||
let convolutionIsFasterThanMonteCarlo = (t1: t, t2: t): bool =>
|
||||
expectedConvolutionCost(t1) * expectedConvolutionCost(t2) < MagicNumbers.OpCost.monteCarloCost
|
||||
|
||||
let preferConvolutionToMonteCarlo = (t1, t2, arithmeticOperation) => {
|
||||
!hasSampleSetDist(t1, t2) &&
|
||||
Operation.Convolution.canDoAlgebraicOperation(arithmeticOperation) &&
|
||||
convolutionIsFasterThanMonteCarlo(t1, t2)
|
||||
}
|
||||
|
||||
let run = (~t1: t, ~t2: t, ~arithmeticOperation): specificStrategy => {
|
||||
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||
| #AnalyticalSolution(_)
|
||||
| #Error(_) =>
|
||||
#AsSymbolic
|
||||
| #NoSolution =>
|
||||
preferConvolutionToMonteCarlo(t1, t2, arithmeticOperation) ? #AsConvolution : #AsMonteCarlo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let runStrategyOnValidatedInputs = (
|
||||
~t1: t,
|
||||
~t2: t,
|
||||
~arithmeticOperation,
|
||||
): option<error> => {
|
||||
if arithmeticOperation == #Logarithm {
|
||||
getLogarithmInputError(t1, t2, ~toPointSetFn)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
//I'm (Ozzie) really just guessing here, very little idea what's best
|
||||
let expectedConvolutionCost: t => int = x =>
|
||||
switch x {
|
||||
| Symbolic(#Float(_)) => MagicNumbers.OpCost.floatCost
|
||||
| Symbolic(_) => MagicNumbers.OpCost.symbolicCost
|
||||
| PointSet(Discrete(m)) => m.xyShape->XYShape.T.length
|
||||
| PointSet(Mixed(_)) => MagicNumbers.OpCost.mixedCost
|
||||
| PointSet(Continuous(_)) => MagicNumbers.OpCost.continuousCost
|
||||
| _ => MagicNumbers.OpCost.wildcardCost
|
||||
}
|
||||
|
||||
type calculationStrategy = MonteCarloStrat | ConvolutionStrat(Operation.convolutionOperation)
|
||||
|
||||
let chooseConvolutionOrMonteCarloDefault = (
|
||||
op: Operation.algebraicOperation,
|
||||
t2: t,
|
||||
t1: t,
|
||||
): calculationStrategy =>
|
||||
switch op {
|
||||
| #Divide
|
||||
| #Power
|
||||
| #Logarithm =>
|
||||
MonteCarloStrat
|
||||
| (#Add | #Subtract | #Multiply) as convOp =>
|
||||
expectedConvolutionCost(t1) * expectedConvolutionCost(t2) > MagicNumbers.OpCost.monteCarloCost
|
||||
? MonteCarloStrat
|
||||
: ConvolutionStrat(convOp)
|
||||
}
|
||||
|
||||
let tryAnalyticalSimplification = (
|
||||
arithmeticOperation: Operation.algebraicOperation,
|
||||
t1: t,
|
||||
t2: t,
|
||||
): option<SymbolicDistTypes.analyticalSimplificationResult> => {
|
||||
switch (t1, t2) {
|
||||
| (DistributionTypes.Symbolic(d1), DistributionTypes.Symbolic(d2)) =>
|
||||
Some(SymbolicDist.T.tryAnalyticalSimplification(d1, d2, arithmeticOperation))
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
||||
let runDefault = (
|
||||
t1: t,
|
||||
~strategy: StrategyChooser.specificStrategy,
|
||||
~toPointSetFn: toPointSetFn,
|
||||
~toSampleSetFn: toSampleSetFn,
|
||||
~arithmeticOperation,
|
||||
~t2: t,
|
||||
): result<t, error> => {
|
||||
switch tryAnalyticalSimplification(arithmeticOperation, t1, t2) {
|
||||
| Some(#AnalyticalSolution(symbolicDist)) => Ok(Symbolic(symbolicDist))
|
||||
| Some(#Error(e)) => Error(OperationError(e))
|
||||
| Some(#NoSolution)
|
||||
| None =>
|
||||
switch getInvalidOperationError(t1, t2, ~toPointSetFn, ~arithmeticOperation) {
|
||||
| Some(e) => Error(e)
|
||||
| None =>
|
||||
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,
|
||||
))
|
||||
}
|
||||
switch strategy {
|
||||
| #AsMonteCarlo =>
|
||||
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
||||
| #AsSymbolic =>
|
||||
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||
| #AnalyticalSolution(symbolicDist) => Ok(Symbolic(symbolicDist))
|
||||
| #Error(e) => Error(OperationError(e))
|
||||
| #NoSolution => Error(Unreachable)
|
||||
}
|
||||
| #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,
|
||||
~t2: t,
|
||||
): result<t, error> => {
|
||||
switch strategy {
|
||||
| AsDefault => runDefault(t1, ~toPointSetFn, ~toSampleSetFn, ~arithmeticOperation, ~t2)
|
||||
| AsSymbolic =>
|
||||
switch tryAnalyticalSimplification(arithmeticOperation, t1, t2) {
|
||||
| Some(#AnalyticalSolution(symbolicDist)) => Ok(Symbolic(symbolicDist))
|
||||
| Some(#NoSolution) => Error(RequestedStrategyInvalidError(`No analytical solution`))
|
||||
| None => Error(RequestedStrategyInvalidError("Inputs were not even symbolic"))
|
||||
| Some(#Error(err)) => Error(OperationError(err))
|
||||
let invalidOperationError = InputValidator.run(t1, t2, ~arithmeticOperation, ~toPointSetFn)
|
||||
switch (invalidOperationError, strategy) {
|
||||
| (Some(e), _) => Error(e)
|
||||
| (None, AsDefault) => {
|
||||
let chooseStrategy = StrategyChooser.run(~arithmeticOperation, ~t1, ~t2)
|
||||
runStrategyOnValidatedInputs(
|
||||
~t1,
|
||||
~t2,
|
||||
~strategy=chooseStrategy,
|
||||
~arithmeticOperation,
|
||||
~toPointSetFn,
|
||||
~toSampleSetFn,
|
||||
)
|
||||
}
|
||||
| AsConvolution => {
|
||||
let errString = opString => `Can't convolve on ${opString}`
|
||||
switch arithmeticOperation {
|
||||
| (#Add | #Subtract | #Multiply) as convOp =>
|
||||
runConvolution(toPointSetFn, convOp, t1, t2)->E.R2.fmap(r => DistributionTypes.PointSet(
|
||||
r,
|
||||
))
|
||||
| (#Divide | #Power | #Logarithm) as op =>
|
||||
op->Operation.Algebraic.toString->errString->RequestedStrategyInvalidError->Error
|
||||
| (None, AsMonteCarlo) =>
|
||||
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
|
||||
| (None, AsSymbolic) =>
|
||||
switch StrategyCallOnValidatedInputs.symbolic(arithmeticOperation, t1, t2) {
|
||||
| #AnalyticalSolution(symbolicDist) => Ok(Symbolic(symbolicDist))
|
||||
| #NoSolution => Error(RequestedStrategyInvalidError(`No analytic solution for inputs`))
|
||||
| #Error(err) => Error(OperationError(err))
|
||||
}
|
||||
| (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,
|
||||
~pointwiseAddFn: pointwiseAddFn,
|
||||
) => 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 = {
|
||||
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 xyPointRange = E.A.Sorted.range(samples) |> E.O.default(0.0)
|
||||
let xyPointWidth = xyPointRange /. float_of_int(outputXYPoints)
|
||||
|
@ -85,7 +63,11 @@ let toPointSetDist = (
|
|||
(),
|
||||
): Internals.Types.outputs => {
|
||||
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 discrete: PointSetTypes.discreteShape =
|
||||
discretePart
|
||||
|
|
|
@ -22,3 +22,16 @@ module OpCost = {
|
|||
let wildcardCost = 1000
|
||||
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
|
||||
let evaluate = Expression.evaluate
|
||||
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
||||
let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings
|
||||
let parse = Expression.parse
|
||||
let parseOuter = Expression.parseOuter
|
||||
let parsePartial = Expression.parsePartial
|
||||
|
|
|
@ -18,12 +18,15 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
|||
let evaluateUsingOptions: (
|
||||
~environment: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.environment>,
|
||||
~externalBindings: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings>,
|
||||
~isPartial: option<bool>,
|
||||
string,
|
||||
) => result<expressionValue, errorValue>
|
||||
@genType
|
||||
let evaluatePartialUsingExternalBindings: (
|
||||
string,
|
||||
QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings,
|
||||
QuriSquiggleLang.ReducerInterface_ExpressionValue.environment,
|
||||
) => result<externalBindings, errorValue>
|
||||
@genType
|
||||
let evaluate: string => result<expressionValue, 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 MathJs = Reducer_MathJs
|
||||
module Bindings = Reducer_Expression_Bindings
|
||||
open ReducerInterface.ExpressionValue
|
||||
open Reducer_ErrorValue
|
||||
|
||||
|
@ -20,12 +21,12 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> =>
|
|||
}
|
||||
|
||||
let constructRecord = arrayOfPairs => {
|
||||
Belt.Array.map(arrayOfPairs, pairValue => {
|
||||
Belt.Array.map(arrayOfPairs, pairValue =>
|
||||
switch pairValue {
|
||||
| EvArray([EvString(key), valueValue]) => (key, valueValue)
|
||||
| _ => ("wrong key type", pairValue->toStringWithType->EvString)
|
||||
}
|
||||
})
|
||||
)
|
||||
->Js.Dict.fromArray
|
||||
->EvRecord
|
||||
->Ok
|
||||
|
@ -68,6 +69,20 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> =>
|
|||
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 {
|
||||
| ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(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]) => inspect(value)
|
||||
| ("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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,179 +3,137 @@
|
|||
they take expressions as parameters and return a new expression.
|
||||
Macros are used to define language building blocks. They are like Lisp macros.
|
||||
*/
|
||||
module Bindings = Reducer_Expression_Bindings
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module Result = Belt.Result
|
||||
|
||||
open Reducer_ErrorValue
|
||||
open Reducer_Expression_ExpressionBuilder
|
||||
|
||||
type expression = ExpressionT.expression
|
||||
type environment = ExpressionValue.environment
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
||||
let dispatchMacroCall = (
|
||||
list: list<expression>,
|
||||
macroExpression: expression,
|
||||
bindings: ExpressionT.bindings,
|
||||
environment,
|
||||
reduceExpression: reducerFn,
|
||||
): result<expression, 'e> => {
|
||||
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
|
||||
reduceExpression: ExpressionT.reducerFn,
|
||||
): result<expression, errorValue> => {
|
||||
let doBindStatement = (bindingExpr: expression, statement: expression, environment) =>
|
||||
switch statement {
|
||||
| ExpressionT.EList(list{
|
||||
ExpressionT.EValue(EvCall("$let")),
|
||||
ExpressionT.EValue(EvSymbol(aSymbol)),
|
||||
expressionToReduce,
|
||||
}) => {
|
||||
let rNewExpressionToReduce = replaceSymbols(expressionToReduce, bindings)
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||
|
||||
let rNewValue =
|
||||
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
||||
reduceExpression(newExpressionToReduce, bindings, environment)
|
||||
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
let doBindExpression = (bindingExpr: expression, statement: expression, environment) =>
|
||||
switch statement {
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||
let rExternalBindingsValue = reduceExpression(
|
||||
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 rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||
rNewStatement
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _environment): result<
|
||||
expression,
|
||||
errorValue,
|
||||
> => {
|
||||
let exprsArray = Belt.List.toArray(exprs)
|
||||
let maxIndex = Js.Array2.length(exprsArray) - 1
|
||||
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
|
||||
}
|
||||
|
||||
let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
|
||||
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
|
||||
let reducedBindings = bindings->Belt.Map.String.keep((_key, value) =>
|
||||
switch value {
|
||||
| ExpressionT.EValue(_) => true
|
||||
| _ => false
|
||||
}
|
||||
)
|
||||
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 doLambdaDefinition = (
|
||||
bindings: ExpressionT.bindings,
|
||||
parameters: array<string>,
|
||||
lambdaDefinition: ExpressionT.expression,
|
||||
) => eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition)->Ok
|
||||
|
||||
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) =>
|
||||
switch expression {
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) =>
|
||||
REExpressionExpected->Error
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$exportVariablesExpression"))}) =>
|
||||
doExportVariableExpression(bindings)
|
||||
| _ => replaceSymbols(expression, bindings)
|
||||
let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment) =>
|
||||
switch aList {
|
||||
| list{
|
||||
ExpressionT.EValue(EvCall("$$bindStatement")),
|
||||
bindingExpr: ExpressionT.expression,
|
||||
statement,
|
||||
} =>
|
||||
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{
|
||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||
bindingExpr: ExpressionT.expression,
|
||||
expression,
|
||||
} =>
|
||||
doBindExpression(bindingExpr, expression, environment)
|
||||
| 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 list {
|
||||
| list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok
|
||||
|
||||
| list{
|
||||
ExpressionT.EValue(EvCall("$$bindStatement")),
|
||||
ExpressionT.EBindings(bindings),
|
||||
statement,
|
||||
} =>
|
||||
doBindStatement(statement, bindings)
|
||||
| list{
|
||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||
ExpressionT.EBindings(bindings),
|
||||
expression,
|
||||
} =>
|
||||
doBindExpression(expression, bindings)
|
||||
| _ => list->ExpressionT.EList->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 ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module Extra = Reducer_Extra
|
||||
module Lambda = Reducer_Expression_Lambda
|
||||
module Macro = Reducer_Expression_Macro
|
||||
module MathJs = Reducer_MathJs
|
||||
module Result = Belt.Result
|
||||
module T = Reducer_Expression_T
|
||||
|
||||
open Reducer_ErrorValue
|
||||
|
||||
type environment = ReducerInterface_ExpressionValue.environment
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
type expression = T.expression
|
||||
|
@ -16,30 +17,6 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
|||
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||
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
|
||||
*/
|
||||
|
@ -49,159 +26,70 @@ let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
|
|||
let parse = (mathJsCode: string): result<t, errorValue> =>
|
||||
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)
|
||||
*/
|
||||
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
||||
expressionValue,
|
||||
'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)
|
||||
> =>
|
||||
switch expression {
|
||||
| T.EValue(value) => value->Ok
|
||||
| T.EList(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)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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 {
|
||||
| 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.EList(list) => {
|
||||
let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
|
||||
racc,
|
||||
each: expression,
|
||||
) =>
|
||||
racc->Result.flatMap(acc => {
|
||||
each
|
||||
->reduceExpandedExpression(environment)
|
||||
->Result.flatMap(newNode => {
|
||||
acc->Belt.List.add(newNode)->Ok
|
||||
})
|
||||
})
|
||||
)
|
||||
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)
|
||||
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,
|
||||
each: expression,
|
||||
) =>
|
||||
racc->Result.flatMap(acc => {
|
||||
each
|
||||
->reduceExpression(bindings, environment)
|
||||
->Result.map(newNode => {
|
||||
acc->Belt.List.add(newNode)
|
||||
})
|
||||
})
|
||||
)
|
||||
racc->Result.flatMap(acc => acc->reduceValueList(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,
|
||||
'e,
|
||||
> => 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 = (
|
||||
~environment: option<ReducerInterface_ExpressionValue.environment>,
|
||||
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
|
||||
~isPartial: option<bool>,
|
||||
code: string,
|
||||
): result<expressionValue, errorValue> => {
|
||||
let anEnvironment = switch environment {
|
||||
|
@ -214,24 +102,27 @@ let evaluateUsingOptions = (
|
|||
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
|
||||
}
|
||||
|
||||
let anIsPartial = switch isPartial {
|
||||
| Some(isPartial) => isPartial
|
||||
| None => false
|
||||
}
|
||||
let bindings = anExternalBindings->Bindings.fromExternalBindings
|
||||
|
||||
let bindings = anExternalBindings->externalBindingsToBindings
|
||||
|
||||
if anIsPartial {
|
||||
evalPartial_(code, bindings, anEnvironment)
|
||||
} else {
|
||||
evalOuter_(code, bindings, anEnvironment)
|
||||
}
|
||||
parse(code)->Result.flatMap(expr => evalUsingBindingsExpression_(expr, bindings, anEnvironment))
|
||||
}
|
||||
|
||||
/*
|
||||
Evaluates MathJs code and bindings via Reducer and answers the result
|
||||
*/
|
||||
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 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.
|
||||
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.
|
||||
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 =
|
||||
| EList(list<expression>) // A list to map-reduce
|
||||
| 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
|
||||
| EParameters(array<string>) // for $defun; for internal use only
|
||||
and bindings = Belt.Map.String.t<expression>
|
||||
and bindings = Belt.Map.String.t<expressionValue>
|
||||
|
||||
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
|
||||
*/
|
||||
let jsToEv = (jsValue): result<expressionValue, errorValue> => {
|
||||
let jsToEv = (jsValue): result<expressionValue, errorValue> =>
|
||||
switch Js.typeof(jsValue) {
|
||||
| "boolean" => jsValue->castBool->EvBool->Ok
|
||||
| "number" => jsValue->castNumber->EvNumber->Ok
|
||||
| "string" => jsValue->castString->EvString->Ok
|
||||
| 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 ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module JavaScript = Reducer_Js
|
||||
module Parse = Reducer_MathJs_Parse
|
||||
module Result = Belt.Result
|
||||
|
||||
type errorValue = ErrorValue.errorValue
|
||||
type expression = ExpressionT.expression
|
||||
type expressionValue = ExpressionValue.expressionValue
|
||||
type errorValue = ErrorValue.errorValue
|
||||
|
||||
type blockTag =
|
||||
| ImportVariablesStatement
|
||||
| ExportVariablesExpression
|
||||
type tagOrNode =
|
||||
| BlockTag(blockTag)
|
||||
| BlockNode(Parse.node)
|
||||
let blockToNode = block => block["node"]
|
||||
|
||||
let toTagOrNode = block => BlockNode(block["node"])
|
||||
|
||||
let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||
let rec fromInnerNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
||||
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
|
||||
Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) =>
|
||||
racc->Result.flatMap(acc =>
|
||||
fromNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||
fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||
)
|
||||
)
|
||||
|
||||
let caseFunctionNode = fNode => {
|
||||
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
||||
rLispArgs->Result.flatMap(lispArgs =>
|
||||
Builder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok
|
||||
rLispArgs->Result.map(lispArgs =>
|
||||
ExpressionBuilder.eFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -42,18 +39,15 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
(key: string, value: Parse.node),
|
||||
) =>
|
||||
racc->Result.flatMap(acc =>
|
||||
fromNode(value)->Result.map(valueExpression => {
|
||||
fromInnerNode(value)->Result.map(valueExpression => {
|
||||
let entryCode =
|
||||
list{
|
||||
key->ExpressionValue.EvString->ExpressionT.EValue,
|
||||
valueExpression,
|
||||
}->ExpressionT.EList
|
||||
list{ExpressionBuilder.eString(key), valueExpression}->ExpressionT.EList
|
||||
list{entryCode, ...acc}
|
||||
})
|
||||
)
|
||||
)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -66,7 +60,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
Ok(list{}),
|
||||
(racc, currentPropertyMathJsNode) =>
|
||||
racc->Result.flatMap(acc =>
|
||||
fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
||||
fromInnerNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
||||
propertyCode,
|
||||
...acc,
|
||||
})
|
||||
|
@ -77,28 +71,41 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
|
||||
let caseAccessorNode = (objectNode, indexNode) => {
|
||||
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
||||
fromNode(objectNode)->Result.flatMap(objectCode =>
|
||||
Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok
|
||||
fromInnerNode(objectNode)->Result.flatMap(objectCode =>
|
||||
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 symbol = aNode["object"]["name"]->Builder.toEvSymbolValue
|
||||
let rValueExpression = fromNode(aNode["value"])
|
||||
rValueExpression->Result.flatMap(valueExpression =>
|
||||
Builder.passToFunction("$let", list{symbol, valueExpression})->Ok
|
||||
let symbolName = aNode["object"]["name"]
|
||||
let rValueExpression = fromInnerNode(aNode["value"])
|
||||
rValueExpression->Result.map(valueExpression =>
|
||||
ExpressionBuilder.eLetStatement(symbolName, valueExpression)
|
||||
)
|
||||
}
|
||||
|
||||
let caseFunctionAssignmentNode = faNode => {
|
||||
let symbol = faNode["name"]->Builder.toEvSymbolValue
|
||||
let rValueExpression = fromNode(faNode["expr"])
|
||||
let symbol = faNode["name"]->ExpressionBuilder.eSymbol
|
||||
let rValueExpression = fromInnerNode(faNode["expr"])
|
||||
|
||||
rValueExpression->Result.flatMap(valueExpression => {
|
||||
let lispParams = faNode["params"]->ExpressionT.EParameters
|
||||
let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression})
|
||||
Builder.passToFunction("$let", list{symbol, lambda})->Ok
|
||||
let lispParams = ExpressionBuilder.eArrayString(faNode["params"])
|
||||
let valueBlock = ExpressionBuilder.eBlock(list{valueExpression})
|
||||
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)
|
||||
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
||||
| MjSymbolNode(sNode) => {
|
||||
let expr: expression = Builder.toEvSymbolValue(sNode["name"])
|
||||
let expr: expression = ExpressionBuilder.eSymbol(sNode["name"])
|
||||
let rExpr: result<expression, errorValue> = expr->Ok
|
||||
rExpr
|
||||
}
|
||||
| MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes
|
||||
| MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock
|
||||
| MjConstantNode(cNode) =>
|
||||
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
|
||||
| MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode)
|
||||
|
@ -123,78 +130,10 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
| MjIndexNode(iNode) => caseIndexNode(iNode)
|
||||
| MjObjectNode(oNode) => caseObjectNode(oNode)
|
||||
| MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
|
||||
| MjParenthesisNode(pNode) => pNode["content"]->fromNode
|
||||
| MjParenthesisNode(pNode) => pNode["content"]->fromInnerNode
|
||||
}
|
||||
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 {
|
||||
"$$bindExpression"
|
||||
} 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
|
||||
})
|
||||
}
|
||||
let fromNode = (node: Parse.node): result<expression, errorValue> =>
|
||||
fromInnerNode(node)->Result.map(expr => ExpressionBuilder.eBlock(list{expr}))
|
||||
|
|
|
@ -11,17 +11,19 @@ type internalCode = Object
|
|||
@genType
|
||||
type rec expressionValue =
|
||||
| EvArray(array<expressionValue>)
|
||||
| EvArrayString(array<string>)
|
||||
| EvBool(bool)
|
||||
| EvCall(string) // External function call
|
||||
| EvDistribution(DistributionTypes.genericDist)
|
||||
| EvLambda((array<string>, internalCode))
|
||||
| EvLambda((array<string>, record, internalCode))
|
||||
| EvNumber(float)
|
||||
| EvRecord(Js.Dict.t<expressionValue>)
|
||||
| EvRecord(record)
|
||||
| EvString(string)
|
||||
| EvSymbol(string)
|
||||
and record = Js.Dict.t<expressionValue>
|
||||
|
||||
@genType
|
||||
type externalBindings = Js.Dict.t<expressionValue>
|
||||
type externalBindings = record
|
||||
@genType
|
||||
let defaultExternalBindings: externalBindings = Js.Dict.empty()
|
||||
|
||||
|
@ -29,20 +31,21 @@ type functionCall = (string, array<expressionValue>)
|
|||
|
||||
let rec toString = 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)
|
||||
| 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)
|
||||
| EvString(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
|
||||
| EvDistribution(dist) => GenericDist.toString(dist)
|
||||
}
|
||||
|
@ -50,19 +53,19 @@ and toStringRecord = aRecord => {
|
|||
let pairs =
|
||||
aRecord
|
||||
->Js.Dict.entries
|
||||
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
||||
->Extra_Array.interperse(", ")
|
||||
->Js.String.concatMany("")
|
||||
->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
||||
->Js.Array2.toString
|
||||
`{${pairs}}`
|
||||
}
|
||||
|
||||
let toStringWithType = aValue =>
|
||||
switch aValue {
|
||||
| EvArray(_) => `Array::${toString(aValue)}`
|
||||
| EvArrayString(_) => `ArrayString::${toString(aValue)}`
|
||||
| EvBool(_) => `Bool::${toString(aValue)}`
|
||||
| EvCall(_) => `Call::${toString(aValue)}`
|
||||
| EvDistribution(_) => `Distribution::${toString(aValue)}`
|
||||
| EvLambda((_parameters, _internalCode)) => `Lambda::${toString(aValue)}`
|
||||
| EvLambda((_parameters, _context, _internalCode)) => `Lambda::${toString(aValue)}`
|
||||
| EvNumber(_) => `Number::${toString(aValue)}`
|
||||
| EvRecord(_) => `Record::${toString(aValue)}`
|
||||
| EvString(_) => `String::${toString(aValue)}`
|
||||
|
@ -70,7 +73,7 @@ let toStringWithType = aValue =>
|
|||
}
|
||||
|
||||
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)})`
|
||||
|
|
|
@ -28,14 +28,14 @@ module Helpers = {
|
|||
let catchAndConvertTwoArgsToDists = (args: array<expressionValue>): option<(
|
||||
DistributionTypes.genericDist,
|
||||
DistributionTypes.genericDist,
|
||||
)> => {
|
||||
)> =>
|
||||
switch args {
|
||||
| [EvDistribution(a), EvDistribution(b)] => Some((a, b))
|
||||
| [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b))
|
||||
| [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b)))
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let toFloatFn = (
|
||||
fnCall: DistributionTypes.DistributionOperation.toFloat,
|
||||
|
@ -119,7 +119,7 @@ module Helpers = {
|
|||
mixtureWithGivenWeights(distributions, weights)
|
||||
}
|
||||
|
||||
let mixture = (args: array<expressionValue>): DistributionOperation.outputType => {
|
||||
let mixture = (args: array<expressionValue>): DistributionOperation.outputType =>
|
||||
switch E.A.last(args) {
|
||||
| Some(EvArray(b)) => {
|
||||
let weights = parseNumberArray(b)
|
||||
|
@ -138,7 +138,7 @@ module Helpers = {
|
|||
}
|
||||
| _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module SymbolicConstructors = {
|
||||
|
|
|
@ -13,6 +13,12 @@ type samplingParams = DistributionOperation.env
|
|||
@genType
|
||||
type genericDist = DistributionTypes.genericDist
|
||||
|
||||
@genType
|
||||
type sampleSetDist = SampleSetDist.t
|
||||
|
||||
@genType
|
||||
type symbolicDist = SymbolicDistTypes.symbolicDist
|
||||
|
||||
@genType
|
||||
type distributionError = DistributionTypes.error
|
||||
|
||||
|
@ -34,6 +40,12 @@ let evaluate = Reducer.evaluate
|
|||
@genType
|
||||
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
||||
|
||||
@genType
|
||||
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
||||
|
||||
@genType
|
||||
type externalBindings = Reducer.externalBindings
|
||||
|
||||
@genType
|
||||
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 Id = Belt.Id.MakeComparable({
|
||||
type t = float
|
||||
|
@ -8,7 +11,7 @@ module FloatFloatMap = {
|
|||
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
||||
|
||||
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 increment = (el, t: t) =>
|
||||
Belt.MutableMap.update(t, el, x =>
|
||||
|
@ -20,6 +23,10 @@ module FloatFloatMap = {
|
|||
|
||||
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
||||
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 = {
|
||||
|
@ -51,17 +58,59 @@ module O = {
|
|||
| None => rFn()
|
||||
}
|
||||
()
|
||||
let fmap = Rationale.Option.fmap
|
||||
let bind = Rationale.Option.bind
|
||||
let default = Rationale.Option.default
|
||||
let isSome = Rationale.Option.isSome
|
||||
let isNone = Rationale.Option.isNone
|
||||
let toExn = Rationale.Option.toExn
|
||||
let some = Rationale.Option.some
|
||||
let firstSome = Rationale.Option.firstSome
|
||||
let toExt = Rationale.Option.toExn // wanna flag this-- looks like a typo but `Rationale.OptiontoExt` doesn't exist.
|
||||
let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten
|
||||
let flatten = Rationale.Option.flatten
|
||||
let fmap = (f: 'a => 'b, x: option<'a>): option<'b> => {
|
||||
switch x {
|
||||
| None => None
|
||||
| Some(x') => Some(f(x'))
|
||||
}
|
||||
}
|
||||
let bind = (o, f) =>
|
||||
switch o {
|
||||
| None => None
|
||||
| Some(a) => f(a)
|
||||
}
|
||||
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 =>
|
||||
switch opt {
|
||||
|
@ -109,6 +158,11 @@ module O2 = {
|
|||
|
||||
/* Functions */
|
||||
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 flatten2Callbacks = (fn1, fn2, fnlast) =>
|
||||
|
@ -156,10 +210,31 @@ exception Assertion(string)
|
|||
|
||||
/* R for Result */
|
||||
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 fmap = Rationale.Result.fmap
|
||||
let bind = Rationale.Result.bind
|
||||
let isOk = Belt.Result.isOk
|
||||
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 =>
|
||||
switch x {
|
||||
| Ok(r) => r
|
||||
|
@ -186,14 +261,17 @@ module R = {
|
|||
let errorIfCondition = (errorCondition, errorMessage, 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) =>
|
||||
switch r {
|
||||
| Ok(f) => fmap(f, a)
|
||||
| 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) => {
|
||||
ap'(fmap(op, xR), yR)
|
||||
}
|
||||
|
@ -243,7 +321,7 @@ module S = {
|
|||
}
|
||||
|
||||
module J = {
|
||||
let toString = \"||>"(Js.Json.decodeString, O.default(""))
|
||||
let toString = F.pipe(Js.Json.decodeString, O.default(""))
|
||||
let fromString = Js.Json.string
|
||||
let fromNumber = Js.Json.number
|
||||
|
||||
|
@ -256,7 +334,7 @@ module J = {
|
|||
|
||||
let toString = (str: option<'a>) =>
|
||||
switch str {
|
||||
| Some(str) => Some(str |> \"||>"(Js.Json.decodeString, O.default("")))
|
||||
| Some(str) => Some(str |> F.pipe(Js.Json.decodeString, O.default("")))
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
@ -271,34 +349,132 @@ module JsDate = {
|
|||
|
||||
/* List */
|
||||
module L = {
|
||||
module Util = {
|
||||
let eq = (a, b) => a == b
|
||||
}
|
||||
let fmap = List.map
|
||||
let get = Belt.List.get
|
||||
let toArray = Array.of_list
|
||||
let fmapi = List.mapi
|
||||
let concat = List.concat
|
||||
let drop = Rationale.RList.drop
|
||||
let remove = Rationale.RList.remove
|
||||
let concat' = (xs, ys) => List.append(ys, xs)
|
||||
|
||||
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 filter = List.filter
|
||||
let for_all = List.for_all
|
||||
let exists = List.exists
|
||||
let sort = List.sort
|
||||
let length = List.length
|
||||
let filter_opt = Rationale.RList.filter_opt
|
||||
let uniqBy = Rationale.RList.uniqBy
|
||||
let join = Rationale.RList.join
|
||||
let head = Rationale.RList.head
|
||||
let uniq = Rationale.RList.uniq
|
||||
|
||||
let filter_opt = xs => {
|
||||
let rec loop = (l, acc) =>
|
||||
switch l {
|
||||
| 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 last = Rationale.RList.last
|
||||
let last = xs => xs |> List.rev |> head
|
||||
let append = List.append
|
||||
let getBy = Belt.List.getBy
|
||||
let dropLast = Rationale.RList.dropLast
|
||||
let contains = Rationale.RList.contains
|
||||
let without = Rationale.RList.without
|
||||
let update = Rationale.RList.update
|
||||
let dropLast = (i, xs) => take(List.length(xs) - i, xs)
|
||||
let containsWith = f => List.exists(f)
|
||||
let contains = x => containsWith(Util.eq(x))
|
||||
|
||||
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 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 tailSafe = Belt.List.tail
|
||||
let headExn = Belt.List.headExn
|
||||
|
@ -360,7 +536,7 @@ module A = {
|
|||
Belt.Array.getUnsafe(a, index),
|
||||
Belt.Array.getUnsafe(a, index + 1),
|
||||
))
|
||||
|> Rationale.Result.return
|
||||
|> (x => Ok(x))
|
||||
}
|
||||
|
||||
let tail = Belt.Array.sliceToEnd(_, 1)
|
||||
|
@ -424,8 +600,8 @@ module A = {
|
|||
module O = {
|
||||
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
||||
optionals
|
||||
|> Js.Array.filter(Rationale.Option.isSome)
|
||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
||||
|> Js.Array.filter(O.isSome)
|
||||
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
||||
switch 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 = {
|
||||
type t = array<float>
|
||||
let mean = Jstat.mean
|
||||
let geomean = Jstat.geomean
|
||||
let mode = Jstat.mode
|
||||
|
@ -553,14 +661,31 @@ module A = {
|
|||
let sum = Jstat.sum
|
||||
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.
|
||||
//https://jstat.github.io/all.html
|
||||
let percentile = (a, b) => Jstat.percentile(a, b, false)
|
||||
|
||||
// Gives an array with all the differences between values
|
||||
// diff([1,5,3,7]) = [4,-2,4]
|
||||
let diff = (arr: array<float>): array<float> =>
|
||||
Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left)
|
||||
let diff = (t: t): array<float> =>
|
||||
Belt.Array.zipBy(t, Belt.Array.sliceToEnd(t, 1), (left, right) => right -. left)
|
||||
|
||||
exception RangeError(string)
|
||||
let range = (min: float, max: float, n: int): array<float> =>
|
||||
|
@ -578,18 +703,104 @@ module A = {
|
|||
|
||||
let min = Js.Math.minMany_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 = {
|
||||
let fmap = (a, b) => A.fmap(b, a)
|
||||
let joinWith = (a, b) => A.joinWith(b, a)
|
||||
let filter = (a, b) => A.filter(b, a)
|
||||
}
|
||||
|
||||
module JsArray = {
|
||||
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
||||
optionals
|
||||
|> Js.Array.filter(Rationale.Option.isSome)
|
||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
||||
|> Js.Array.filter(O.isSome)
|
||||
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||
let filter = Js.Array.filter
|
||||
}
|
||||
|
|
|
@ -29,6 +29,18 @@ type distToFloatOperation = [
|
|||
|
||||
module Convolution = {
|
||||
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 =>
|
||||
switch x {
|
||||
| #Add => \"+."
|
||||
|
|
|
@ -4,6 +4,42 @@ type xyShape = {
|
|||
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
|
||||
type interpolationStrategy = [
|
||||
| #Stepwise
|
||||
|
@ -60,6 +96,44 @@ module T = {
|
|||
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 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 = {
|
||||
|
|
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
|
||||
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.
|
||||
|
||||
_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
|
||||
title: Language Basics
|
||||
---
|
||||
|
||||
import { SquiggleEditor } from "../../src/components/SquiggleEditor";
|
||||
|
||||
# Squiggle Language
|
||||
## Expressions
|
||||
|
||||
The squiggle language has a very simple syntax. The best way to get to understand
|
||||
it is by simply looking at examples.
|
||||
A distribution
|
||||
|
||||
## 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
|
||||
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
|
||||
(the lone `value_of_work` line). Variables can be used later in a squiggle program
|
||||
and even in other notebooks!
|
||||
### Functions
|
||||
|
||||
An export is rendered to the output view so you can see your result.
|
||||
|
||||
the exports can be expressions, such as:
|
||||
|
||||
<SquiggleEditor initialSquiggleString="normal(0,1)" />
|
||||
|
||||
## Functions
|
||||
|
||||
Squiggle supports functions, including the rendering of functions:
|
||||
We can define functions
|
||||
|
||||
<SquiggleEditor
|
||||
initialSquiggleString={`ozzie_estimate(t) = lognormal({mean: 3 + (t+.1)^2.5, stdev: 8})
|
||||
ozzie_estimate
|
||||
`}
|
||||
initialSquiggleString={`ozzie_estimate(t) = lognormal(1, t ^ 1.01)
|
||||
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
|
||||
title: Node Packages
|
||||
---
|
||||
|
||||
# Javascript Libraries
|
||||
|
||||
There are two JavaScript packages currently available for Squiggle:
|
||||
|
||||
- [`@quri/squiggle-lang`](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||
- [`@quri/squiggle-components`](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||
- [`@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) ![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)
|
||||
|
||||
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
|
||||
in the previous environment will be made available.
|
||||
|
||||
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
|
||||
The return type of `run` is a bit complicated, and comes from auto generated `js`
|
||||
code that comes from rescript. We highly recommend using typescript when using
|
||||
this library to help navigate the return type.
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -19,10 +22,7 @@ module Normal = {
|
|||
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$.
|
||||
|
@ -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.
|
||||
|
||||
## For lognormals
|
||||
|
||||
TODO
|
|
@ -1,10 +1,16 @@
|
|||
---
|
||||
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
|
||||
cases in forecasting and writing better evaluations.
|
||||
## Get started
|
||||
|
||||
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 |