A playground based on reducer
This commit is contained in:
parent
61b589d0bd
commit
cb07f5f68a
|
@ -1,124 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import _ from "lodash";
|
|
||||||
import type { Spec } from "vega";
|
|
||||||
import type {
|
|
||||||
DistPlus,
|
|
||||||
} from "@quri/squiggle-lang";
|
|
||||||
import { createClassFromSpec } from "react-vega";
|
|
||||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
|
||||||
|
|
||||||
let SquiggleVegaChart = createClassFromSpec({
|
|
||||||
spec: chartSpecification as Spec,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const DistPlusChart: React.FC<{
|
|
||||||
distPlus: DistPlus;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}> = ({ distPlus, width, height }) => {
|
|
||||||
let shape = distPlus.pointSetDist;
|
|
||||||
if (shape.tag === "Continuous") {
|
|
||||||
let xyShape = shape.value.xyShape;
|
|
||||||
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
|
||||||
let total = 0;
|
|
||||||
let cdf = xyShape.ys.map((y) => {
|
|
||||||
total += y;
|
|
||||||
return total / totalY;
|
|
||||||
});
|
|
||||||
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
|
|
||||||
cdf: (c * 100).toFixed(2) + "%",
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SquiggleVegaChart
|
|
||||||
width={width}
|
|
||||||
height={height}
|
|
||||||
data={{ con: values }}
|
|
||||||
actions={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (shape.tag === "Discrete") {
|
|
||||||
let xyShape = shape.value.xyShape;
|
|
||||||
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
|
||||||
let total = 0;
|
|
||||||
let cdf = xyShape.ys.map((y) => {
|
|
||||||
total += y;
|
|
||||||
return total / totalY;
|
|
||||||
});
|
|
||||||
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
|
|
||||||
cdf: (c * 100).toFixed(2) + "%",
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return <SquiggleVegaChart data={{ dis: values }} actions={false} />;
|
|
||||||
} else if (shape.tag === "Mixed") {
|
|
||||||
let discreteShape = shape.value.discrete.xyShape;
|
|
||||||
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
|
||||||
|
|
||||||
let discretePoints = _.zip(discreteShape.xs, discreteShape.ys);
|
|
||||||
let continuousShape = shape.value.continuous.xyShape;
|
|
||||||
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
|
||||||
|
|
||||||
interface labeledPoint {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
type: "discrete" | "continuous";
|
|
||||||
}
|
|
||||||
|
|
||||||
let markedDisPoints: labeledPoint[] = discretePoints.map(([x, y]) => ({
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
type: "discrete",
|
|
||||||
}));
|
|
||||||
let markedConPoints: labeledPoint[] = continuousPoints.map(([x, y]) => ({
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
type: "continuous",
|
|
||||||
}));
|
|
||||||
|
|
||||||
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), "x");
|
|
||||||
|
|
||||||
let totalContinuous = 1 - totalDiscrete;
|
|
||||||
let totalY = continuousShape.ys.reduce((a: number, b: number) => a + b);
|
|
||||||
|
|
||||||
let total = 0;
|
|
||||||
let cdf = sortedPoints.map((point: labeledPoint) => {
|
|
||||||
if (point.type === "discrete") {
|
|
||||||
total += point.y;
|
|
||||||
return total;
|
|
||||||
} else if (point.type === "continuous") {
|
|
||||||
total += (point.y / totalY) * totalContinuous;
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interface cdfLabeledPoint {
|
|
||||||
cdf: string;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
type: "discrete" | "continuous";
|
|
||||||
}
|
|
||||||
let cdfLabeledPoint: cdfLabeledPoint[] = _.zipWith(
|
|
||||||
cdf,
|
|
||||||
sortedPoints,
|
|
||||||
(c: number, point: labeledPoint) => ({
|
|
||||||
...point,
|
|
||||||
cdf: (c * 100).toFixed(2) + "%",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
let continuousValues = cdfLabeledPoint.filter(
|
|
||||||
(x) => x.type === "continuous"
|
|
||||||
);
|
|
||||||
let discreteValues = cdfLabeledPoint.filter((x) => x.type === "discrete");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SquiggleVegaChart
|
|
||||||
data={{ con: continuousValues, dis: discreteValues }}
|
|
||||||
actions={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
38
packages/components/src/components/DistributionChart.tsx
Normal file
38
packages/components/src/components/DistributionChart.tsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import _ from "lodash";
|
||||||
|
import type { Spec } from "vega";
|
||||||
|
import type {
|
||||||
|
Distribution,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
|
import { distributionErrorToString } from '@quri/squiggle-lang';
|
||||||
|
import { createClassFromSpec } from "react-vega";
|
||||||
|
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||||
|
|
||||||
|
let SquiggleVegaChart = createClassFromSpec({
|
||||||
|
spec: chartSpecification as Spec,
|
||||||
|
});
|
||||||
|
|
||||||
|
type DistributionChartProps = {
|
||||||
|
distribution: Distribution;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DistributionChart: React.FC<DistributionChartProps> = ({ distribution, width, height }: DistributionChartProps) => {
|
||||||
|
console.log("Making shape")
|
||||||
|
let shape = distribution.shape();
|
||||||
|
console.log(shape)
|
||||||
|
if (shape.tag === "Ok") {
|
||||||
|
return (
|
||||||
|
<SquiggleVegaChart
|
||||||
|
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
actions={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return <> {distributionErrorToString(shape.value)} </>;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,10 +1,10 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import type { Spec } from "vega";
|
import type { Spec } from "vega";
|
||||||
import type { DistPlus } from "@quri/squiggle-lang";
|
import type { Distribution, errorValue, result } from "@quri/squiggle-lang";
|
||||||
import { createClassFromSpec } from "react-vega";
|
import { createClassFromSpec } from "react-vega";
|
||||||
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
||||||
import { DistPlusChart } from "./DistPlusChart";
|
import { DistributionChart } from "./DistributionChart";
|
||||||
import { Error } from "./Error";
|
import { Error } from "./Error";
|
||||||
|
|
||||||
let SquigglePercentilesChart = createClassFromSpec({
|
let SquigglePercentilesChart = createClassFromSpec({
|
||||||
|
@ -13,36 +13,38 @@ let SquigglePercentilesChart = createClassFromSpec({
|
||||||
|
|
||||||
type distPlusFn = (
|
type distPlusFn = (
|
||||||
a: number
|
a: number
|
||||||
) => { tag: "Ok"; value: DistPlus } | { tag: "Error"; value: string };
|
) => result<Distribution, errorValue>
|
||||||
|
|
||||||
const _rangeByCount = (start, stop, count) => {
|
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||||
const step = (stop - start) / (count - 1);
|
const step = (stop - start) / (count - 1);
|
||||||
const items = _.range(start, stop, step);
|
const items = _.range(start, stop, step);
|
||||||
const result = items.concat([stop]);
|
const result = items.concat([stop]);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function unwrap<a, b>( x: result<a, b>): a {
|
||||||
|
if(x.tag === "Ok"){
|
||||||
|
return x.value
|
||||||
|
}
|
||||||
|
}
|
||||||
export const FunctionChart: React.FC<{
|
export const FunctionChart: React.FC<{
|
||||||
distPlusFn: distPlusFn;
|
distPlusFn: distPlusFn;
|
||||||
diagramStart: number;
|
diagramStart: number;
|
||||||
diagramStop: number;
|
diagramStop: number;
|
||||||
diagramCount: number;
|
diagramCount: number;
|
||||||
}> = ({ distPlusFn, diagramStart, diagramStop, diagramCount }) => {
|
}> = ({ distPlusFn, diagramStart, diagramStop, diagramCount }) => {
|
||||||
let [mouseOverlay, setMouseOverlay] = React.useState(NaN);
|
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||||
function handleHover(...args) {
|
function handleHover(...args) {
|
||||||
setMouseOverlay(args[1]);
|
setMouseOverlay(args[1]);
|
||||||
}
|
}
|
||||||
function handleOut(...args) {
|
function handleOut() {
|
||||||
setMouseOverlay(NaN);
|
setMouseOverlay(NaN);
|
||||||
}
|
}
|
||||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||||
let percentileArray = [
|
|
||||||
0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99,
|
|
||||||
];
|
|
||||||
let mouseItem = distPlusFn(mouseOverlay);
|
let mouseItem = distPlusFn(mouseOverlay);
|
||||||
let showChart =
|
let showChart =
|
||||||
mouseItem.tag === "Ok" ? (
|
mouseItem.tag === "Ok" ? (
|
||||||
<DistPlusChart distPlus={mouseItem.value} width={400} height={140} />
|
<DistributionChart distribution={mouseItem.value} width={400} height={140} />
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
);
|
);
|
||||||
|
@ -56,22 +58,21 @@ export const FunctionChart: React.FC<{
|
||||||
})
|
})
|
||||||
.filter((x) => x !== null)
|
.filter((x) => x !== null)
|
||||||
.map(({ x, value }) => {
|
.map(({ x, value }) => {
|
||||||
let percentiles = getPercentiles(percentileArray, value);
|
|
||||||
return {
|
return {
|
||||||
x: x,
|
x: x,
|
||||||
p1: percentiles[0],
|
p1: unwrap(value.inv(0.01)),
|
||||||
p5: percentiles[1],
|
p5: unwrap(value.inv(0.05)),
|
||||||
p10: percentiles[2],
|
p10: unwrap(value.inv(0.12)),
|
||||||
p20: percentiles[3],
|
p20: unwrap(value.inv(0.20)),
|
||||||
p30: percentiles[4],
|
p30: unwrap(value.inv(0.30)),
|
||||||
p40: percentiles[5],
|
p40: unwrap(value.inv(0.40)),
|
||||||
p50: percentiles[6],
|
p50: unwrap(value.inv(0.50)),
|
||||||
p60: percentiles[7],
|
p60: unwrap(value.inv(0.60)),
|
||||||
p70: percentiles[8],
|
p70: unwrap(value.inv(0.70)),
|
||||||
p80: percentiles[9],
|
p80: unwrap(value.inv(0.80)),
|
||||||
p90: percentiles[10],
|
p90: unwrap(value.inv(0.90)),
|
||||||
p95: percentiles[11],
|
p95: unwrap(value.inv(0.95)),
|
||||||
p99: percentiles[12],
|
p99: unwrap(value.inv(0.99)),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,88 +102,3 @@ export const FunctionChart: React.FC<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getPercentiles(percentiles: number[], t: DistPlus) {
|
|
||||||
if (t.pointSetDist.tag === "Discrete") {
|
|
||||||
let total = 0;
|
|
||||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
|
||||||
let bounds = percentiles.map((_) => maxX);
|
|
||||||
_.zipWith(
|
|
||||||
t.pointSetDist.value.xyShape.xs,
|
|
||||||
t.pointSetDist.value.xyShape.ys,
|
|
||||||
(x, y) => {
|
|
||||||
total += y;
|
|
||||||
percentiles.forEach((v, i) => {
|
|
||||||
if (total > v && bounds[i] === maxX) {
|
|
||||||
bounds[i] = x;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return bounds;
|
|
||||||
} else if (t.pointSetDist.tag === "Continuous") {
|
|
||||||
let total = 0;
|
|
||||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
|
||||||
let totalY = _.sum(t.pointSetDist.value.xyShape.ys);
|
|
||||||
let bounds = percentiles.map((_) => maxX);
|
|
||||||
_.zipWith(
|
|
||||||
t.pointSetDist.value.xyShape.xs,
|
|
||||||
t.pointSetDist.value.xyShape.ys,
|
|
||||||
(x, y) => {
|
|
||||||
total += y / totalY;
|
|
||||||
percentiles.forEach((v, i) => {
|
|
||||||
if (total > v && bounds[i] === maxX) {
|
|
||||||
bounds[i] = x;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return bounds;
|
|
||||||
} else if (t.pointSetDist.tag === "Mixed") {
|
|
||||||
let discreteShape = t.pointSetDist.value.discrete.xyShape;
|
|
||||||
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
|
||||||
|
|
||||||
let discretePoints = _.zip(discreteShape.xs, discreteShape.ys);
|
|
||||||
let continuousShape = t.pointSetDist.value.continuous.xyShape;
|
|
||||||
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
|
|
||||||
|
|
||||||
interface labeledPoint {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
type: "discrete" | "continuous";
|
|
||||||
}
|
|
||||||
|
|
||||||
let markedDisPoints: labeledPoint[] = discretePoints.map(([x, y]) => ({
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
type: "discrete",
|
|
||||||
}));
|
|
||||||
let markedConPoints: labeledPoint[] = continuousPoints.map(([x, y]) => ({
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
type: "continuous",
|
|
||||||
}));
|
|
||||||
|
|
||||||
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), "x");
|
|
||||||
|
|
||||||
let totalContinuous = 1 - totalDiscrete;
|
|
||||||
let totalY = continuousShape.ys.reduce((a: number, b: number) => a + b);
|
|
||||||
|
|
||||||
let total = 0;
|
|
||||||
let maxX = _.max(sortedPoints.map((x) => x.x));
|
|
||||||
let bounds = percentiles.map((_) => maxX);
|
|
||||||
sortedPoints.map((point: labeledPoint) => {
|
|
||||||
if (point.type === "discrete") {
|
|
||||||
total += point.y;
|
|
||||||
} else if (point.type === "continuous") {
|
|
||||||
total += (point.y / totalY) * totalContinuous;
|
|
||||||
}
|
|
||||||
percentiles.forEach((v, i) => {
|
|
||||||
if (total > v && bounds[i] === maxX) {
|
|
||||||
bounds[i] = total;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return total;
|
|
||||||
});
|
|
||||||
return bounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { run } from "@quri/squiggle-lang";
|
import { run, errorValueToString } from "@quri/squiggle-lang";
|
||||||
import type {
|
import type {
|
||||||
SamplingInputs,
|
samplingParams,
|
||||||
exportEnv,
|
exportEnv,
|
||||||
exportDistribution,
|
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
import { NumberShower } from "./NumberShower";
|
import { NumberShower } from "./NumberShower";
|
||||||
import { DistPlusChart } from "./DistPlusChart";
|
import { DistributionChart } from "./DistributionChart";
|
||||||
import { FunctionChart } from "./FunctionChart";
|
|
||||||
import { Error } from "./Error";
|
import { Error } from "./Error";
|
||||||
|
|
||||||
export interface SquiggleChartProps {
|
export interface SquiggleChartProps {
|
||||||
|
@ -39,8 +37,6 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
squiggleString = "",
|
squiggleString = "",
|
||||||
sampleCount = 1000,
|
sampleCount = 1000,
|
||||||
outputXYPoints = 1000,
|
outputXYPoints = 1000,
|
||||||
kernelWidth,
|
|
||||||
pointDistLength = 1000,
|
|
||||||
diagramStart = 0,
|
diagramStart = 0,
|
||||||
diagramStop = 10,
|
diagramStop = 10,
|
||||||
diagramCount = 20,
|
diagramCount = 20,
|
||||||
|
@ -49,43 +45,35 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
width = 500,
|
width = 500,
|
||||||
height = 60,
|
height = 60,
|
||||||
}: SquiggleChartProps) => {
|
}: SquiggleChartProps) => {
|
||||||
let samplingInputs: SamplingInputs = {
|
let samplingInputs: samplingParams = {
|
||||||
sampleCount: sampleCount,
|
sampleCount: sampleCount,
|
||||||
outputXYPoints: outputXYPoints,
|
xyPointLength: outputXYPoints
|
||||||
kernelWidth: kernelWidth,
|
|
||||||
pointDistLength: pointDistLength,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = run(squiggleString, samplingInputs, environment);
|
let result = run(squiggleString, samplingInputs, environment);
|
||||||
|
console.log(result)
|
||||||
if (result.tag === "Ok") {
|
if (result.tag === "Ok") {
|
||||||
let environment = result.value.environment;
|
|
||||||
let exports = result.value.exports;
|
|
||||||
onEnvChange(environment);
|
onEnvChange(environment);
|
||||||
let chartResults = exports.map((chartResult: exportDistribution) => {
|
let chartResult = result.value;
|
||||||
if (chartResult["NAME"] === "Float") {
|
if (chartResult.tag === "number") {
|
||||||
return <NumberShower precision={3} number={chartResult["VAL"]} />;
|
return <NumberShower precision={3} number={chartResult.value} />;
|
||||||
} else if (chartResult["NAME"] === "DistPlus") {
|
} else if (chartResult.tag === "distribution") {
|
||||||
return (
|
console.log("Is a distribution")
|
||||||
<DistPlusChart
|
return (
|
||||||
distPlus={chartResult.VAL}
|
<DistributionChart
|
||||||
height={height}
|
distribution={chartResult.value}
|
||||||
width={width}
|
height={height}
|
||||||
/>
|
width={width}
|
||||||
);
|
/>
|
||||||
} else if (chartResult.NAME === "Function") {
|
);
|
||||||
return (
|
console.log("NOT THIS LINE")
|
||||||
<FunctionChart
|
}
|
||||||
distPlusFn={chartResult.VAL}
|
else {
|
||||||
diagramStart={diagramStart}
|
console.log("Is a distribution")
|
||||||
diagramStop={diagramStop}
|
return <Error heading="No Viewer">{"We don't currently have a viewer for this type: " + chartResult.tag}</Error>;
|
||||||
diagramCount={diagramCount}
|
}
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return <>{chartResults}</>;
|
|
||||||
} else if (result.tag === "Error") {
|
} else if (result.tag === "Error") {
|
||||||
// At this point, we came across an error. What was our error?
|
// At this point, we came across an error. What was our error?
|
||||||
return <Error heading={"Parse Error"}>{result.value}</Error>;
|
return <Error heading={"Parse Error"}>{errorValueToString(result.value)}</Error>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,8 @@ import type {
|
||||||
exportDistribution,
|
exportDistribution,
|
||||||
} from "../rescript/ProgramEvaluator.gen";
|
} from "../rescript/ProgramEvaluator.gen";
|
||||||
export type { exportEnv, exportDistribution };
|
export type { exportEnv, exportDistribution };
|
||||||
import { genericDist, samplingParams, evaluate, expressionValue, errorValue, distributionError } from "../rescript/TypescriptInterface.gen";
|
import { genericDist, samplingParams, evaluate, expressionValue, errorValue, distributionError, toPointSet, continuousShape, discreteShape, distributionErrorToString } from "../rescript/TypescriptInterface.gen";
|
||||||
export { makeSampleSetDist } from "../rescript/TypescriptInterface.gen";
|
export { makeSampleSetDist, errorValueToString, distributionErrorToString } from "../rescript/TypescriptInterface.gen";
|
||||||
import {
|
import {
|
||||||
Constructors_mean,
|
Constructors_mean,
|
||||||
Constructors_sample,
|
Constructors_sample,
|
||||||
|
@ -32,19 +32,14 @@ import {
|
||||||
Constructors_pointwiseLogarithm,
|
Constructors_pointwiseLogarithm,
|
||||||
Constructors_pointwisePower,
|
Constructors_pointwisePower,
|
||||||
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
||||||
|
export type {samplingParams, errorValue}
|
||||||
|
|
||||||
export type SamplingInputs = {
|
|
||||||
readonly sampleCount?: number;
|
|
||||||
readonly outputXYPoints?: number;
|
|
||||||
readonly kernelWidth?: number;
|
|
||||||
readonly pointDistLength?: number
|
|
||||||
};
|
|
||||||
export let defaultSamplingInputs: samplingParams = {
|
export let defaultSamplingInputs: samplingParams = {
|
||||||
sampleCount: 10000,
|
sampleCount: 10000,
|
||||||
xyPointLength: 10000
|
xyPointLength: 10000
|
||||||
};
|
};
|
||||||
|
|
||||||
type result<a, b> =
|
export type result<a, b> =
|
||||||
| {
|
| {
|
||||||
tag: "Ok";
|
tag: "Ok";
|
||||||
value: a;
|
value: a;
|
||||||
|
@ -65,6 +60,10 @@ export function resultMap<a, b, c>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Ok<a,b>(x: a): result<a,b> {
|
||||||
|
return {"tag": "Ok", value: x}
|
||||||
|
}
|
||||||
|
|
||||||
type tagged<a, b> = {tag: a, value: b}
|
type tagged<a, b> = {tag: a, value: b}
|
||||||
|
|
||||||
function tag<a,b>(x: a, y: b) : tagged<a, b>{
|
function tag<a,b>(x: a, y: b) : tagged<a, b>{
|
||||||
|
@ -97,9 +96,6 @@ function createTsExport(x: expressionValue, sampEnv: samplingParams): squiggleEx
|
||||||
return tag("number", x.value);
|
return tag("number", x.value);
|
||||||
case "EvRecord":
|
case "EvRecord":
|
||||||
return tag("record", _.mapValues(x.value, x => createTsExport(x, sampEnv)))
|
return tag("record", _.mapValues(x.value, x => createTsExport(x, sampEnv)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +104,19 @@ export function resultExn<a, c>(r: result<a, c>): a | c {
|
||||||
return r.value;
|
return r.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type point = { x: number, y: number}
|
||||||
|
|
||||||
|
export type shape = {
|
||||||
|
continuous: point[]
|
||||||
|
discrete: point[]
|
||||||
|
}
|
||||||
|
|
||||||
|
function shapePoints(x : continuousShape | discreteShape): point[]{
|
||||||
|
let xs = x.xyShape.xs;
|
||||||
|
let ys = x.xyShape.ys;
|
||||||
|
return _.zipWith(xs, ys, (x, y) => ({x, y}))
|
||||||
|
}
|
||||||
|
|
||||||
export class Distribution {
|
export class Distribution {
|
||||||
t: genericDist;
|
t: genericDist;
|
||||||
env: samplingParams;
|
env: samplingParams;
|
||||||
|
@ -148,6 +157,34 @@ export class Distribution {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shape() : result<shape, distributionError> {
|
||||||
|
let pointSet = toPointSet(this.t, {xyPointLength: this.env.xyPointLength, sampleCount: this.env.sampleCount}, null);
|
||||||
|
if(pointSet.tag === "Ok"){
|
||||||
|
let distribution = pointSet.value;
|
||||||
|
if(distribution.tag === "Continuous"){
|
||||||
|
return Ok({
|
||||||
|
continuous: shapePoints(distribution.value),
|
||||||
|
discrete: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if(distribution.tag === "Discrete"){
|
||||||
|
return Ok({
|
||||||
|
discrete: shapePoints(distribution.value),
|
||||||
|
continuous: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if(distribution.tag === "Mixed"){
|
||||||
|
return Ok({
|
||||||
|
discrete: shapePoints(distribution.value.discrete),
|
||||||
|
continuous: shapePoints(distribution.value.continuous)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return pointSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toPointSet(): result<Distribution, distributionError> {
|
toPointSet(): result<Distribution, distributionError> {
|
||||||
return this.mapResultDist(
|
return this.mapResultDist(
|
||||||
Constructors_toPointSet({ env: this.env }, this.t)
|
Constructors_toPointSet({ env: this.env }, this.t)
|
||||||
|
@ -170,8 +207,14 @@ export class Distribution {
|
||||||
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
|
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): result<string, distributionError> {
|
toString(): string {
|
||||||
return Constructors_toString({ env: this.env }, this.t);
|
let result = Constructors_toString({ env: this.env }, this.t);
|
||||||
|
if(result.tag === "Ok"){
|
||||||
|
result.value
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return distributionErrorToString(result.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toSparkline(n: number): result<string, distributionError> {
|
toSparkline(n: number): result<string, distributionError> {
|
||||||
|
|
|
@ -21,6 +21,7 @@ let toFloatOperation: (
|
||||||
~distToFloatOperation: Operation.distToFloatOperation,
|
~distToFloatOperation: Operation.distToFloatOperation,
|
||||||
) => result<float, error>
|
) => result<float, error>
|
||||||
|
|
||||||
|
@genType
|
||||||
let toPointSet: (
|
let toPointSet: (
|
||||||
t,
|
t,
|
||||||
~xyPointLength: int,
|
~xyPointLength: int,
|
||||||
|
|
|
@ -10,10 +10,21 @@ type error =
|
||||||
| DistributionVerticalShiftIsInvalid
|
| DistributionVerticalShiftIsInvalid
|
||||||
| Other(string)
|
| Other(string)
|
||||||
|
|
||||||
|
@genType
|
||||||
module Error = {
|
module Error = {
|
||||||
type t = error
|
type t = error
|
||||||
|
|
||||||
let fromString = (s: string): t => Other(s)
|
let fromString = (s: string): t => Other(s)
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let toString = (x: t) => {
|
||||||
|
switch x {
|
||||||
|
| NotYetImplemented => "Not Yet Implemented"
|
||||||
|
| Unreachable => "Unreachable"
|
||||||
|
| DistributionVerticalShiftIsInvalid => "Distribution Vertical Shift Is Invalid"
|
||||||
|
| Other(s) => s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let resultStringToResultError: result<'a, string> => result<'a, error> = n =>
|
let resultStringToResultError: result<'a, string> => result<'a, error> = n =>
|
||||||
n->E.R2.errMap(r => r->fromString->Error)
|
n->E.R2.errMap(r => r->fromString->Error)
|
||||||
|
@ -51,6 +62,7 @@ module Operation = {
|
||||||
| #Sample
|
| #Sample
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@genType
|
||||||
type pointsetXSelection = [#Linear | #ByWeight]
|
type pointsetXSelection = [#Linear | #ByWeight]
|
||||||
|
|
||||||
type toDist =
|
type toDist =
|
||||||
|
|
|
@ -214,4 +214,4 @@ module T = Dist({
|
||||||
let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean
|
let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean
|
||||||
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,6 +19,7 @@ type interpolationStrategy = XYShape.interpolationStrategy;
|
||||||
type extrapolationStrategy = XYShape.extrapolationStrategy;
|
type extrapolationStrategy = XYShape.extrapolationStrategy;
|
||||||
type interpolator = XYShape.extrapolationStrategy;
|
type interpolator = XYShape.extrapolationStrategy;
|
||||||
|
|
||||||
|
@genType
|
||||||
type rec continuousShape = {
|
type rec continuousShape = {
|
||||||
xyShape: xyShape,
|
xyShape: xyShape,
|
||||||
interpolation: interpolationStrategy,
|
interpolation: interpolationStrategy,
|
||||||
|
@ -26,12 +27,14 @@ type rec continuousShape = {
|
||||||
integralCache: option<continuousShape>,
|
integralCache: option<continuousShape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
type discreteShape = {
|
type discreteShape = {
|
||||||
xyShape: xyShape,
|
xyShape: xyShape,
|
||||||
integralSumCache: option<float>,
|
integralSumCache: option<float>,
|
||||||
integralCache: option<continuousShape>,
|
integralCache: option<continuousShape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
type mixedShape = {
|
type mixedShape = {
|
||||||
continuous: continuousShape,
|
continuous: continuousShape,
|
||||||
discrete: discreteShape,
|
discrete: discreteShape,
|
||||||
|
|
|
@ -8,6 +8,7 @@ type errorValue =
|
||||||
|
|
||||||
type t = errorValue
|
type t = errorValue
|
||||||
|
|
||||||
|
@genType
|
||||||
let errorToString = err =>
|
let errorToString = err =>
|
||||||
switch err {
|
switch err {
|
||||||
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
||||||
|
|
|
@ -36,3 +36,21 @@ type expressionValue = Reducer_Expression.expressionValue
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let toPointSet = GenericDist.toPointSet
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type mixedShape = PointSetTypes.mixedShape
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type discreteShape = PointSetTypes.discreteShape
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type continuousShape = PointSetTypes.continuousShape
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let errorValueToString = Reducer_ErrorValue.errorToString
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let distributionErrorToString = GenericDist_Types.Error.toString
|
||||||
|
|
Loading…
Reference in New Issue
Block a user