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 result = run(x)
|
||||
if(result.tag == 'Ok'){
|
||||
return { tag: 'Ok', value: result.value.exports }
|
||||
let result = run(x);
|
||||
if (result.tag == "Ok") {
|
||||
return { tag: "Ok", value: result.value.exports };
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return result
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe("Simple calculations and results", () => {
|
||||
test("mean(normal(5,2))", () => {
|
||||
expect(testRun("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] })
|
||||
})
|
||||
test("10+10", () => {
|
||||
let foo = testRun("10 + 10")
|
||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 20 } ] })
|
||||
})
|
||||
})
|
||||
test("mean(normal(5,2))", () => {
|
||||
expect(testRun("mean(normal(5,2))")).toEqual({
|
||||
tag: "Ok",
|
||||
value: [{ NAME: "Float", VAL: 5 }],
|
||||
});
|
||||
});
|
||||
test("10+10", () => {
|
||||
let foo = testRun("10 + 10");
|
||||
expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 20 }] });
|
||||
});
|
||||
});
|
||||
describe("Log function", () => {
|
||||
test("log(1) = 0", () => {
|
||||
let foo = testRun("log(1)")
|
||||
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]})
|
||||
})
|
||||
})
|
||||
test("log(1) = 0", () => {
|
||||
let foo = testRun("log(1)");
|
||||
expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 0 }] });
|
||||
});
|
||||
});
|
||||
|
||||
describe("Multimodal too many weights error", () => {
|
||||
test("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" })
|
||||
})
|
||||
test("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",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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": {
|
||||
"language": "typescript",
|
||||
"module": "commonjs",
|
||||
"shims": {},
|
||||
"shims": {"Js": "Js"},
|
||||
"debug": {
|
||||
"all": false,
|
||||
"basic": false
|
||||
|
|
|
@ -1,17 +1,223 @@
|
|||
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
||||
import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen';
|
||||
export type { SamplingInputs, exportEnv, exportDistribution }
|
||||
export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen';
|
||||
import { runAll } from "../rescript/ProgramEvaluator.gen";
|
||||
import type {
|
||||
Inputs_SamplingInputs_t as SamplingInputs,
|
||||
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 = {
|
||||
sampleCount : 10000,
|
||||
outputXYPoints : 10000,
|
||||
pointDistLength : 1000
|
||||
export let defaultSamplingInputs: SamplingInputs = {
|
||||
sampleCount: 10000,
|
||||
outputXYPoints: 10000,
|
||||
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 }
|
||||
| { tag: "Error"; value: string } {
|
||||
let si : SamplingInputs = samplingInputs ? samplingInputs : defaultSamplingInputs
|
||||
let env : exportEnv = environment ? environment : []
|
||||
return runAll(squiggleString, si, env)
|
||||
//This is clearly not fully typed. I think later we should use a functional library to
|
||||
// provide a better Either type and corresponding functions.
|
||||
type result =
|
||||
| {
|
||||
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))
|
||||
->OutputLocal.fromResult
|
||||
| ToString(ToString) => dist->GenericDist.toString->String
|
||||
| ToString(ToSparkline(buckets)) =>
|
||||
GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ())
|
||||
| ToString(ToSparkline(bucketCount)) =>
|
||||
GenericDist.toSparkline(dist, ~sampleCount, ~bucketCount, ())
|
||||
->E.R2.fmap(r => String(r))
|
||||
->OutputLocal.fromResult
|
||||
| ToDist(Inspect) => {
|
||||
|
@ -185,3 +185,44 @@ module Output = {
|
|||
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 = {
|
||||
sampleCount: int,
|
||||
xyPointLength: int,
|
||||
}
|
||||
|
||||
open GenericDist_Types
|
||||
|
||||
@genType
|
||||
type outputType =
|
||||
| Dist(GenericDist_Types.genericDist)
|
||||
| Dist(genericDist)
|
||||
| Float(float)
|
||||
| String(string)
|
||||
| GenDistError(GenericDist_Types.error)
|
||||
| GenDistError(error)
|
||||
|
||||
@genType
|
||||
let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType
|
||||
let runFromDist: (
|
||||
~env: env,
|
||||
~functionCallInfo: GenericDist_Types.Operation.fromDist,
|
||||
GenericDist_Types.genericDist,
|
||||
genericDist,
|
||||
) => outputType
|
||||
let runFromFloat: (
|
||||
~env: env,
|
||||
|
@ -23,12 +28,68 @@ let runFromFloat: (
|
|||
|
||||
module Output: {
|
||||
type t = outputType
|
||||
let toDist: t => option<GenericDist_Types.genericDist>
|
||||
let toDistR: t => result<GenericDist_Types.genericDist, GenericDist_Types.error>
|
||||
let toDist: t => option<genericDist>
|
||||
let toDistR: t => result<genericDist, error>
|
||||
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 toStringR: t => result<string, GenericDist_Types.error>
|
||||
let toError: t => option<GenericDist_Types.error>
|
||||
let toStringR: t => result<string, error>
|
||||
let toError: t => option<error>
|
||||
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 {
|
||||
| PointSet(r) => Ok(PointSetDist.sampleNRendered(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))
|
||||
|
@ -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
|
||||
->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ())
|
||||
->E.R.bind(r => r->PointSetDist.toSparkline->E.R2.errMap(r => Error(GenericDist_Types.Other(r))))
|
||||
->toPointSet(~xSelection=#Linear, ~xyPointLength=bucketCount * 3, ~sampleCount, ())
|
||||
->E.R.bind(r =>
|
||||
r->PointSetDist.toSparkline(bucketCount)->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))
|
||||
)
|
||||
|
||||
module Truncate = {
|
||||
let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option<t> =>
|
||||
|
|
|
@ -26,7 +26,7 @@ let toPointSet: (
|
|||
~xSelection: GenericDist_Types.Operation.pointsetXSelection=?,
|
||||
unit,
|
||||
) => 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: (
|
||||
t,
|
||||
|
|
|
@ -3,6 +3,7 @@ type genericDist =
|
|||
| SampleSet(SampleSet.t)
|
||||
| Symbolic(SymbolicDistTypes.symbolicDist)
|
||||
|
||||
@genType
|
||||
type error =
|
||||
| NotYetImplemented
|
||||
| Unreachable
|
||||
|
@ -53,8 +54,8 @@ module Operation = {
|
|||
type toFloatArray = Sample(int)
|
||||
|
||||
type toString =
|
||||
| ToString
|
||||
| ToSparkline(int)
|
||||
| ToString
|
||||
| ToSparkline(int)
|
||||
|
||||
type fromDist =
|
||||
| ToFloat(toFloat)
|
||||
|
@ -66,6 +67,7 @@ module Operation = {
|
|||
| FromDist(fromDist)
|
||||
| FromFloat(fromDist)
|
||||
|
||||
@genType
|
||||
type genericFunctionCallInfo =
|
||||
| FromDist(fromDist, genericDist)
|
||||
| FromFloat(fromDist, float)
|
||||
|
@ -95,3 +97,79 @@ module Operation = {
|
|||
| 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
|
||||
each discrete data point, and then adds them all together. */
|
||||
let combineAlgebraicallyWithDiscrete = (
|
||||
|
|
|
@ -203,7 +203,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float =>
|
|||
| #Mean => T.mean(s)
|
||||
}
|
||||
|
||||
let toSparkline = (t: t) =>
|
||||
let toSparkline = (t: t, bucketCount) =>
|
||||
T.toContinuous(t)
|
||||
->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount))
|
||||
->E.O2.toResult("toContinous Error: Could not convert into continuous distribution")
|
||||
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
|
@ -1,3 +1,4 @@
|
|||
@genType
|
||||
type t = array<float>
|
||||
|
||||
// TODO: Refactor to raise correct error when not enough samples
|
||||
|
@ -59,6 +60,7 @@ module Internals = {
|
|||
: {
|
||||
let _ = Js.Array.push(element, continuous)
|
||||
}
|
||||
|
||||
()
|
||||
})
|
||||
(continuous, discrete)
|
||||
|
@ -143,3 +145,25 @@ let toPointSetDist = (
|
|||
|
||||
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 = {
|
||||
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
||||
let random = (~min, ~max) => Js.Math.random_int(min, max)
|
||||
}
|
||||
/* Utils */
|
||||
module U = {
|
||||
|
@ -277,6 +278,7 @@ module A = {
|
|||
let fold_right = Array.fold_right
|
||||
let concatMany = Belt.Array.concatMany
|
||||
let keepMap = Belt.Array.keepMap
|
||||
let slice = Belt.Array.slice
|
||||
let init = Array.init
|
||||
let reduce = Belt.Array.reduce
|
||||
let reducei = Belt.Array.reduceWithIndex
|
||||
|
|
Loading…
Reference in New Issue
Block a user