Added tests for index.js and fixed some corresponding functionality

This commit is contained in:
Ozzie Gooen 2022-04-08 19:48:53 -04:00
parent d62ccc27bd
commit 0af0c9e274
8 changed files with 191 additions and 147 deletions

View File

@ -1,34 +1,66 @@
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", () => {
let dist = new GenericDist(
{ tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
{ sampleCount: 100, xyPointLength: 100 }
);
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("▁▁▃▅███▆▄▃▂▁▁▂▂▃▂▁▁▁");
});
}); });

View File

@ -7,7 +7,6 @@ import type {
} from "../rescript/ProgramEvaluator.gen"; } from "../rescript/ProgramEvaluator.gen";
export type { SamplingInputs, exportEnv, exportDistribution }; export type { SamplingInputs, exportEnv, exportDistribution };
export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen"; export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen";
import type { Operation_genericFunctionCallInfo } from "../rescript/Distributions/GenericDist/GenericDist_Types.gen";
import { import {
genericDist, genericDist,
resultDist, resultDist,
@ -16,30 +15,30 @@ import {
} from "../rescript/TSInterface.gen"; } from "../rescript/TSInterface.gen";
import { import {
env, env,
Constructors_UsingDists_mean, Constructors_mean,
Constructors_UsingDists_sample, Constructors_sample,
Constructors_UsingDists_pdf, Constructors_pdf,
Constructors_UsingDists_cdf, Constructors_cdf,
Constructors_UsingDists_inv, Constructors_inv,
Constructors_UsingDists_normalize, Constructors_normalize,
Constructors_UsingDists_toPointSet, Constructors_toPointSet,
Constructors_UsingDists_toSampleSet, Constructors_toSampleSet,
Constructors_UsingDists_truncate, Constructors_truncate,
Constructors_UsingDists_inspect, Constructors_inspect,
Constructors_UsingDists_toString, Constructors_toString,
Constructors_UsingDists_toSparkline, Constructors_toSparkline,
Constructors_UsingDists_algebraicAdd, Constructors_algebraicAdd,
Constructors_UsingDists_algebraicMultiply, Constructors_algebraicMultiply,
Constructors_UsingDists_algebraicDivide, Constructors_algebraicDivide,
Constructors_UsingDists_algebraicSubtract, Constructors_algebraicSubtract,
Constructors_UsingDists_algebraicLogarithm, Constructors_algebraicLogarithm,
Constructors_UsingDists_algebraicExponentiate, Constructors_algebraicExponentiate,
Constructors_UsingDists_pointwiseAdd, Constructors_pointwiseAdd,
Constructors_UsingDists_pointwiseMultiply, Constructors_pointwiseMultiply,
Constructors_UsingDists_pointwiseDivide, Constructors_pointwiseDivide,
Constructors_UsingDists_pointwiseSubtract, Constructors_pointwiseSubtract,
Constructors_UsingDists_pointwiseLogarithm, Constructors_pointwiseLogarithm,
Constructors_UsingDists_pointwiseExponentiate, Constructors_pointwiseExponentiate,
} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen";
export let defaultSamplingInputs: SamplingInputs = { export let defaultSamplingInputs: SamplingInputs = {
@ -60,160 +59,172 @@ export function run(
return runAll(squiggleString, si, env); return runAll(squiggleString, si, env);
} }
class GenericDist { export function resultMap(
r:
| {
tag: "Ok";
value: any;
}
| {
tag: "Error";
value: any;
},
mapFn: any
):
| {
tag: "Ok";
value: any;
}
| {
tag: "Error";
value: any;
} {
if (r.tag === "Ok") {
return { tag: "Ok", value: mapFn(r.value) };
} else {
return r;
}
}
export class GenericDist {
t: genericDist; t: genericDist;
env: env; env: env;
constructor(t: genericDist, env: env) { constructor(t: genericDist, env: env) {
this.t = t; this.t = t;
this.env = env;
return this;
} }
mean(): resultFloat { mapResultDist(r: resultDist) {
return Constructors_UsingDists_mean({ env: this.env }, this.t); return resultMap(r, (v: genericDist) => new GenericDist(v, this.env));
}
mean() {
return Constructors_mean({ env: this.env }, this.t);
} }
sample(): resultFloat { sample(): resultFloat {
return Constructors_UsingDists_sample({ env: this.env }, this.t); return Constructors_sample({ env: this.env }, this.t);
} }
pdf(n: number): resultFloat { pdf(n: number): resultFloat {
return Constructors_UsingDists_pdf({ env: this.env }, this.t, n); return Constructors_pdf({ env: this.env }, this.t, n);
} }
cdf(n: number): resultFloat { cdf(n: number): resultFloat {
return Constructors_UsingDists_cdf({ env: this.env }, this.t, n); return Constructors_cdf({ env: this.env }, this.t, n);
} }
inv(n: number): resultFloat { inv(n: number): resultFloat {
return Constructors_UsingDists_inv({ env: this.env }, this.t, n); return Constructors_inv({ env: this.env }, this.t, n);
} }
normalize(): resultDist { normalize() {
return Constructors_UsingDists_normalize({ env: this.env }, this.t); return this.mapResultDist(
} Constructors_normalize({ env: this.env }, this.t)
toPointSet(): resultDist {
return Constructors_UsingDists_toPointSet({ env: this.env }, this.t);
}
toSampleSet(n: number): resultDist {
return Constructors_UsingDists_toSampleSet({ env: this.env }, this.t, n);
}
truncate(left: number, right: number): resultDist {
return Constructors_UsingDists_truncate(
{ env: this.env },
this.t,
left,
right
); );
} }
inspect(): resultDist { toPointSet() {
return Constructors_UsingDists_inspect({ env: this.env }, this.t); 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 { toString(): resultString {
return Constructors_UsingDists_toString({ env: this.env }, this.t); return Constructors_toString({ env: this.env }, this.t);
} }
toSparkline(n: number): resultString { toSparkline(n: number): resultString {
return Constructors_UsingDists_toSparkline({ env: this.env }, this.t, n); return Constructors_toSparkline({ env: this.env }, this.t, n);
} }
algebraicAdd(d2: GenericDist): resultDist { algebraicAdd(d2: GenericDist) {
return Constructors_UsingDists_algebraicAdd( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
algebraicMultiply(d2: GenericDist): resultDist { algebraicMultiply(d2: GenericDist) {
return Constructors_UsingDists_algebraicMultiply( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
algebraicDivide(d2: GenericDist): resultDist { algebraicDivide(d2: GenericDist) {
return Constructors_UsingDists_algebraicDivide( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
algebraicSubtract(d2: GenericDist): resultDist { algebraicSubtract(d2: GenericDist) {
return Constructors_UsingDists_algebraicSubtract( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
algebraicLogarithm(d2: GenericDist): resultDist { algebraicLogarithm(d2: GenericDist) {
return Constructors_UsingDists_algebraicLogarithm( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
algebraicExponentiate(d2: GenericDist): resultDist { algebraicExponentiate(d2: GenericDist) {
return Constructors_UsingDists_algebraicExponentiate( return this.mapResultDist(
{ env: this.env }, Constructors_algebraicExponentiate({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseAdd(d2: GenericDist): resultDist { pointwiseAdd(d2: GenericDist) {
return Constructors_UsingDists_pointwiseAdd( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseMultiply(d2: GenericDist): resultDist { pointwiseMultiply(d2: GenericDist) {
return Constructors_UsingDists_pointwiseMultiply( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseDivide(d2: GenericDist): resultDist { pointwiseDivide(d2: GenericDist) {
return Constructors_UsingDists_pointwiseDivide( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseSubtract(d2: GenericDist): resultDist { pointwiseSubtract(d2: GenericDist) {
return Constructors_UsingDists_pointwiseSubtract( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseLogarithm(d2: GenericDist): resultDist { pointwiseLogarithm(d2: GenericDist) {
return Constructors_UsingDists_pointwiseLogarithm( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
pointwiseExponentiate(d2: GenericDist): resultDist { pointwiseExponentiate(d2: GenericDist) {
return Constructors_UsingDists_pointwiseExponentiate( return this.mapResultDist(
{ env: this.env }, Constructors_pointwiseExponentiate({ env: this.env }, this.t, d2.t)
this.t,
d2.t
); );
} }
} }

View File

@ -187,8 +187,7 @@ module Output = {
} }
module Constructors = { module Constructors = {
module UsingDists = { module C = GenericDist_Types.Constructors.UsingDists;
module C = GenericDist_Types.Constructors.UsingDists
open OutputLocal open OutputLocal
let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR
let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR
@ -225,5 +224,4 @@ module Constructors = {
C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR
let pointwiseExponentiate = (~env, dist1, dist2) => let pointwiseExponentiate = (~env, dist1, dist2) =>
C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR
}
} }

View File

@ -39,7 +39,6 @@ module Output: {
} }
module Constructors: { module Constructors: {
module UsingDists: {
@genType @genType
let mean: (~env: env, genericDist) => result<float, error> let mean: (~env: env, genericDist) => result<float, error>
@genType @genType
@ -93,5 +92,4 @@ module Constructors: {
let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result<genericDist, error> let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result<genericDist, error>
@genType @genType
let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result<genericDist, error> let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result<genericDist, error>
}
} }

View File

@ -83,8 +83,8 @@ let toPointSet = (
let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result<string, error> => let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result<string, error> =>
t t
->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ()) ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets*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(buckets)->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> =>

View File

@ -102,6 +102,7 @@ module Constructors = {
type t = Operation.genericFunctionCallInfo type t = Operation.genericFunctionCallInfo
module UsingDists = { module UsingDists = {
@genType
let mean = (dist): t => FromDist(ToFloat(#Mean), dist) let mean = (dist): t => FromDist(ToFloat(#Mean), dist)
let sample = (dist): t => FromDist(ToFloat(#Sample), dist) let sample = (dist): t => FromDist(ToFloat(#Sample), dist)
let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist) let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist)

View File

@ -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 = (

View File

@ -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, n) =>
T.toContinuous(t) T.toContinuous(t)
->E.O2.fmap(Continuous.downsampleEquallyOverX(n))
->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())