squiggle/packages/squiggle-lang/src/js/index.ts

341 lines
8.8 KiB
TypeScript
Raw Normal View History

import * as _ from "lodash";
import type {
exportEnv,
exportDistribution,
} from "../rescript/ProgramEvaluator.gen";
export type { exportEnv, exportDistribution };
import {
genericDist,
samplingParams,
evaluate,
expressionValue,
errorValue,
distributionError,
toPointSet,
continuousShape,
discreteShape,
distributionErrorToString,
} from "../rescript/TypescriptInterface.gen";
export {
makeSampleSetDist,
errorValueToString,
distributionErrorToString,
} from "../rescript/TypescriptInterface.gen";
2022-04-08 19:55:04 +00:00
import {
Constructors_mean,
Constructors_sample,
Constructors_pdf,
Constructors_cdf,
Constructors_inv,
Constructors_normalize,
Constructors_toPointSet,
Constructors_toSampleSet,
Constructors_truncate,
Constructors_inspect,
Constructors_toString,
Constructors_toSparkline,
Constructors_algebraicAdd,
Constructors_algebraicMultiply,
Constructors_algebraicDivide,
Constructors_algebraicSubtract,
Constructors_algebraicLogarithm,
2022-04-09 16:37:26 +00:00
Constructors_algebraicPower,
Constructors_pointwiseAdd,
Constructors_pointwiseMultiply,
Constructors_pointwiseDivide,
Constructors_pointwiseSubtract,
Constructors_pointwiseLogarithm,
2022-04-09 16:37:26 +00:00
Constructors_pointwisePower,
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
export type { samplingParams, errorValue };
2022-04-11 03:16:31 +00:00
export let defaultSamplingInputs: samplingParams = {
sampleCount: 10000,
xyPointLength: 10000,
};
2022-04-11 06:16:29 +00:00
export type result<a, b> =
| {
tag: "Ok";
2022-04-11 00:48:45 +00:00
value: a;
}
| {
tag: "Error";
2022-04-11 00:48:45 +00:00
value: b;
2022-04-09 02:55:06 +00:00
};
2022-04-11 00:51:43 +00:00
export function resultMap<a, b, c>(
r: result<a, c>,
mapFn: (x: a) => b
): result<b, c> {
if (r.tag === "Ok") {
return { tag: "Ok", value: mapFn(r.value) };
} else {
return r;
}
}
function Ok<a, b>(x: a): result<a, b> {
return { tag: "Ok", value: x };
2022-04-11 06:16:29 +00:00
}
type tagged<a, b> = { tag: a; value: b };
2022-04-11 03:16:31 +00:00
function tag<a, b>(x: a, y: b): tagged<a, b> {
return { tag: x, value: y };
2022-04-11 03:16:31 +00:00
}
export type squiggleExpression =
| tagged<"symbol", string>
| tagged<"string", string>
| tagged<"array", squiggleExpression[]>
| tagged<"boolean", boolean>
| tagged<"distribution", Distribution>
| tagged<"number", number>
| tagged<"record", { [key: string]: squiggleExpression }>;
2022-04-11 03:16:31 +00:00
export function run(
squiggleString: string,
samplingInputs?: samplingParams,
_environment?: exportEnv
): result<squiggleExpression, errorValue> {
let si: samplingParams = samplingInputs
? samplingInputs
: defaultSamplingInputs;
let result: result<expressionValue, errorValue> = evaluate(squiggleString);
return resultMap(result, (x) => createTsExport(x, si));
2022-04-11 03:16:31 +00:00
}
function createTsExport(
x: expressionValue,
sampEnv: samplingParams
): squiggleExpression {
2022-04-11 03:16:31 +00:00
switch (x.tag) {
case "EvArray":
return tag(
"array",
x.value.map((x) => createTsExport(x, sampEnv))
);
2022-04-11 03:16:31 +00:00
case "EvBool":
return tag("boolean", x.value);
case "EvDistribution":
return tag("distribution", new Distribution(x.value, sampEnv));
case "EvNumber":
return tag("number", x.value);
case "EvRecord":
return tag(
"record",
_.mapValues(x.value, (x) => createTsExport(x, sampEnv))
);
case "EvString":
return tag("string", x.value);
case "EvSymbol":
return tag("symbol", x.value);
2022-04-11 03:16:31 +00:00
}
}
2022-04-11 00:51:43 +00:00
export function resultExn<a, c>(r: result<a, c>): a | c {
return r.value;
2022-04-10 01:56:05 +00:00
}
export type point = { x: number; y: number };
2022-04-11 06:16:29 +00:00
export type shape = {
continuous: point[];
discrete: point[];
};
2022-04-11 06:16:29 +00:00
function shapePoints(x: continuousShape | discreteShape): point[] {
2022-04-11 06:16:29 +00:00
let xs = x.xyShape.xs;
let ys = x.xyShape.ys;
return _.zipWith(xs, ys, (x, y) => ({ x, y }));
2022-04-11 06:16:29 +00:00
}
2022-04-11 00:48:45 +00:00
export class Distribution {
t: genericDist;
2022-04-11 03:16:31 +00:00
env: samplingParams;
2022-04-11 03:16:31 +00:00
constructor(t: genericDist, env: samplingParams) {
this.t = t;
this.env = env;
return this;
}
mapResultDist(
r: result<genericDist, distributionError>
): result<Distribution, distributionError> {
2022-04-11 00:48:45 +00:00
return resultMap(r, (v: genericDist) => new Distribution(v, this.env));
}
2022-04-11 03:16:31 +00:00
mean(): result<number, distributionError> {
return Constructors_mean({ env: this.env }, this.t);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
sample(): result<number, distributionError> {
return Constructors_sample({ env: this.env }, this.t);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
pdf(n: number): result<number, distributionError> {
return Constructors_pdf({ env: this.env }, this.t, n);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
cdf(n: number): result<number, distributionError> {
return Constructors_cdf({ env: this.env }, this.t, n);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
inv(n: number): result<number, distributionError> {
return Constructors_inv({ env: this.env }, this.t, n);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
normalize(): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_normalize({ env: this.env }, this.t)
);
2022-04-08 19:55:04 +00:00
}
pointSet(): result<shape, distributionError> {
let pointSet = toPointSet(
this.t,
{
xyPointLength: this.env.xyPointLength,
sampleCount: this.env.sampleCount,
},
undefined
);
if (pointSet.tag === "Ok") {
2022-04-11 06:16:29 +00:00
let distribution = pointSet.value;
if (distribution.tag === "Continuous") {
2022-04-11 06:16:29 +00:00
return Ok({
continuous: shapePoints(distribution.value),
discrete: [],
});
} else if (distribution.tag === "Discrete") {
2022-04-11 06:16:29 +00:00
return Ok({
discrete: shapePoints(distribution.value),
continuous: [],
});
} else {
2022-04-11 06:16:29 +00:00
return Ok({
discrete: shapePoints(distribution.value.discrete),
continuous: shapePoints(distribution.value.continuous),
});
2022-04-11 06:16:29 +00:00
}
} else {
return pointSet;
2022-04-11 06:16:29 +00:00
}
}
2022-04-11 03:16:31 +00:00
toPointSet(): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_toPointSet({ env: this.env }, this.t)
);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
toSampleSet(n: number): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_toSampleSet({ env: this.env }, this.t, n)
);
2022-04-08 19:55:04 +00:00
}
truncate(
left: number,
right: number
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_truncate({ env: this.env }, this.t, left, right)
2022-04-08 19:55:04 +00:00
);
}
2022-04-11 03:16:31 +00:00
inspect(): result<Distribution, distributionError> {
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
2022-04-08 19:55:04 +00:00
}
2022-04-11 06:16:29 +00:00
toString(): string {
let result = Constructors_toString({ env: this.env }, this.t);
if (result.tag === "Ok") {
return result.value;
} else {
return distributionErrorToString(result.value);
2022-04-11 06:16:29 +00:00
}
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
toSparkline(n: number): result<string, distributionError> {
return Constructors_toSparkline({ env: this.env }, this.t, n);
2022-04-08 19:55:04 +00:00
}
2022-04-11 03:16:31 +00:00
algebraicAdd(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
algebraicMultiply(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
algebraicDivide(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
algebraicSubtract(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
);
}
algebraicLogarithm(
d2: Distribution
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
algebraicPower(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
2022-04-09 16:37:26 +00:00
Constructors_algebraicPower({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
pointwiseAdd(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
pointwiseMultiply(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
pointwiseDivide(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
pointwiseSubtract(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
);
}
pointwiseLogarithm(
d2: Distribution
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
);
}
2022-04-11 03:16:31 +00:00
pointwisePower(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
2022-04-09 16:37:26 +00:00
Constructors_pointwisePower({ env: this.env }, this.t, d2.t)
);
}
}