Merge pull request #210 from QURIresearch/GenericOperation-operation-functions
Turn GenericOperation into a bunch of manual functions for distributions
This commit is contained in:
commit
344c989cb5
|
@ -1,34 +1,86 @@
|
||||||
import { run } from '../src/js/index';
|
import { run, GenericDist, resultMap } from "../src/js/index";
|
||||||
|
|
||||||
let testRun = (x: string) => {
|
let testRun = (x: string) => {
|
||||||
let result = run(x)
|
let result = run(x);
|
||||||
if(result.tag == 'Ok'){
|
if (result.tag == "Ok") {
|
||||||
return { tag: 'Ok', value: result.value.exports }
|
return { tag: "Ok", value: result.value.exports };
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
else {
|
};
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Simple calculations and results", () => {
|
describe("Simple calculations and results", () => {
|
||||||
test("mean(normal(5,2))", () => {
|
test("mean(normal(5,2))", () => {
|
||||||
expect(testRun("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] })
|
expect(testRun("mean(normal(5,2))")).toEqual({
|
||||||
})
|
tag: "Ok",
|
||||||
test("10+10", () => {
|
value: [{ NAME: "Float", VAL: 5 }],
|
||||||
let foo = testRun("10 + 10")
|
});
|
||||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 20 } ] })
|
});
|
||||||
})
|
test("10+10", () => {
|
||||||
})
|
let foo = testRun("10 + 10");
|
||||||
|
expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 20 }] });
|
||||||
|
});
|
||||||
|
});
|
||||||
describe("Log function", () => {
|
describe("Log function", () => {
|
||||||
test("log(1) = 0", () => {
|
test("log(1) = 0", () => {
|
||||||
let foo = testRun("log(1)")
|
let foo = testRun("log(1)");
|
||||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]})
|
expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 0 }] });
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe("Multimodal too many weights error", () => {
|
describe("Multimodal too many weights error", () => {
|
||||||
test("mm(0,0,[0,0,0])", () => {
|
test("mm(0,0,[0,0,0])", () => {
|
||||||
let foo = testRun("mm(0,0,[0,0,0])")
|
let foo = testRun("mm(0,0,[0,0,0])");
|
||||||
expect(foo).toEqual({ "tag": "Error", "value": "Function multimodal error: Too many weights provided" })
|
expect(foo).toEqual({
|
||||||
})
|
tag: "Error",
|
||||||
|
value: "Function multimodal error: Too many weights provided",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("GenericDist", () => {
|
||||||
|
|
||||||
|
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
||||||
|
let env = { sampleCount: 8, xyPointLength: 100 };
|
||||||
|
let dist = new GenericDist(
|
||||||
|
{ tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
|
||||||
|
env
|
||||||
|
);
|
||||||
|
let dist2 = new GenericDist(
|
||||||
|
{ tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] },
|
||||||
|
env
|
||||||
|
);
|
||||||
|
|
||||||
|
test("mean", () => {
|
||||||
|
expect(dist.mean().value).toBeCloseTo(3.737);
|
||||||
|
});
|
||||||
|
test("pdf", () => {
|
||||||
|
expect(dist.pdf(5.0).value).toBeCloseTo(0.0431);
|
||||||
|
});
|
||||||
|
test("cdf", () => {
|
||||||
|
expect(dist.cdf(5.0).value).toBeCloseTo(0.155);
|
||||||
|
});
|
||||||
|
test("inv", () => {
|
||||||
|
expect(dist.inv(0.5).value).toBeCloseTo(9.458);
|
||||||
|
});
|
||||||
|
test("toPointSet", () => {
|
||||||
|
expect(
|
||||||
|
resultMap(dist.toPointSet(), (r: GenericDist) => r.toString()).value.value
|
||||||
|
).toBe("Point Set Distribution");
|
||||||
|
});
|
||||||
|
test("toSparkline", () => {
|
||||||
|
expect(dist.toSparkline(20).value).toBe("▁▁▃▅███▆▄▃▂▁▁▂▂▃▂▁▁▁");
|
||||||
|
});
|
||||||
|
test("algebraicAdd", () => {
|
||||||
|
expect(
|
||||||
|
resultMap(dist.algebraicAdd(dist2), (r: GenericDist) => r.toSparkline(20))
|
||||||
|
.value.value
|
||||||
|
).toBe("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁");
|
||||||
|
});
|
||||||
|
test("pointwiseAdd", () => {
|
||||||
|
expect(
|
||||||
|
resultMap(dist.pointwiseAdd(dist2), (r: GenericDist) => r.toSparkline(20))
|
||||||
|
.value.value
|
||||||
|
).toBe("▁▂▅██▅▅▅▆▇█▆▅▃▃▂▂▁▁▁");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"gentypeconfig": {
|
"gentypeconfig": {
|
||||||
"language": "typescript",
|
"language": "typescript",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"shims": {},
|
"shims": {"Js": "Js"},
|
||||||
"debug": {
|
"debug": {
|
||||||
"all": false,
|
"all": false,
|
||||||
"basic": false
|
"basic": false
|
||||||
|
|
|
@ -1,17 +1,223 @@
|
||||||
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
import { runAll } from "../rescript/ProgramEvaluator.gen";
|
||||||
import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen';
|
import type {
|
||||||
export type { SamplingInputs, exportEnv, exportDistribution }
|
Inputs_SamplingInputs_t as SamplingInputs,
|
||||||
export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen';
|
exportEnv,
|
||||||
|
exportType,
|
||||||
|
exportDistribution,
|
||||||
|
} from "../rescript/ProgramEvaluator.gen";
|
||||||
|
export type { SamplingInputs, exportEnv, exportDistribution };
|
||||||
|
export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen";
|
||||||
|
import {
|
||||||
|
genericDist,
|
||||||
|
env,
|
||||||
|
resultDist,
|
||||||
|
resultFloat,
|
||||||
|
resultString,
|
||||||
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
|
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,
|
||||||
|
Constructors_algebraicExponentiate,
|
||||||
|
Constructors_pointwiseAdd,
|
||||||
|
Constructors_pointwiseMultiply,
|
||||||
|
Constructors_pointwiseDivide,
|
||||||
|
Constructors_pointwiseSubtract,
|
||||||
|
Constructors_pointwiseLogarithm,
|
||||||
|
Constructors_pointwiseExponentiate,
|
||||||
|
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
|
||||||
|
|
||||||
export let defaultSamplingInputs : SamplingInputs = {
|
export let defaultSamplingInputs: SamplingInputs = {
|
||||||
sampleCount : 10000,
|
sampleCount: 10000,
|
||||||
outputXYPoints : 10000,
|
outputXYPoints: 10000,
|
||||||
pointDistLength : 1000
|
pointDistLength: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function run(
|
||||||
|
squiggleString: string,
|
||||||
|
samplingInputs?: SamplingInputs,
|
||||||
|
environment?: exportEnv
|
||||||
|
): { tag: "Ok"; value: exportType } | { tag: "Error"; value: string } {
|
||||||
|
let si: SamplingInputs = samplingInputs
|
||||||
|
? samplingInputs
|
||||||
|
: defaultSamplingInputs;
|
||||||
|
let env: exportEnv = environment ? environment : [];
|
||||||
|
return runAll(squiggleString, si, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function run(squiggleString : string, samplingInputs? : SamplingInputs, environment?: exportEnv) : { tag: "Ok"; value: exportType }
|
//This is clearly not fully typed. I think later we should use a functional library to
|
||||||
| { tag: "Error"; value: string } {
|
// provide a better Either type and corresponding functions.
|
||||||
let si : SamplingInputs = samplingInputs ? samplingInputs : defaultSamplingInputs
|
type result =
|
||||||
let env : exportEnv = environment ? environment : []
|
| {
|
||||||
return runAll(squiggleString, si, env)
|
tag: "Ok";
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
tag: "Error";
|
||||||
|
value: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function resultMap(r: result, mapFn: any): result {
|
||||||
|
if (r.tag === "Ok") {
|
||||||
|
return { tag: "Ok", value: mapFn(r.value) };
|
||||||
|
} else {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GenericDist {
|
||||||
|
t: genericDist;
|
||||||
|
env: env;
|
||||||
|
|
||||||
|
constructor(t: genericDist, env: env) {
|
||||||
|
this.t = t;
|
||||||
|
this.env = env;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapResultDist(r: resultDist) {
|
||||||
|
return resultMap(r, (v: genericDist) => new GenericDist(v, this.env));
|
||||||
|
}
|
||||||
|
|
||||||
|
mean() {
|
||||||
|
return Constructors_mean({ env: this.env }, this.t);
|
||||||
|
}
|
||||||
|
|
||||||
|
sample(): resultFloat {
|
||||||
|
return Constructors_sample({ env: this.env }, this.t);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf(n: number): resultFloat {
|
||||||
|
return Constructors_pdf({ env: this.env }, this.t, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdf(n: number): resultFloat {
|
||||||
|
return Constructors_cdf({ env: this.env }, this.t, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
inv(n: number): resultFloat {
|
||||||
|
return Constructors_inv({ env: this.env }, this.t, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize() {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_normalize({ env: this.env }, this.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toPointSet() {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_toPointSet({ env: this.env }, this.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toSampleSet(n: number) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_toSampleSet({ env: this.env }, this.t, n)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
truncate(left: number, right: number) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_truncate({ env: this.env }, this.t, left, right)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inspect() {
|
||||||
|
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): resultString {
|
||||||
|
return Constructors_toString({ env: this.env }, this.t);
|
||||||
|
}
|
||||||
|
|
||||||
|
toSparkline(n: number): resultString {
|
||||||
|
return Constructors_toSparkline({ env: this.env }, this.t, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicAdd(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicMultiply(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicDivide(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicSubtract(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicLogarithm(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
algebraicExponentiate(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_algebraicExponentiate({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseAdd(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseMultiply(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseDivide(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseSubtract(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseLogarithm(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointwiseExponentiate(d2: GenericDist) {
|
||||||
|
return this.mapResultDist(
|
||||||
|
Constructors_pointwiseExponentiate({ env: this.env }, this.t, d2.t)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,8 +114,8 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
|
||||||
->E.R2.fmap(r => Float(r))
|
->E.R2.fmap(r => Float(r))
|
||||||
->OutputLocal.fromResult
|
->OutputLocal.fromResult
|
||||||
| ToString(ToString) => dist->GenericDist.toString->String
|
| ToString(ToString) => dist->GenericDist.toString->String
|
||||||
| ToString(ToSparkline(buckets)) =>
|
| ToString(ToSparkline(bucketCount)) =>
|
||||||
GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ())
|
GenericDist.toSparkline(dist, ~sampleCount, ~bucketCount, ())
|
||||||
->E.R2.fmap(r => String(r))
|
->E.R2.fmap(r => String(r))
|
||||||
->OutputLocal.fromResult
|
->OutputLocal.fromResult
|
||||||
| ToDist(Inspect) => {
|
| ToDist(Inspect) => {
|
||||||
|
@ -185,3 +185,44 @@ module Output = {
|
||||||
newFnCall->E.R2.fmap(run(~env))->OutputLocal.fromResult
|
newFnCall->E.R2.fmap(run(~env))->OutputLocal.fromResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See comment above GenericDist_Types.Constructors to explain the purpose of this module.
|
||||||
|
// I tried having another internal module called UsingDists, similar to how its done in
|
||||||
|
// GenericDist_Types.Constructors. However, this broke GenType for me, so beware.
|
||||||
|
module Constructors = {
|
||||||
|
module C = GenericDist_Types.Constructors.UsingDists
|
||||||
|
open OutputLocal
|
||||||
|
let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR
|
||||||
|
let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR
|
||||||
|
let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR
|
||||||
|
let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR
|
||||||
|
let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR
|
||||||
|
let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR
|
||||||
|
let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR
|
||||||
|
let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR
|
||||||
|
let truncate = (~env, dist, leftCutoff, rightCutoff) =>
|
||||||
|
C.truncate(dist, leftCutoff, rightCutoff)->run(~env)->toDistR
|
||||||
|
let inspect = (~env, dist) => C.inspect(dist)->run(~env)->toDistR
|
||||||
|
let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR
|
||||||
|
let toSparkline = (~env, dist, bucketCount) => C.toSparkline(dist, bucketCount)->run(~env)->toStringR
|
||||||
|
let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let algebraicMultiply = (~env, dist1, dist2) =>
|
||||||
|
C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let algebraicDivide = (~env, dist1, dist2) => C.algebraicDivide(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let algebraicSubtract = (~env, dist1, dist2) =>
|
||||||
|
C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let algebraicLogarithm = (~env, dist1, dist2) =>
|
||||||
|
C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let algebraicExponentiate = (~env, dist1, dist2) =>
|
||||||
|
C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseMultiply = (~env, dist1, dist2) =>
|
||||||
|
C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseDivide = (~env, dist1, dist2) => C.pointwiseDivide(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseSubtract = (~env, dist1, dist2) =>
|
||||||
|
C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseLogarithm = (~env, dist1, dist2) =>
|
||||||
|
C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR
|
||||||
|
let pointwiseExponentiate = (~env, dist1, dist2) =>
|
||||||
|
C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
|
@genType
|
||||||
type env = {
|
type env = {
|
||||||
sampleCount: int,
|
sampleCount: int,
|
||||||
xyPointLength: int,
|
xyPointLength: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open GenericDist_Types
|
||||||
|
|
||||||
|
@genType
|
||||||
type outputType =
|
type outputType =
|
||||||
| Dist(GenericDist_Types.genericDist)
|
| Dist(genericDist)
|
||||||
| Float(float)
|
| Float(float)
|
||||||
| String(string)
|
| String(string)
|
||||||
| GenDistError(GenericDist_Types.error)
|
| GenDistError(error)
|
||||||
|
|
||||||
|
@genType
|
||||||
let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType
|
let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType
|
||||||
let runFromDist: (
|
let runFromDist: (
|
||||||
~env: env,
|
~env: env,
|
||||||
~functionCallInfo: GenericDist_Types.Operation.fromDist,
|
~functionCallInfo: GenericDist_Types.Operation.fromDist,
|
||||||
GenericDist_Types.genericDist,
|
genericDist,
|
||||||
) => outputType
|
) => outputType
|
||||||
let runFromFloat: (
|
let runFromFloat: (
|
||||||
~env: env,
|
~env: env,
|
||||||
|
@ -23,12 +28,68 @@ let runFromFloat: (
|
||||||
|
|
||||||
module Output: {
|
module Output: {
|
||||||
type t = outputType
|
type t = outputType
|
||||||
let toDist: t => option<GenericDist_Types.genericDist>
|
let toDist: t => option<genericDist>
|
||||||
let toDistR: t => result<GenericDist_Types.genericDist, GenericDist_Types.error>
|
let toDistR: t => result<genericDist, error>
|
||||||
let toFloat: t => option<float>
|
let toFloat: t => option<float>
|
||||||
let toFloatR: t => result<float, GenericDist_Types.error>
|
let toFloatR: t => result<float, error>
|
||||||
let toString: t => option<string>
|
let toString: t => option<string>
|
||||||
let toStringR: t => result<string, GenericDist_Types.error>
|
let toStringR: t => result<string, error>
|
||||||
let toError: t => option<GenericDist_Types.error>
|
let toError: t => option<error>
|
||||||
let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t
|
let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module Constructors: {
|
||||||
|
@genType
|
||||||
|
let mean: (~env: env, genericDist) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let sample: (~env: env, genericDist) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let cdf: (~env: env, genericDist, float) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let inv: (~env: env, genericDist, float) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let pdf: (~env: env, genericDist, float) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let normalize: (~env: env, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let toPointSet: (~env: env, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let toSampleSet: (~env: env, genericDist, int) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let truncate: (
|
||||||
|
~env: env,
|
||||||
|
genericDist,
|
||||||
|
option<float>,
|
||||||
|
option<float>,
|
||||||
|
) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let inspect: (~env: env, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let toString: (~env: env, genericDist) => result<string, error>
|
||||||
|
@genType
|
||||||
|
let toSparkline: (~env: env, genericDist, int) => result<string, error>
|
||||||
|
@genType
|
||||||
|
let algebraicAdd: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let algebraicMultiply: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let algebraicDivide: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let algebraicSubtract: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let algebraicLogarithm: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let algebraicExponentiate: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseAdd: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseMultiply: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseDivide: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseSubtract: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result<genericDist, error>
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ let sampleN = (t: t, n) =>
|
||||||
switch t {
|
switch t {
|
||||||
| PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r))
|
| PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r))
|
||||||
| Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r))
|
| Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r))
|
||||||
| SampleSet(_) => Error(GenericDist_Types.NotYetImplemented)
|
| SampleSet(r) => Ok(SampleSet.sampleN(r, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f))
|
let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f))
|
||||||
|
@ -81,10 +81,18 @@ let toPointSet = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result<string, error> =>
|
/*
|
||||||
|
PointSetDist.toSparkline calls "downsampleEquallyOverX", which downsamples it to n=bucketCount.
|
||||||
|
It first needs a pointSetDist, so we convert to a pointSetDist. In this process we want the
|
||||||
|
xyPointLength to be a bit longer than the eventual toSparkline downsampling. I chose 3
|
||||||
|
fairly arbitrarily.
|
||||||
|
*/
|
||||||
|
let toSparkline = (t: t, ~sampleCount: int, ~bucketCount: int=20, unit): result<string, error> =>
|
||||||
t
|
t
|
||||||
->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ())
|
->toPointSet(~xSelection=#Linear, ~xyPointLength=bucketCount * 3, ~sampleCount, ())
|
||||||
->E.R.bind(r => r->PointSetDist.toSparkline->E.R2.errMap(r => Error(GenericDist_Types.Other(r))))
|
->E.R.bind(r =>
|
||||||
|
r->PointSetDist.toSparkline(bucketCount)->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))
|
||||||
|
)
|
||||||
|
|
||||||
module Truncate = {
|
module Truncate = {
|
||||||
let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option<t> =>
|
let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option<t> =>
|
||||||
|
|
|
@ -26,7 +26,7 @@ let toPointSet: (
|
||||||
~xSelection: GenericDist_Types.Operation.pointsetXSelection=?,
|
~xSelection: GenericDist_Types.Operation.pointsetXSelection=?,
|
||||||
unit,
|
unit,
|
||||||
) => result<PointSetTypes.pointSetDist, error>
|
) => result<PointSetTypes.pointSetDist, error>
|
||||||
let toSparkline: (t, ~sampleCount: int, ~buckets: int=?, unit) => result<string, error>
|
let toSparkline: (t, ~sampleCount: int, ~bucketCount: int=?, unit) => result<string, error>
|
||||||
|
|
||||||
let truncate: (
|
let truncate: (
|
||||||
t,
|
t,
|
||||||
|
|
|
@ -3,6 +3,7 @@ type genericDist =
|
||||||
| SampleSet(SampleSet.t)
|
| SampleSet(SampleSet.t)
|
||||||
| Symbolic(SymbolicDistTypes.symbolicDist)
|
| Symbolic(SymbolicDistTypes.symbolicDist)
|
||||||
|
|
||||||
|
@genType
|
||||||
type error =
|
type error =
|
||||||
| NotYetImplemented
|
| NotYetImplemented
|
||||||
| Unreachable
|
| Unreachable
|
||||||
|
@ -53,8 +54,8 @@ module Operation = {
|
||||||
type toFloatArray = Sample(int)
|
type toFloatArray = Sample(int)
|
||||||
|
|
||||||
type toString =
|
type toString =
|
||||||
| ToString
|
| ToString
|
||||||
| ToSparkline(int)
|
| ToSparkline(int)
|
||||||
|
|
||||||
type fromDist =
|
type fromDist =
|
||||||
| ToFloat(toFloat)
|
| ToFloat(toFloat)
|
||||||
|
@ -66,6 +67,7 @@ module Operation = {
|
||||||
| FromDist(fromDist)
|
| FromDist(fromDist)
|
||||||
| FromFloat(fromDist)
|
| FromFloat(fromDist)
|
||||||
|
|
||||||
|
@genType
|
||||||
type genericFunctionCallInfo =
|
type genericFunctionCallInfo =
|
||||||
| FromDist(fromDist, genericDist)
|
| FromDist(fromDist, genericDist)
|
||||||
| FromFloat(fromDist, float)
|
| FromFloat(fromDist, float)
|
||||||
|
@ -95,3 +97,79 @@ module Operation = {
|
||||||
| Mixture(_) => `mixture`
|
| Mixture(_) => `mixture`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
It can be a pain to write out the genericFunctionCallInfo. The constructors help with this.
|
||||||
|
This code only covers some of genericFunctionCallInfo: many arguments could be called with either a
|
||||||
|
float or a distribution. The "UsingDists" module assumes that everything is a distribution.
|
||||||
|
This is a tradeoff of some generality in order to get a bit more simplicity.
|
||||||
|
I could see having a longer interface in the future, but it could be messy.
|
||||||
|
Like, algebraicAddDistFloat vs. algebraicAddDistDist
|
||||||
|
*/
|
||||||
|
module Constructors = {
|
||||||
|
type t = Operation.genericFunctionCallInfo
|
||||||
|
|
||||||
|
module UsingDists = {
|
||||||
|
@genType
|
||||||
|
let mean = (dist): t => FromDist(ToFloat(#Mean), dist)
|
||||||
|
let sample = (dist): t => FromDist(ToFloat(#Sample), dist)
|
||||||
|
let cdf = (dist, x): t => FromDist(ToFloat(#Cdf(x)), dist)
|
||||||
|
let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist)
|
||||||
|
let pdf = (dist, x): t => FromDist(ToFloat(#Pdf(x)), dist)
|
||||||
|
let normalize = (dist): t => FromDist(ToDist(Normalize), dist)
|
||||||
|
let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist)
|
||||||
|
let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist)
|
||||||
|
let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist)
|
||||||
|
let inspect = (dist): t => FromDist(ToDist(Inspect), dist)
|
||||||
|
let toString = (dist): t => FromDist(ToString(ToString), dist)
|
||||||
|
let toSparkline = (dist, n): t => FromDist(ToString(ToSparkline(n)), dist)
|
||||||
|
let algebraicAdd = (dist1, dist2: genericDist): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Add, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let algebraicMultiply = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Multiply, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let algebraicDivide = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Divide, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let algebraicSubtract = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Subtract, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let algebraicLogarithm = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Logarithm, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let algebraicExponentiate = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Algebraic, #Exponentiate, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseAdd = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Add, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseMultiply = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Multiply, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseDivide = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Divide, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseSubtract = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Subtract, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseLogarithm = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
let pointwiseExponentiate = (dist1, dist2): t => FromDist(
|
||||||
|
ToDistCombination(Pointwise, #Exponentiate, #Dist(dist2)),
|
||||||
|
dist1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -249,6 +249,9 @@ module T = Dist({
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let downsampleEquallyOverX = (length, t): t =>
|
||||||
|
t |> shapeMap(XYShape.XsConversion.proportionEquallyOverX(length))
|
||||||
|
|
||||||
/* This simply creates multiple copies of the continuous distribution, scaled and shifted according to
|
/* This simply creates multiple copies of the continuous distribution, scaled and shifted according to
|
||||||
each discrete data point, and then adds them all together. */
|
each discrete data point, and then adds them all together. */
|
||||||
let combineAlgebraicallyWithDiscrete = (
|
let combineAlgebraicallyWithDiscrete = (
|
||||||
|
|
|
@ -203,7 +203,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float =>
|
||||||
| #Mean => T.mean(s)
|
| #Mean => T.mean(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
let toSparkline = (t: t) =>
|
let toSparkline = (t: t, bucketCount) =>
|
||||||
T.toContinuous(t)
|
T.toContinuous(t)
|
||||||
|
->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount))
|
||||||
->E.O2.toResult("toContinous Error: Could not convert into continuous distribution")
|
->E.O2.toResult("toContinous Error: Could not convert into continuous distribution")
|
||||||
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
|
@ -1,3 +1,4 @@
|
||||||
|
@genType
|
||||||
type t = array<float>
|
type t = array<float>
|
||||||
|
|
||||||
// TODO: Refactor to raise correct error when not enough samples
|
// TODO: Refactor to raise correct error when not enough samples
|
||||||
|
@ -59,6 +60,7 @@ module Internals = {
|
||||||
: {
|
: {
|
||||||
let _ = Js.Array.push(element, continuous)
|
let _ = Js.Array.push(element, continuous)
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
})
|
})
|
||||||
(continuous, discrete)
|
(continuous, discrete)
|
||||||
|
@ -143,3 +145,25 @@ let toPointSetDist = (
|
||||||
|
|
||||||
samplesParse
|
samplesParse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Randomly get one sample from the distribution
|
||||||
|
let sample = (t: t): float => {
|
||||||
|
let i = E.Int.random(~min=0, ~max=E.A.length(t) - 1)
|
||||||
|
E.A.unsafe_get(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If asked for a length of samples shorter or equal the length of the distribution,
|
||||||
|
return this first n samples of this distribution.
|
||||||
|
Else, return n random samples of the distribution.
|
||||||
|
The former helps in cases where multiple distributions are correlated.
|
||||||
|
However, if n > length(t), then there's no clear right answer, so we just randomly
|
||||||
|
sample everything.
|
||||||
|
*/
|
||||||
|
let sampleN = (t: t, n) => {
|
||||||
|
if n <= E.A.length(t) {
|
||||||
|
E.A.slice(t, ~offset=0, ~len=n)
|
||||||
|
} else {
|
||||||
|
Belt.Array.makeBy(n, _ => sample(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
24
packages/squiggle-lang/src/rescript/TypescriptInterface.res
Normal file
24
packages/squiggle-lang/src/rescript/TypescriptInterface.res
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
This is meant as a file to contain @genType declarations as needed for Typescript.
|
||||||
|
I would ultimately want to have all @genType declarations here, vs. other files, but
|
||||||
|
@genType doesn't play as nicely with renaming Modules and functions as
|
||||||
|
would be preferable.
|
||||||
|
|
||||||
|
The below few seem to work fine. In the future there's definitely more work to do here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type env = DistributionOperation.env
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type genericDist = GenericDist_Types.genericDist
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type error = GenericDist_Types.error
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type resultDist = result<genericDist, error>
|
||||||
|
@genType
|
||||||
|
type resultFloat = result<float, error>
|
||||||
|
@genType
|
||||||
|
type resultString = result<string, error>
|
|
@ -24,6 +24,7 @@ module FloatFloatMap = {
|
||||||
|
|
||||||
module Int = {
|
module Int = {
|
||||||
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
||||||
|
let random = (~min, ~max) => Js.Math.random_int(min, max)
|
||||||
}
|
}
|
||||||
/* Utils */
|
/* Utils */
|
||||||
module U = {
|
module U = {
|
||||||
|
@ -277,6 +278,7 @@ module A = {
|
||||||
let fold_right = Array.fold_right
|
let fold_right = Array.fold_right
|
||||||
let concatMany = Belt.Array.concatMany
|
let concatMany = Belt.Array.concatMany
|
||||||
let keepMap = Belt.Array.keepMap
|
let keepMap = Belt.Array.keepMap
|
||||||
|
let slice = Belt.Array.slice
|
||||||
let init = Array.init
|
let init = Array.init
|
||||||
let reduce = Belt.Array.reduce
|
let reduce = Belt.Array.reduce
|
||||||
let reducei = Belt.Array.reduceWithIndex
|
let reducei = Belt.Array.reduceWithIndex
|
||||||
|
|
Loading…
Reference in New Issue
Block a user