From 0c032e710c9a12a0a170e48772630bda3bc5b4b9 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 14:01:00 -0700 Subject: [PATCH] Moved function library modules to separate files --- .../FunctionRegistry_Library.res | 915 +----------------- .../FunctionRegistry/Library/FR_Dict.res | 169 ++++ .../FunctionRegistry/Library/FR_Dist.res | 155 +++ .../FunctionRegistry/Library/FR_Fn.res | 61 ++ .../FunctionRegistry/Library/FR_List.res | 128 +++ .../FunctionRegistry/Library/FR_Number.res | 233 +++++ .../FunctionRegistry/Library/FR_Pointset.res | 55 ++ .../FunctionRegistry/Library/FR_Scoring.res | 90 ++ 8 files changed, 898 insertions(+), 908 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 5d68c7b9..949837b5 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -1,910 +1,9 @@ -open FunctionRegistry_Core -open FunctionRegistry_Helpers - -let twoArgs = E.Tuple2.toFnCall - -module Declaration = { - let frType = FRTypeRecord([ - ("fn", FRTypeLambda), - ("inputs", FRTypeArray(FRTypeRecord([("min", FRTypeNumber), ("max", FRTypeNumber)]))), - ]) - - let fromExpressionValue = (e: frValue): result => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs([e]) { - | Ok([FRValueLambda(lambda), FRValueArray(inputs)]) => { - open FunctionRegistry_Helpers.Prepare - let getMinMax = arg => - ToValueArray.Record.toArgs([arg]) - ->E.R.bind(ToValueTuple.twoNumbers) - ->E.R2.fmap(((min, max)) => Declaration.ContinuousFloatArg.make(min, max)) - inputs - ->E.A2.fmap(getMinMax) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(args => ReducerInterface_InternalExpressionValue.IEvDeclaration( - Declaration.make(lambda, args), - )) - } - | Error(r) => Error(r) - | Ok(_) => Error(FunctionRegistry_Helpers.impossibleError) - } - } -} - -module PointSet = { - let nameSpace = "PointSet" - let requiresNamespace = true - - let inputsTodist = (inputs: array, makeDist) => { - let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) - let xyCoords = - array->E.R.bind(xyCoords => - xyCoords - ->E.A2.fmap(xyCoord => - [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) - ) - ->E.A.R.firstErrorOrOpen - ) - let expressionValue = - xyCoords - ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) - ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( - PointSet(makeDist(r)), - )) - expressionValue - } - - let library = [ - Function.make( - ~name="makeContinuous", - ~nameSpace, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="makeContinuous", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), - (), - ), - ], - (), - ), - Function.make( - ~name="makeDiscrete", - ~nameSpace, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="makeDiscrete", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), - (), - ), - ], - (), - ), - ] -} - -module Functionn = { - let nameSpace = "Function" - let library = [ - Function.make( - ~name="declare", - ~nameSpace, - ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", - ~examples=[ - `declareFn({ - fn: {|a,b| a }, - inputs: [ - {min: 0, max: 100}, - {min: 30, max: 50} - ] -})`, - ], - ~isExperimental=true, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="declare", - ~inputs=[Declaration.frType], - ~run=(_, inputs, _) => { - inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) - }, - (), - ), - ], - (), - ), - ] -} - -module DistributionCreation = { - let nameSpace = "Dist" - let output = ReducerInterface_InternalExpressionValue.EvtDistribution - - let fnMake = (~name, ~examples, ~definitions) => { - Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) - } - - module TwoArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], - ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordP5P95 = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordMeanStdev = (name, fn) => { - FnDefinition.make( - ~name, - ~requiresNamespace=false, - ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - } - - module OneArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeDistOrNumber], - ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), - (), - ) - } - - let library = [ - fnMake( - ~name="normal", - ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], - ~definitions=[ - TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), - TwoArgDist.makeRecordP5P95("normal", r => - twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), - ], - ), - fnMake( - ~name="lognormal", - ~examples=[ - "lognormal(0.5, 0.8)", - "lognormal({p5: 4, p95: 10})", - "lognormal({mean: 5, stdev: 2})", - ], - ~definitions=[ - TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), - TwoArgDist.makeRecordP5P95("lognormal", r => - twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev( - "lognormal", - twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), - ), - ], - ), - fnMake( - ~name="uniform", - ~examples=[`uniform(10, 12)`], - ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], - ), - fnMake( - ~name="beta", - ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], - ~definitions=[ - TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), - TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), - ], - ), - fnMake( - ~name="cauchy", - ~examples=[`cauchy(5, 1)`], - ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], - ), - fnMake( - ~name="gamma", - ~examples=[`gamma(5, 1)`], - ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], - ), - fnMake( - ~name="logistic", - ~examples=[`logistic(5, 1)`], - ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], - ), - fnMake( - ~name="to (distribution)", - ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], - ~definitions=[ - TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), - TwoArgDist.make( - "credibleIntervalToDistribution", - twoArgs(SymbolicDist.From90thPercentile.make), - ), - ], - ), - fnMake( - ~name="exponential", - ~examples=[`exponential(2)`], - ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], - ), - fnMake( - ~name="bernoulli", - ~examples=[`bernoulli(0.5)`], - ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], - ), - fnMake( - ~name="pointMass", - ~examples=[`pointMass(0.5)`], - ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], - ), - ] -} - -module Number = { - let nameSpace = "Number" - let requiresNamespace = false - - module NumberToNumber = { - let make = (name, fn) => - FnDefinition.make( - ~requiresNamespace, - ~name, - ~inputs=[FRTypeNumber], - ~run=(_, inputs, _) => { - inputs - ->getOrError(0) - ->E.R.bind(Prepare.oneNumber) - ->E.R2.fmap(fn) - ->E.R2.fmap(Wrappers.evNumber) - }, - (), - ) - } - - module ArrayNumberDist = { - let make = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeArray(FRTypeNumber)], - ~run=(_, inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } - let make2 = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(_, inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } - } - - let library = [ - Function.make( - ~name="floor", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`floor(3.5)`], - ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], - (), - ), - Function.make( - ~name="ceiling", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`ceiling(3.5)`], - ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], - (), - ), - Function.make( - ~name="absolute value", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`abs(3.5)`], - ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], - (), - ), - Function.make( - ~name="exponent", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`exp(3.5)`], - ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], - (), - ), - Function.make( - ~name="log", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log(3.5)`], - ~definitions=[NumberToNumber.make("log", Js.Math.log)], - (), - ), - Function.make( - ~name="log base 10", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log10(3.5)`], - ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], - (), - ), - Function.make( - ~name="log base 2", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log2(3.5)`], - ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], - (), - ), - Function.make( - ~name="round", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`round(3.5)`], - ~definitions=[NumberToNumber.make("round", Js.Math.round)], - (), - ), - Function.make( - ~name="sum", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`sum([3,5,2])`], - ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="product", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`product([3,5,2])`], - ~definitions=[ - ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="min", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`min([3,5,2])`], - ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="max", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`max([3,5,2])`], - ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="mean", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`mean([3,5,2])`], - ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="geometric mean", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`geomean([3,5,2])`], - ~definitions=[ - ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="standard deviation", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`stdev([3,5,2,3,5])`], - ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="variance", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`variance([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="sort", - ~nameSpace, - ~output=EvtArray, - ~examples=[`sort([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("sort", r => - r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="cumulative sum", - ~nameSpace, - ~output=EvtArray, - ~examples=[`cumsum([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("cumsum", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="cumulative prod", - ~nameSpace, - ~output=EvtArray, - ~examples=[`cumprod([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("cumprod", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="diff", - ~nameSpace, - ~output=EvtArray, - ~examples=[`diff([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("diff", r => - r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - ] -} - -module Dict = { - let nameSpace = "Dict" - module Internals = { - type t = ReducerInterface_InternalExpressionValue.map - - let keys = (a: t): internalExpressionValue => IEvArray( - Belt.Map.String.keysToArray(a)->E.A2.fmap(Wrappers.evString), - ) - - let values = (a: t): internalExpressionValue => IEvArray(Belt.Map.String.valuesToArray(a)) - - let toList = (a: t): internalExpressionValue => - Belt.Map.String.toArray(a) - ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) - ->Wrappers.evArray - - let fromList = (items: array): result< - internalExpressionValue, - string, - > => - items - ->E.A2.fmap(item => { - switch (item: internalExpressionValue) { - | IEvArray([IEvString(string), value]) => (string, value)->Ok - | _ => Error(impossibleError) - } - }) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) - - let merge = (a: t, b: t): internalExpressionValue => IEvRecord( - Belt.Map.String.merge(a, b, (_, _, c) => c), - ) - - //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. - let mergeMany = (a: array): internalExpressionValue => { - let mergedValues = - a->E.A2.fmap(Belt.Map.String.toArray)->Belt.Array.concatMany->Belt.Map.String.fromArray - IEvRecord(mergedValues) - } - } - - let library = [ - Function.make( - ~name="merge", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="merge", - ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => { - switch inputs { - | [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - //TODO: Change to use new mergeMany() function. - Function.make( - ~name="mergeMany", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="mergeMany", - ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], - ~run=(_, inputs, _) => - inputs - ->Prepare.ToTypedArray.dicts - ->E.R2.fmap(E.Dict.concatMany) - ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) - ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord), - (), - ), - ], - (), - ), - Function.make( - ~name="keys", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.keys({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="keys", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(d1)] => Internals.keys(d1)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="values", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.values({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="values", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(d1)] => Internals.values(d1)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="toList", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.toList({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="toList", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(dict)] => dict->Internals.toList->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="fromList", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.fromList({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="fromList", - ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(items)] => Internals.fromList(items) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - ] -} - -module List = { - let nameSpace = "List" - let requiresNamespace = true - - module Internals = { - let makeFromNumber = ( - n: float, - value: internalExpressionValue, - ): internalExpressionValue => IEvArray(Belt.Array.make(E.Float.toInt(n), value)) - - let upTo = (low: float, high: float): internalExpressionValue => IEvArray( - E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt)->E.A2.fmap( - Wrappers.evNumber, - ), - ) - - let first = (v: array): result => - v->E.A.first |> E.O.toResult("No first element") - - let last = (v: array): result => - v->E.A.last |> E.O.toResult("No last element") - - let reverse = (array: array): internalExpressionValue => IEvArray( - Belt.Array.reverse(array), - ) - } - - let library = [ - Function.make( - ~name="make", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.make(2, "testValue")`], - ~definitions=[ - //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. - FnDefinition.make( - ~requiresNamespace, - ~name="make", - ~inputs=[FRTypeNumber, FRTypeAny], - ~run=(inputs, _, _) => { - switch inputs { - | [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - Function.make( - ~name="upTo", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.upTo(1,4)`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="upTo", - ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - inputs - ->Prepare.ToValueTuple.twoNumbers - ->E.R2.fmap(((low, high)) => Internals.upTo(low, high)), - (), - ), - ], - (), - ), - Function.make( - ~name="first", - ~nameSpace, - ~examples=[`List.first([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="first", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.first(array) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="last", - ~nameSpace, - ~examples=[`List.last([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=false, - ~name="last", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.last(array) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="reverse", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.reverse([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=false, - ~name="reverse", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.reverse(array)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - ] -} - -module Scoring = { - let nameSpace = "Dist" - let requiresNamespace = false - - let runScoring = (estimate, answer, prior, env) => { - GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) - ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) - ->E.R2.errMap(DistributionTypes.Error.toString) - } - - let library = [ - Function.make( - ~name="logScore", - ~nameSpace, - ~output=EvtNumber, - ~examples=[ - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", - "Dist.logScore({estimate: normal(5,2), answer: 4.5})", - ], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="logScore", - ~inputs=[ - FRTypeRecord([ - ("estimate", FRTypeDist), - ("answer", FRTypeDistOrNumber), - ("prior", FRTypeDist), - ]), - ], - ~run=(_, inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { - | Ok([ - FRValueDist(estimate), - FRValueDistOrNumber(FRValueDist(d)), - FRValueDist(prior), - ]) => - runScoring(estimate, Score_Dist(d), Some(prior), env) - | Ok([ - FRValueDist(estimate), - FRValueDistOrNumber(FRValueNumber(d)), - FRValueDist(prior), - ]) => - runScoring(estimate, Score_Scalar(d), Some(prior), env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - FnDefinition.make( - ~name="logScore", - ~requiresNamespace, - ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => - runScoring(estimate, Score_Dist(d), None, env) - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => - runScoring(estimate, Score_Scalar(d), None, env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - ], - (), - ), - Function.make( - ~name="klDivergence", - ~nameSpace, - ~output=EvtNumber, - ~examples=[ - "Dist.klDivergence(normal(5,2), normal(5,1.5)", - ], - ~definitions=[ - FnDefinition.make( - ~name="klDivergence", - ~requiresNamespace, - ~inputs=[FRTypeDist, FRTypeDist], - ~run=(_, inputs, env) => { - switch inputs { - | [FRValueDist(estimate), FRValueDist(d)] => - runScoring(estimate, Score_Dist(d), None, env) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - ], - (), - ), - ] -} - let registry = Belt.Array.concatMany([ - PointSet.library, - Functionn.library, - Number.library, - Dict.library, - List.library, - DistributionCreation.library, - Scoring.library, + FR_Dict.library, + FR_Dist.library, + FR_Fn.library, + FR_List.library, + FR_Number.library, + FR_Pointset.library, + FR_Scoring.library ]) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res new file mode 100644 index 00000000..c8d28a78 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res @@ -0,0 +1,169 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "Dict" + +module Internals = { + type t = ReducerInterface_InternalExpressionValue.map + + let keys = (a: t): internalExpressionValue => IEvArray( + Belt.Map.String.keysToArray(a)->E.A2.fmap(Wrappers.evString), + ) + + let values = (a: t): internalExpressionValue => IEvArray(Belt.Map.String.valuesToArray(a)) + + let toList = (a: t): internalExpressionValue => + Belt.Map.String.toArray(a) + ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) + ->Wrappers.evArray + + let fromList = (items: array): result => + items + ->E.A2.fmap(item => { + switch (item: internalExpressionValue) { + | IEvArray([IEvString(string), value]) => (string, value)->Ok + | _ => Error(impossibleError) + } + }) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord) + + let merge = (a: t, b: t): internalExpressionValue => IEvRecord( + Belt.Map.String.merge(a, b, (_, _, c) => c), + ) + + //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. + let mergeMany = (a: array): internalExpressionValue => { + let mergedValues = + a->E.A2.fmap(Belt.Map.String.toArray)->Belt.Array.concatMany->Belt.Map.String.fromArray + IEvRecord(mergedValues) + } +} + +let library = [ + Function.make( + ~name="merge", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="merge", + ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => { + switch inputs { + | [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + //TODO: Change to use new mergeMany() function. + Function.make( + ~name="mergeMany", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="mergeMany", + ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], + ~run=(_, inputs, _) => + inputs + ->Prepare.ToTypedArray.dicts + ->E.R2.fmap(E.Dict.concatMany) + ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) + ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord), + (), + ), + ], + (), + ), + Function.make( + ~name="keys", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.keys({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="keys", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(d1)] => Internals.keys(d1)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="values", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.values({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="values", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(d1)] => Internals.values(d1)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="toList", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.toList({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="toList", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(dict)] => dict->Internals.toList->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="fromList", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.fromList({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="fromList", + ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(items)] => Internals.fromList(items) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res new file mode 100644 index 00000000..35e17dd3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res @@ -0,0 +1,155 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers +let twoArgs = E.Tuple2.toFnCall + +module DistributionCreation = { + let nameSpace = "Dist" + let output = ReducerInterface_InternalExpressionValue.EvtDistribution + + let fnMake = (~name, ~examples, ~definitions) => { + Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) + } + + module TwoArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + + let makeRecordP5P95 = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + + let makeRecordMeanStdev = (name, fn) => { + FnDefinition.make( + ~name, + ~requiresNamespace=false, + ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + } + + module OneArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber], + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + (), + ) + } + + let library = [ + fnMake( + ~name="normal", + ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], + ~definitions=[ + TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.makeRecordP5P95("normal", r => + twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), + ], + ), + fnMake( + ~name="lognormal", + ~examples=[ + "lognormal(0.5, 0.8)", + "lognormal({p5: 4, p95: 10})", + "lognormal({mean: 5, stdev: 2})", + ], + ~definitions=[ + TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), + TwoArgDist.makeRecordP5P95("lognormal", r => + twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev( + "lognormal", + twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), + ), + ], + ), + fnMake( + ~name="uniform", + ~examples=[`uniform(10, 12)`], + ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], + ), + fnMake( + ~name="beta", + ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], + ~definitions=[ + TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), + TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), + ], + ), + fnMake( + ~name="cauchy", + ~examples=[`cauchy(5, 1)`], + ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], + ), + fnMake( + ~name="gamma", + ~examples=[`gamma(5, 1)`], + ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], + ), + fnMake( + ~name="logistic", + ~examples=[`logistic(5, 1)`], + ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], + ), + fnMake( + ~name="to (distribution)", + ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], + ~definitions=[ + TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), + TwoArgDist.make( + "credibleIntervalToDistribution", + twoArgs(SymbolicDist.From90thPercentile.make), + ), + ], + ), + fnMake( + ~name="exponential", + ~examples=[`exponential(2)`], + ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], + ), + fnMake( + ~name="bernoulli", + ~examples=[`bernoulli(0.5)`], + ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], + ), + fnMake( + ~name="pointMass", + ~examples=[`pointMass(0.5)`], + ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], + ), + ] +} + +let library = DistributionCreation.library \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res new file mode 100644 index 00000000..b30cac2d --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res @@ -0,0 +1,61 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +module Declaration = { + let frType = FRTypeRecord([ + ("fn", FRTypeLambda), + ("inputs", FRTypeArray(FRTypeRecord([("min", FRTypeNumber), ("max", FRTypeNumber)]))), + ]) + + let fromExpressionValue = (e: frValue): result => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs([e]) { + | Ok([FRValueLambda(lambda), FRValueArray(inputs)]) => { + open FunctionRegistry_Helpers.Prepare + let getMinMax = arg => + ToValueArray.Record.toArgs([arg]) + ->E.R.bind(ToValueTuple.twoNumbers) + ->E.R2.fmap(((min, max)) => Declaration.ContinuousFloatArg.make(min, max)) + inputs + ->E.A2.fmap(getMinMax) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(args => ReducerInterface_InternalExpressionValue.IEvDeclaration( + Declaration.make(lambda, args), + )) + } + | Error(r) => Error(r) + | Ok(_) => Error(FunctionRegistry_Helpers.impossibleError) + } + } +} + +let nameSpace = "Function" + +let library = [ + Function.make( + ~name="declare", + ~nameSpace, + ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", + ~examples=[ + `declareFn({ + fn: {|a,b| a }, + inputs: [ + {min: 0, max: 100}, + {min: 30, max: 50} + ] +})`, + ], + ~isExperimental=true, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="declare", + ~inputs=[Declaration.frType], + ~run=(_, inputs, _) => { + inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res new file mode 100644 index 00000000..9c064966 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res @@ -0,0 +1,128 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "List" +let requiresNamespace = true + +module Internals = { + let makeFromNumber = ( + n: float, + value: internalExpressionValue, + ): internalExpressionValue => IEvArray(Belt.Array.make(E.Float.toInt(n), value)) + + let upTo = (low: float, high: float): internalExpressionValue => IEvArray( + E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt)->E.A2.fmap(Wrappers.evNumber), + ) + + let first = (v: array): result => + v->E.A.first |> E.O.toResult("No first element") + + let last = (v: array): result => + v->E.A.last |> E.O.toResult("No last element") + + let reverse = (array: array): internalExpressionValue => IEvArray( + Belt.Array.reverse(array), + ) +} + +let library = [ + Function.make( + ~name="make", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.make(2, "testValue")`], + ~definitions=[ + //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. + FnDefinition.make( + ~requiresNamespace, + ~name="make", + ~inputs=[FRTypeNumber, FRTypeAny], + ~run=(inputs, _, _) => { + switch inputs { + | [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="upTo", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.upTo(1,4)`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="upTo", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + inputs + ->Prepare.ToValueTuple.twoNumbers + ->E.R2.fmap(((low, high)) => Internals.upTo(low, high)), + (), + ), + ], + (), + ), + Function.make( + ~name="first", + ~nameSpace, + ~examples=[`List.first([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="first", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.first(array) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="last", + ~nameSpace, + ~examples=[`List.last([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="last", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.last(array) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="reverse", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.reverse([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="reverse", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.reverse(array)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res new file mode 100644 index 00000000..0dba4c9a --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res @@ -0,0 +1,233 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "Number" +let requiresNamespace = false + +module NumberToNumber = { + let make = (name, fn) => + FnDefinition.make( + ~requiresNamespace, + ~name, + ~inputs=[FRTypeNumber], + ~run=(_, inputs, _) => { + inputs + ->getOrError(0) + ->E.R.bind(Prepare.oneNumber) + ->E.R2.fmap(fn) + ->E.R2.fmap(Wrappers.evNumber) + }, + (), + ) +} + +module ArrayNumberDist = { + let make = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeArray(FRTypeNumber)], + ~run=(_, inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } + let make2 = (name, fn) => { + FnDefinition.make( + ~name, + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(_, inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } +} + +let library = [ + Function.make( + ~name="floor", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`floor(3.5)`], + ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], + (), + ), + Function.make( + ~name="ceiling", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`ceiling(3.5)`], + ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], + (), + ), + Function.make( + ~name="absolute value", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`abs(3.5)`], + ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], + (), + ), + Function.make( + ~name="exponent", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`exp(3.5)`], + ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], + (), + ), + Function.make( + ~name="log", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log(3.5)`], + ~definitions=[NumberToNumber.make("log", Js.Math.log)], + (), + ), + Function.make( + ~name="log base 10", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log10(3.5)`], + ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], + (), + ), + Function.make( + ~name="log base 2", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log2(3.5)`], + ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], + (), + ), + Function.make( + ~name="round", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`round(3.5)`], + ~definitions=[NumberToNumber.make("round", Js.Math.round)], + (), + ), + Function.make( + ~name="sum", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`sum([3,5,2])`], + ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="product", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`product([3,5,2])`], + ~definitions=[ + ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="min", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`min([3,5,2])`], + ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="max", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`max([3,5,2])`], + ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="mean", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`mean([3,5,2])`], + ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="geometric mean", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`geomean([3,5,2])`], + ~definitions=[ + ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="standard deviation", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`stdev([3,5,2,3,5])`], + ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="variance", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`variance([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="sort", + ~nameSpace, + ~output=EvtArray, + ~examples=[`sort([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("sort", r => + r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="cumulative sum", + ~nameSpace, + ~output=EvtArray, + ~examples=[`cumsum([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("cumsum", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="cumulative prod", + ~nameSpace, + ~output=EvtArray, + ~examples=[`cumprod([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("cumprod", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="diff", + ~nameSpace, + ~output=EvtArray, + ~examples=[`diff([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("diff", r => + r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res new file mode 100644 index 00000000..92e4ab5f --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res @@ -0,0 +1,55 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "PointSet" +let requiresNamespace = true + +let inputsTodist = (inputs: array, makeDist) => { + let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) + let xyCoords = + array->E.R.bind(xyCoords => + xyCoords + ->E.A2.fmap(xyCoord => + [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) + ) + ->E.A.R.firstErrorOrOpen + ) + let expressionValue = + xyCoords + ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) + ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( + PointSet(makeDist(r)), + )) + expressionValue +} + +let library = [ + Function.make( + ~name="makeContinuous", + ~nameSpace, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="makeContinuous", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), + ), + ], + (), + ), + Function.make( + ~name="makeDiscrete", + ~nameSpace, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="makeDiscrete", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res new file mode 100644 index 00000000..19886841 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res @@ -0,0 +1,90 @@ +open FunctionRegistry_Core + +let nameSpace = "Dist" +let requiresNamespace = false + +let runScoring = (estimate, answer, prior, env) => { + GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) + ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) + ->E.R2.errMap(DistributionTypes.Error.toString) +} + +let library = [ + Function.make( + ~name="logScore", + ~nameSpace, + ~output=EvtNumber, + ~examples=[ + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", + "Dist.logScore({estimate: normal(5,2), answer: 4.5})", + ], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="logScore", + ~inputs=[ + FRTypeRecord([ + ("estimate", FRTypeDist), + ("answer", FRTypeDistOrNumber), + ("prior", FRTypeDist), + ]), + ], + ~run=(_, inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) => + runScoring(estimate, Score_Dist(d), Some(prior), env) + | Ok([ + FRValueDist(estimate), + FRValueDistOrNumber(FRValueNumber(d)), + FRValueDist(prior), + ]) => + runScoring(estimate, Score_Scalar(d), Some(prior), env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + FnDefinition.make( + ~name="logScore", + ~requiresNamespace, + ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => + runScoring(estimate, Score_Dist(d), None, env) + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => + runScoring(estimate, Score_Scalar(d), None, env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="klDivergence", + ~nameSpace, + ~output=EvtNumber, + ~examples=["Dist.klDivergence(normal(5,2), normal(5,1.5)"], + ~definitions=[ + FnDefinition.make( + ~name="klDivergence", + ~requiresNamespace, + ~inputs=[FRTypeDist, FRTypeDist], + ~run=(_, inputs, env) => { + switch inputs { + | [FRValueDist(estimate), FRValueDist(d)] => + runScoring(estimate, Score_Dist(d), None, env) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), +]