diff --git a/packages/squiggle-lang/__tests__/JS__Test.ts b/packages/squiggle-lang/__tests__/JS__Test.ts index aded69c1..51f21818 100644 --- a/packages/squiggle-lang/__tests__/JS__Test.ts +++ b/packages/squiggle-lang/__tests__/JS__Test.ts @@ -1,34 +1,16 @@ -import { run } from '../src/js/index'; +import { run, exportToString } from '../src/js/index'; -let testRun = (x: string) => { - let result = run(x) - if(result.tag == 'Ok'){ - return { tag: 'Ok', value: result.value.exports } - } - else { - return result - } -} +let testRun = (expression: string): string => exportToString(run(expression)[0]) + +let runTest = (expression: string, expected: string) => test(expression, () => expect(testRun(expression)).toEqual(expected)) + +let runErrorTest = (expression: string, expected: string) => test(`${expression} will error`, () => expect(() => testRun(expression)).toThrowError(expected)) 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 } ] }) - }) -}) -describe("Log function", () => { - test("log(1) = 0", () => { - let foo = testRun("log(1)") - expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]}) - }) + runTest("mean(normal(5,2))", "5") + runTest("10 + 10", "20") }) -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" }) - }) -}); +describe("Log function", () => { + runTest("log(1)", "0") +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 2fd2a976..1bb26e28 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -4,7 +4,7 @@ open Jest open Expect let expectEvalToBe = (expr: string, answer: string) => - Reducer.eval(expr)->ExpressionValue.toStringResult->expect->toBe(answer) + Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) describe("builtin", () => { // All MathJs operators and functions are available for string, number and boolean diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 7029e2ff..7e00068b 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -8,7 +8,7 @@ let expectParseToBe = (expr: string, answer: string) => Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer) let expectEvalToBe = (expr: string, answer: string) => - Reducer.eval(expr)->ExpressionValue.toStringResult->expect->toBe(answer) + Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) // Current configuration does not ignore this file so we have to have a test test("test helpers", () => expect(1)->toBe(1)) diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index e936eb82..173ab3c7 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -33,7 +33,9 @@ "gentypeconfig": { "language": "typescript", "module": "commonjs", - "shims": {}, + "shims": { + "Js": "Js" + }, "debug": { "all": false, "basic": false diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 7856ef6f..3a11ef0f 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -1,7 +1,12 @@ -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 * as _ from 'lodash'; +import {evaluate} from '../rescript/Reducer/Reducer.gen'; +import type { expressionValue } from '../rescript/Reducer/Reducer_Expression/Reducer_Expression.gen'; +import type { pointSetDist } from '../rescript/Distributions/PointSetDist/PointSetTypes.gen'; +import type { genericDist } from '../rescript/Distributions/GenericDist/GenericDist_Types.gen'; +import { errorToString } from '../rescript/Reducer/Reducer_ErrorValue.gen'; +import { toPointSet, inv } from '../rescript/Distributions/GenericDist/GenericDist.gen'; +import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportDistribution} from '../rescript/ProgramEvaluator.gen'; +export type { SamplingInputs, exportEnv, exportDistribution, tsExport } export let defaultSamplingInputs : SamplingInputs = { sampleCount : 10000, @@ -9,9 +14,140 @@ export let defaultSamplingInputs : SamplingInputs = { 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) +type taggedOption = { + tag: tag, + value: value +} + +function tagOption(tag : T, value: V): taggedOption { + return { tag: tag, value: value}; +} +type tsExport = taggedOption<"string", string> | taggedOption<"symbol", string> | taggedOption<"number", number> | taggedOption<"boolean", boolean> | taggedOption<"distribution", Distribution> | taggedOption<"array", tsExport[]> | taggedOption<"record", {[key: string]: tsExport}> | taggedOption<"function", (x: number) => tsExport> + +// This is here mainly for testing purposes +export function exportToString(result : tsExport) : string{ + if(result.tag === "string"){ + return `"${result.value}"` + } + else if(result.tag === "boolean"){ + return `${result.value}` + } + else if(result.tag === "array"){ + return `[${result.value.map(exportToString).join(", ")}]` + } + else if(result.tag === "distribution"){ + return result.value.toString() + } + else if(result.tag === "number"){ + return `${result.value}` + } + else if(result.tag === "symbol"){ + return `${result.value}` + } + else if(result.tag === "record"){ + return `${_.mapValues(result.value, exportToString)}` + } +} + +function expressionValueToValue(value : expressionValue, samplingInputs: SamplingInputs) : tsExport { + if(value.tag == "EvArray"){ + return tagOption("array", value.value.map((val) => expressionValueToValue(val,samplingInputs))); + }else if (value.tag == "EvBool"){ + return tagOption("boolean", value.value) + } + else if(value.tag == "EvDistribution"){ + return tagOption("distribution", new Distribution(value.value, samplingInputs)); + } + else if(value.tag == "EvNumber"){ + return tagOption("number", value.value); + } + else if(value.tag == "EvString"){ + return tagOption("string", value.value); + } + else if(value.tag == "EvSymbol"){ + return tagOption("symbol", value.value); + } + else if(value.tag == "EvRecord"){ + return tagOption("record", _.mapValues(value.value, (val) => expressionValueToValue(val, samplingInputs))); + } +} + +export function run(squiggleString : string, samplingInputs : SamplingInputs = defaultSamplingInputs, _environment?: exportEnv): tsExport[] { + let result = evaluate(squiggleString); + if(result.tag == "Ok"){ + return [expressionValueToValue(result.value, samplingInputs)]; + } + else{ + throw Error(errorToString(result.value)); + } +} + +class Distribution { + dist: genericDist + samplingInputs : SamplingInputs + constructor(dist : genericDist, samplingInputs: SamplingInputs){ + this.dist = dist; + this.samplingInputs = samplingInputs; + } + + pointShape() { + let pointSet = toPointSet({xyPointLength: this.samplingInputs.outputXYPoints, sampleCount: this.samplingInputs.sampleCount}, this.dist) + if(pointSet.tag == "Ok"){ + return new Shape(pointSet.value); + } + } + + inv(x: number): number{ + let result= inv(this.dist, x) + if (result.tag == "Ok") { + return result.value; + } + else { + throw Error(result.value.toString()) + } + } + + toString(): string { + return "Todo" + } +} + +type point = { x: number, y: number, cdf: number} +class Shape { + shape : pointSetDist + constructor(shape : pointSetDist){ + this.shape = shape; + } + + discretePoints(): point[]{ + let discreteShape = undefined; + if(this.shape.tag == "Discrete"){ + discreteShape = this.shape.value; + } else if (this.shape.tag == "Mixed"){ + discreteShape = this.shape.value.discrete; + } + if(discreteShape !== undefined) { + return _.zipWith(discreteShape.xyShape.xs, discreteShape.xyShape.ys, discreteShape.integralCache.xyShape.ys, (x, y, c) => ({x, y, cdf: c})) + } + else { + return [] + } + } + + continuousPoints(): point[]{ + let continuousShape = undefined; + console.log(this.shape.tag) + if(this.shape.tag == "Continuous"){ + continuousShape = this.shape.value; + } else if (this.shape.tag == "Mixed"){ + continuousShape = this.shape.value.continuous; + } + if(continuousShape !== undefined) { + return _.zipWith(continuousShape.xyShape.xs, continuousShape.xyShape.ys, continuousShape.integralCache.xyShape.ys, (x, y, c) => ({x, y, cdf: c})) + } + else { + return [] + } + } + } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index f71d9b93..d5b3c1a0 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -13,6 +13,13 @@ let sampleN = (t: t, n) => | SampleSet(_) => Error(GenericDist_Types.NotYetImplemented) } +let inv = (t: t, x: float): result => + switch t { + | PointSet(r) => Ok(PointSetDist.inv(x, r)) + | Symbolic(r) => Ok(SymbolicDist.T.inv(x, r)) + | SampleSet(_) => Error(GenericDist_Types.NotYetImplemented) + } + let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) let toString = (t: t) => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index 46db83a7..7e7825e8 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -7,6 +7,9 @@ type pointwiseAddFn = (t, t) => result let sampleN: (t, int) => result, error> +@genType +let inv : (t, float) => result + let fromFloat: float => t let toString: t => string @@ -19,6 +22,7 @@ let toFloatOperation: ( ~distToFloatOperation: Operation.distToFloatOperation, ) => result +@genType let toPointSet: ( ~xyPointLength: int, ~sampleCount: int, diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index df7549bb..32666b5e 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -1,8 +1,10 @@ +@genType type genericDist = | PointSet(PointSetTypes.pointSetDist) | SampleSet(SampleSet.t) | Symbolic(SymbolicDistTypes.symbolicDist) +@genType type error = | NotYetImplemented | Unreachable diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index bc5f496d..6e8dbdfa 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -5,5 +5,5 @@ module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs -let eval = Expression.eval +let evaluate = Expression.eval let parse = Expression.parse diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 65b2a62a..c6c3e1e2 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -1,8 +1,11 @@ module Dispatch = Reducer_Dispatch +@genType module ErrorValue = Reducer_ErrorValue +@genType module Expression = Reducer_Expression module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs -let eval: string => result +@genType +let evaluate: string => result let parse: string => result diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 4f57bc2c..d0c85d59 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -1,3 +1,4 @@ +@genType type errorValue = | REArrayIndexNotFound(string, int) | REFunctionExpected(string) @@ -7,6 +8,7 @@ type errorValue = type t = errorValue +@genType let errorToString = err => switch err { | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}` diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi index 8b09c516..2a6db9bd 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi @@ -1,7 +1,8 @@ module Result = Belt.Result module T = Reducer_Expression_T type expression = T.expression -type expressionValue = ReducerInterface.ExpressionValue.expressionValue +@genType +type expressionValue = ReducerInterface_ExpressionValue.expressionValue type t = expression let toString: T.expression => Js.String.t let toStringResult: result => string diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index bfb79df1..8842ce8f 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -5,6 +5,7 @@ module Extra_Array = Reducer_Extra_Array module ErrorValue = Reducer_ErrorValue +@genType type rec expressionValue = | EvBool(bool) | EvNumber(float) diff --git a/packages/squiggle-lang/src/rescript/shims/Js.shim.ts b/packages/squiggle-lang/src/rescript/shims/Js.shim.ts new file mode 100644 index 00000000..edb17d3c --- /dev/null +++ b/packages/squiggle-lang/src/rescript/shims/Js.shim.ts @@ -0,0 +1 @@ +export type Dict_t = {[key: string]: T}