Merge pull request #675 from quantified-uncertainty/develop

Develop -> Master
This commit is contained in:
Ozzie Gooen 2022-06-11 13:38:40 -07:00 committed by GitHub
commit b63039b803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1583 additions and 106 deletions

View File

@ -18,7 +18,7 @@ describe("builtin", () => {
testEval("2>1", "Ok(true)")
testEval("concat('a','b')", "Ok('ab')")
testEval(
"addOne(t)=t+1; toInternalSampleArray(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))",
"addOne(t)=t+1; toList(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))",
"Ok([2,3,4,5,6,7])",
)
})

View File

@ -0,0 +1,19 @@
module ExpressionT = Reducer_Expression_T
module ExpressionValue = ReducerInterface.ExpressionValue
module ErrorValue = Reducer_ErrorValue
module Bindings = Reducer_Category_Bindings
let removeDefaults = (ev: ExpressionT.expressionValue): ExpressionT.expressionValue =>
switch ev {
| EvRecord(extbindings) => {
let bindings: Bindings.t = Bindings.fromRecord(extbindings)
let keys = Js.Dict.keys(Reducer.defaultExternalBindings)
Belt.Map.String.keep(bindings, (key, _value) => {
let removeThis = Js.Array2.includes(keys, key)
!removeThis
})->Bindings.toExpressionValue
}
| value => value
}
let rRemoveDefaults = r => Belt.Result.map(r, ev => removeDefaults(ev))

View File

@ -235,6 +235,9 @@ describe("Peggy parse", () => {
testParse("1M", "{(::fromUnit_M 1)}")
testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}")
})
describe("Module", () => {
testParse("Math.pi", "{(::$_atIndex_$ @Math 'pi')}")
})
})
describe("parsing new line", () => {

View File

@ -23,8 +23,13 @@ let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
let a2 =
rExpr
->Result.flatMap(expr =>
Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment)
Expression.reduceExpression(
expr,
ReducerInterface_DefaultExternalBindings.defaultInternalBindings,
ExpressionValue.defaultEnvironment,
)
)
->Reducer_Helpers.rRemoveDefaults
->ExpressionValue.toStringResultOkless
(a1, a2)->expect->toEqual((answer, v))
}

View File

@ -181,4 +181,8 @@ describe("Peggy to Expression", () => {
(),
)
})
describe("module", () => {
testToExpression("Math.pi", "{(:$_atIndex_$ :Math 'pi')}", ~v="3.141592653589793", ())
})
})

View File

@ -88,8 +88,8 @@ describe("Peggy Types to Expression", () => {
})
describe("squiggle expressions in type modifiers", () => {
testToExpression(
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(odds1 + odds2)",
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:add :odds1 :odds2)))}",
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}",
~v="{_typeAliases_: {odds: {typeTag: 'typeIdentifier',typeIdentifier: #number,memberOf: [1,3,5,7,9]}},odds1: [1,3,5],odds2: [7,9]}",
(),
)

View File

@ -1,6 +1,7 @@
module ExpressionT = Reducer_Expression_T
module ExpressionValue = ReducerInterface.ExpressionValue
module ErrorValue = Reducer_ErrorValue
module Bindings = Reducer_Category_Bindings
open Jest
open Expect
@ -17,7 +18,11 @@ let expectParseToBe = (expr: string, answer: string) =>
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
let expectEvalToBe = (expr: string, answer: string) =>
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
Reducer.evaluate(expr)
->Reducer_Helpers.rRemoveDefaults
->ExpressionValue.toStringResult
->expect
->toBe(answer)
let expectEvalError = (expr: string) =>
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toMatch("Error\(")

View File

@ -7,7 +7,7 @@ describe("map reduce", () => {
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduce(arr, 0, change)", "Ok(15)")
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduceReverse(arr, 0, change)", "Ok(9)")
testEvalToBe("arr=[1,2,3]; reverse(arr)", "Ok([3,2,1])")
testEvalToBe("check(x)=(x==2);arr=[1,2,3]; keep(arr,check)", "Ok([2])")
testEvalToBe("check(x)=(x==2);arr=[1,2,3]; filter(arr,check)", "Ok([2])")
})
Skip.describe("map reduce (sam)", () => {

View File

@ -0,0 +1,7 @@
open Jest
open Reducer_TestHelpers
describe("Math Library", () => {
testEvalToBe("Math.e", "Ok(2.718281828459045)")
testEvalToBe("Math.pi", "Ok(3.141592653589793)")
})

View File

@ -187,5 +187,16 @@ function createTsExport(
return tag("lambdaDeclaration", x.value);
case "EvTypeIdentifier":
return tag("typeIdentifier", x.value);
case "EvModule":
let moduleResult: tagged<
"module",
{ [key: string]: squiggleExpression }
> = tag(
"module",
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return moduleResult;
}
}

View File

@ -73,6 +73,10 @@ export type rescriptExport =
| {
TAG: 13; // EvTypeIdentifier
_0: string;
}
| {
TAG: 14; // EvModule
_0: { [key: string]: rescriptExport };
};
type rescriptDist =
@ -125,7 +129,8 @@ export type squiggleExpression =
| tagged<"timeDuration", number>
| tagged<"lambdaDeclaration", lambdaDeclaration>
| tagged<"record", { [key: string]: squiggleExpression }>
| tagged<"typeIdentifier", string>;
| tagged<"typeIdentifier", string>
| tagged<"module", { [key: string]: squiggleExpression }>;
export { lambdaValue };
@ -177,6 +182,11 @@ export function convertRawToTypescript(
});
case 13: // EvSymbol
return tag("typeIdentifier", result._0);
case 14: // EvModule
return tag(
"module",
_.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
);
}
}

View File

@ -47,6 +47,9 @@ type fnDefinition = {
type function = {
name: string,
definitions: array<fnDefinition>,
examples: option<string>,
description: option<string>,
isExperimental: bool,
}
type registry = array<function>
@ -57,10 +60,10 @@ module FRType = {
switch t {
| FRTypeNumber => "number"
| FRTypeNumeric => "numeric"
| FRTypeDistOrNumber => "frValueDistOrNumber"
| FRTypeDistOrNumber => "distribution|number"
| FRTypeRecord(r) => {
let input = ((name, frType): frTypeRecordParam) => `${name}: ${toString(frType)}`
`record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})`
`{${r->E.A2.fmap(input)->E.A2.joinWith(", ")}}`
}
| FRTypeArray(r) => `list(${toString(r)})`
| FRTypeLambda => `lambda`
@ -331,13 +334,34 @@ module FnDefinition = {
module Function = {
type t = function
let make = (~name, ~definitions): t => {
type functionJson = {
name: string,
definitions: array<string>,
examples: option<string>,
description: option<string>,
isExperimental: bool,
}
let make = (~name, ~definitions, ~examples=?, ~description=?, ~isExperimental=false, ()): t => {
name: name,
definitions: definitions,
examples: examples,
isExperimental: isExperimental,
description: description,
}
let toJson = (t: t): functionJson => {
name: t.name,
definitions: t.definitions->E.A2.fmap(FnDefinition.toString),
examples: t.examples,
description: t.description,
isExperimental: t.isExperimental,
}
}
module Registry = {
let toJson = (r: registry) => r->E.A2.fmap(Function.toJson)
/*
There's a (potential+minor) bug here: If a function definition is called outside of the calls
to the registry, then it's possible that there could be a match after the registry is
@ -350,6 +374,7 @@ module Registry = {
~env: DistributionOperation.env,
) => {
let matchToDef = m => Matcher.Registry.matchToDef(registry, m)
//Js.log(toSimple(registry))
let showNameMatchDefinitions = matches => {
let defs =
matches

View File

@ -57,6 +57,7 @@ let registry = [
~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))),
),
],
(),
),
Function.make(
~name="toDiscretePointSet",
@ -67,6 +68,7 @@ let registry = [
~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))),
),
],
(),
),
Function.make(
~name="Declaration",
@ -75,9 +77,13 @@ let registry = [
inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue)
}),
],
(),
),
Function.make(
~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 =>
@ -85,9 +91,13 @@ let registry = [
),
TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)),
],
(),
),
Function.make(
~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 =>
@ -95,29 +105,43 @@ let registry = [
),
TwoArgDist.makeRecordMeanStdev("lognormal", twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)),
],
(),
),
Function.make(
~name="Uniform",
~examples=`uniform(10, 12)`,
~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))],
(),
),
Function.make(
~name="Beta",
~examples=`beta(20, 25)`,
~definitions=[TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make))],
(),
),
Function.make(
~name="Cauchy",
~examples=`cauchy(5, 1)`,
~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))],
(),
),
Function.make(
~name="Gamma",
~examples=`gamma(5, 1)`,
~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))],
(),
),
Function.make(
~name="Logistic",
~examples=`gamma(5, 1)`,
~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))],
(),
),
Function.make(
~name="To",
~name="To (Distribution)",
~examples=`5 to 10
to(5,10)
-5 to 5`,
~definitions=[
TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)),
TwoArgDist.make(
@ -125,63 +149,149 @@ let registry = [
twoArgs(SymbolicDist.From90thPercentile.make),
),
],
(),
),
Function.make(
~name="Exponential",
~examples=`exponential(2)`,
~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)],
(),
),
Function.make(
~name="Bernoulli",
~examples=`bernoulli(0.5)`,
~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)],
(),
),
Function.make(
~name="PointMass",
~examples=`pointMass(0.5)`,
~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)],
(),
),
Function.make(
~name="toContinuousPointSet",
~description="Converts a set of points to a continuous distribution",
~examples=`toContinuousPointSet([
{x: 0, y: 0.1},
{x: 1, y: 0.2},
{x: 2, y: 0.15},
{x: 3, y: 0.1}
])`,
~definitions=[
FnDefinition.make(
~name="toContinuousPointSet",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))),
),
],
(),
),
Function.make(
~name="toDiscretePointSet",
~description="Converts a set of points to a discrete distribution",
~examples=`toDiscretePointSet([
{x: 0, y: 0.1},
{x: 1, y: 0.2},
{x: 2, y: 0.15},
{x: 3, y: 0.1}
])`,
~definitions=[
FnDefinition.make(
~name="toDiscretePointSet",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))),
),
],
(),
),
Function.make(
~name="Declaration (Continuous Function)",
~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}
]
})`,
~definitions=[
FnDefinition.make(~name="declareFn", ~inputs=[Declaration.frType], ~run=(inputs, _) => {
inputs->E.A.unsafe_get(0)->Declaration.fromExpressionValue
}),
],
~isExperimental=true,
(),
),
Function.make(
~name="Floor",
~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)],
(),
),
Function.make(
~name="Ceiling",
~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)],
(),
),
Function.make(~name="Floor", ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)]),
Function.make(~name="Ceiling", ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)]),
Function.make(
~name="Absolute Value",
~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)],
(),
),
Function.make(~name="Exponent", ~definitions=[NumberToNumber.make("exp", Js.Math.exp)]),
Function.make(~name="Log", ~definitions=[NumberToNumber.make("log", Js.Math.log)]),
Function.make(~name="Log Base 10", ~definitions=[NumberToNumber.make("log10", Js.Math.log10)]),
Function.make(~name="Log Base 2", ~definitions=[NumberToNumber.make("log2", Js.Math.log2)]),
Function.make(~name="Round", ~definitions=[NumberToNumber.make("round", Js.Math.round)]),
Function.make(~name="Exponent", ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], ()),
Function.make(~name="Log", ~definitions=[NumberToNumber.make("log", Js.Math.log)], ()),
Function.make(
~name="Log Base 10",
~definitions=[NumberToNumber.make("log10", Js.Math.log10)],
(),
),
Function.make(~name="Log Base 2", ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], ()),
Function.make(~name="Round", ~definitions=[NumberToNumber.make("round", Js.Math.round)], ()),
Function.make(
~name="Sum",
~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)],
(),
),
Function.make(
~name="Product",
~definitions=[
ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok),
],
(),
),
Function.make(
~name="Min",
~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)],
(),
),
Function.make(
~name="Max",
~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)],
(),
),
Function.make(
~name="Mean",
~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)],
(),
),
Function.make(
~name="Geometric Mean",
~definitions=[
ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok),
],
(),
),
Function.make(
~name="Standard Deviation",
~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)],
(),
),
Function.make(
~name="Variance",
~definitions=[
ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok),
],
(),
),
Function.make(
~name="First",
@ -190,6 +300,7 @@ let registry = [
r->E.A.first |> E.O.toResult(impossibleError) |> E.R.fmap(Wrappers.evNumber)
),
],
(),
),
Function.make(
~name="Last",
@ -198,6 +309,7 @@ let registry = [
r->E.A.last |> E.O.toResult(impossibleError) |> E.R.fmap(Wrappers.evNumber)
),
],
(),
),
Function.make(
~name="Sort",
@ -206,6 +318,7 @@ let registry = [
r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
),
],
(),
),
Function.make(
~name="Reverse",
@ -214,6 +327,7 @@ let registry = [
r->Belt_Array.reverse->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
),
],
(),
),
Function.make(
~name="Cumulative Sum",
@ -222,6 +336,7 @@ let registry = [
r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
),
],
(),
),
Function.make(
~name="Cumulative Prod",
@ -230,6 +345,7 @@ let registry = [
r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
),
],
(),
),
Function.make(
~name="Diff",
@ -238,6 +354,7 @@ let registry = [
r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
),
],
(),
),
Function.make(
~name="Dict.merge",
@ -259,6 +376,7 @@ let registry = [
},
),
],
(),
),
//TODO: Make sure that two functions can't have the same name. This causes chaos elsewhere.
Function.make(
@ -275,6 +393,7 @@ let registry = [
->E.R2.fmap(Wrappers.evRecord)
),
],
(),
),
Function.make(
~name="Dict.keys",
@ -286,6 +405,7 @@ let registry = [
}
),
],
(),
),
Function.make(
~name="Dict.values",
@ -301,6 +421,7 @@ let registry = [
}
),
],
(),
),
Function.make(
~name="Dict.toList",
@ -322,6 +443,7 @@ let registry = [
}
),
],
(),
),
Function.make(
~name="Dict.fromList",
@ -346,6 +468,7 @@ let registry = [
|> E.R2.bind(convertInternalItems)
}),
],
(),
),
Function.make(
~name="List.make",
@ -362,6 +485,7 @@ let registry = [
}
}),
],
(),
),
Function.make(
~name="upTo",
@ -376,5 +500,6 @@ let registry = [
)
),
],
(),
),
]

View File

@ -24,4 +24,4 @@ let foreignFunctionInterface = (
let defaultEnvironment = ExpressionValue.defaultEnvironment
let defaultExternalBindings = ExpressionValue.defaultExternalBindings
let defaultExternalBindings = ReducerInterface_DefaultExternalBindings.defaultExternalBindings

View File

@ -0,0 +1,12 @@
include Reducer_Category_Module // Bindings inherit from Module
open ReducerInterface_ExpressionValue
let emptyBindings = emptyModule
let toExpressionValue = (container: t): expressionValue => EvRecord(toRecord(container))
let fromExpressionValue = (aValue: expressionValue): t =>
switch aValue {
| EvRecord(r) => fromRecord(r)
| _ => emptyBindings
}

View File

@ -0,0 +1,33 @@
module ExpressionT = Reducer_Expression_T
open ReducerInterface_ExpressionValue
let expressionValueToString = toString
type t = ExpressionT.bindings
let typeAliasesKey = "_typeAliases_"
let typeReferencesKey = "_typeReferences_"
let emptyModule: t = Belt.Map.String.empty
let cloneRecord = (r: record): record => r->Js.Dict.entries->Js.Dict.fromArray
let fromRecord = (r: record): t => Js.Dict.entries(r)->Belt.Map.String.fromArray
let toRecord = (container: t): record => Belt.Map.String.toArray(container)->Js.Dict.fromArray
let toExpressionValue = (container: t): expressionValue => EvModule(toRecord(container))
let fromExpressionValue = (aValue: expressionValue): t =>
switch aValue {
| EvModule(r) => fromRecord(r)
| _ => emptyModule
}
let toString = (container: t): string => container->toRecord->EvRecord->expressionValueToString
// -- Module definition
let define = (container: t, identifier: string, ev: expressionValue): t =>
Belt.Map.String.set(container, identifier, ev) // TODO build lambda for polymorphic functions here
let defineNumber = (container: t, identifier: string, value: float): t =>
container->define(identifier, EvNumber(value))
let defineModule = (container: t, identifier: string, value: t): t =>
container->define(identifier, toExpressionValue(value))

View File

@ -256,6 +256,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
switch call {
| ("$_atIndex_$", [EvArray(aValueArray), EvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
| ("$_atIndex_$", [EvModule(dict), EvString(sIndex)]) => recordAtIndex(dict, sIndex)
| ("$_atIndex_$", [EvRecord(dict), EvString(sIndex)]) => recordAtIndex(dict, sIndex)
| ("$_constructArray_$", [EvArray(aValueArray)]) => EvArray(aValueArray)->Ok
| ("$_constructRecord_$", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
@ -281,12 +282,12 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
| ("$_typeModifier_opaque_$", [EvRecord(typeRecord)]) => typeModifier_opaque_update(typeRecord)
| ("$_typeOr_$", [EvArray(arr)]) => typeOr(EvArray(arr))
| ("$_typeFunction_$", [EvArray(arr)]) => typeFunction(arr)
| ("add", [EvArray(aValueArray), EvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray)
| ("add", [EvString(aValueString), EvString(bValueString)]) =>
| ("concat", [EvArray(aValueArray), EvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray)
| ("concat", [EvString(aValueString), EvString(bValueString)]) =>
doAddString(aValueString, bValueString)
| ("inspect", [value, EvString(label)]) => inspectLabel(value, label)
| ("inspect", [value]) => inspect(value)
| ("keep", [EvArray(aValueArray), EvLambda(aLambdaValue)]) =>
| ("filter", [EvArray(aValueArray), EvLambda(aLambdaValue)]) =>
doKeepArray(aValueArray, aLambdaValue)
| ("map", [EvArray(aValueArray), EvLambda(aLambdaValue)]) => doMapArray(aValueArray, aLambdaValue)
| ("mapSamples", [EvDistribution(SampleSet(dist)), EvLambda(aLambdaValue)]) =>

View File

@ -123,7 +123,7 @@ let evaluateUsingOptions = (
let anExternalBindings = switch externalBindings {
| Some(bindings) => bindings
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
| None => ReducerInterface_DefaultExternalBindings.defaultExternalBindings
}
let bindings = anExternalBindings->Bindings.fromExternalBindings

View File

@ -2,77 +2,25 @@ module ErrorValue = Reducer_ErrorValue
module ExpressionT = Reducer_Expression_T
module ExpressionValue = ReducerInterface.ExpressionValue
module Result = Belt.Result
module Bindings = Reducer_Category_Bindings
type errorValue = Reducer_ErrorValue.errorValue
type expression = ExpressionT.expression
type expressionValue = ExpressionValue.expressionValue
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
let defaultBindings: ExpressionT.bindings = Belt.Map.String.empty
let emptyBindings = Reducer_Category_Bindings.emptyBindings
let typeAliasesKey = "_typeAliases_"
let typeReferencesKey = "_typeReferences_"
let typeAliasesKey = Bindings.typeAliasesKey
let typeReferencesKey = Bindings.typeReferencesKey
let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => {
let keys = Belt.Map.String.keysToArray(bindings)
keys->Belt.Array.reduce(Js.Dict.empty(), (acc, key) => {
let value = bindings->Belt.Map.String.getExn(key)
Js.Dict.set(acc, key, value)
acc
})
}
let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings =>
Bindings.toRecord(bindings)
let fromExternalBindings_ = (externalBindings: externalBindings): ExpressionT.bindings => {
let keys = Js.Dict.keys(externalBindings)
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
let value = Js.Dict.unsafeGet(externalBindings, key)
acc->Belt.Map.String.set(key, value)
})
}
let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings =>
Bindings.fromRecord(externalBindings)
let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => {
// TODO: This code will be removed in the future when maps are used instead of records. Please don't mind this function for now.
let internalBindings0 = fromExternalBindings_(externalBindings)
let oExistingTypeAliases = Belt.Map.String.get(internalBindings0, typeAliasesKey)
let internalBindings1 = Belt.Option.mapWithDefault(
oExistingTypeAliases,
internalBindings0,
existingTypeAliases => {
let newTypeAliases = switch existingTypeAliases {
| EvRecord(actualTypeAliases) =>
actualTypeAliases->fromExternalBindings_->toExternalBindings->ExpressionValue.EvRecord
| _ => existingTypeAliases
}
Belt.Map.String.set(internalBindings0, typeAliasesKey, newTypeAliases)
},
)
let oExistingTypeReferences = Belt.Map.String.get(internalBindings1, typeReferencesKey)
let internalBindings2 = Belt.Option.mapWithDefault(
oExistingTypeReferences,
internalBindings1,
existingTypeReferences => {
let newTypeReferences = switch existingTypeReferences {
| EvRecord(actualTypeReferences) =>
actualTypeReferences->fromExternalBindings_->toExternalBindings->ExpressionValue.EvRecord
| _ => existingTypeReferences
}
Belt.Map.String.set(internalBindings0, typeReferencesKey, newTypeReferences)
},
)
internalBindings2
}
let fromValue = (aValue: expressionValue) =>
switch aValue {
| EvRecord(externalBindings) => fromExternalBindings(externalBindings)
| _ => defaultBindings
}
let externalFromArray = anArray => Js.Dict.fromArray(anArray)
let fromValue = (aValue: expressionValue) => Bindings.fromExpressionValue(aValue)
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")

View File

@ -65,5 +65,7 @@ let eBindExpression = (bindingExpr: expression, expression: expression): express
let eBindExpressionDefault = (expression: expression): expression =>
eFunction("$$_bindExpression_$$", list{expression})
let eIdentifier = (name: string): expression => name->BExpressionValue.EvSymbol->BExpressionT.EValue
let eTypeIdentifier = (name: string): expression =>
name->BExpressionValue.EvTypeIdentifier->BExpressionT.EValue

View File

@ -64,6 +64,7 @@
return {type: 'KeyValue', key: key, value: value}}
function nodeLambda(args, body) {return {type: 'Lambda', args: args, body: body}}
function nodeLetStatment(variable, value) {return {type: 'LetStatement', variable: variable, value: value}}
function nodeModuleIdentifier(value) {return {type: 'ModuleIdentifier', value: value}}
function nodeString(value) {return {type: 'String', value: value}}
function nodeTernary(condition, trueExpression, falseExpression) {return {type: 'Ternary', condition: condition, trueExpression: trueExpression, falseExpression: falseExpression}}
@ -256,11 +257,11 @@ basicLiteral
dollarIdentifierWithModule 'identifier'
= head:moduleIdentifier
tail:('.' _nl @moduleIdentifier)* '.' _nl
final:dollarIdentifier
tail:('.' _nl @$moduleIdentifier)* '.' _nl
final:$dollarIdentifier
{ tail.push(final);
return tail.reduce(function(result, element) {
return makeFunctionCall(postOperatorToFunction['[]'], [result, element])
return makeFunctionCall(postOperatorToFunction['[]'], [result, nodeString(element)])
}, head)}
identifier 'identifier'
@ -273,7 +274,7 @@ dollarIdentifier '$identifier'
= ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())}
moduleIdentifier 'identifier'
= ([A-Z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
= ([A-Z]+[_a-z0-9]i*) {return nodeModuleIdentifier(text())}
string 'string'

View File

@ -22,6 +22,7 @@ type nodeInteger = {...node, "value": int}
type nodeKeyValue = {...node, "key": node, "value": node}
type nodeLambda = {...node, "args": array<nodeIdentifier>, "body": nodeBlock}
type nodeLetStatement = {...node, "variable": nodeIdentifier, "value": node}
type nodeModuleIdentifier = {...node, "value": string}
type nodeString = {...node, "value": string}
type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node}
type nodeTypeIdentifier = {...node, "value": string}
@ -37,6 +38,7 @@ type peggyNode =
| PgNodeKeyValue(nodeKeyValue)
| PgNodeLambda(nodeLambda)
| PgNodeLetStatement(nodeLetStatement)
| PgNodeModuleIdentifier(nodeModuleIdentifier)
| PgNodeString(nodeString)
| PgNodeTernary(nodeTernary)
| PgNodeTypeIdentifier(nodeTypeIdentifier)
@ -51,6 +53,7 @@ external castNodeInteger: node => nodeInteger = "%identity"
external castNodeKeyValue: node => nodeKeyValue = "%identity"
external castNodeLambda: node => nodeLambda = "%identity"
external castNodeLetStatement: node => nodeLetStatement = "%identity"
external castNodeModuleIdentifier: node => nodeModuleIdentifier = "%identity"
external castNodeString: node => nodeString = "%identity"
external castNodeTernary: node => nodeTernary = "%identity"
external castNodeTypeIdentifier: node => nodeTypeIdentifier = "%identity"
@ -68,6 +71,7 @@ let castNodeType = (node: node) =>
| "KeyValue" => node->castNodeKeyValue->PgNodeKeyValue
| "Lambda" => node->castNodeLambda->PgNodeLambda
| "LetStatement" => node->castNodeLetStatement->PgNodeLetStatement
| "ModuleIdentifier" => node->castNodeModuleIdentifier->PgNodeModuleIdentifier
| "String" => node->castNodeString->PgNodeString
| "Ternary" => node->castNodeTernary->PgNodeTernary
| "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier
@ -94,6 +98,7 @@ let rec pgToString = (peggyNode: peggyNode): string => {
"{|" ++ node["args"]->argsToString ++ "| " ++ pgToString(PgNodeBlock(node["body"])) ++ "}"
| PgNodeLetStatement(node) =>
pgToString(PgNodeIdentifier(node["variable"])) ++ " = " ++ toString(node["value"])
| PgNodeModuleIdentifier(node) => `@${node["value"]}`
| PgNodeString(node) => `'${node["value"]->Js.String.make}'`
| PgNodeTernary(node) =>
"(::$$_ternary_$$ " ++

View File

@ -34,6 +34,8 @@ let rec fromNode = (node: Parse.node): expression => {
nodeLetStatement["variable"]["value"],
fromNode(nodeLetStatement["value"]),
)
| PgNodeModuleIdentifier(nodeModuleIdentifier) =>
ExpressionBuilder.eIdentifier(nodeModuleIdentifier["value"])
| PgNodeString(nodeString) => ExpressionBuilder.eString(nodeString["value"])
| PgNodeTernary(nodeTernary) =>
ExpressionBuilder.eFunction(

View File

@ -0,0 +1,6 @@
module Bindings = Reducer_Category_Bindings
let defaultInternalBindings = Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings
@genType
let defaultExternalBindings = defaultInternalBindings->Bindings.toRecord

View File

@ -27,6 +27,7 @@ let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
EV.EvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok->Some
| ("divide", [EvTimeDuration(d1), EvNumber(d2)]) =>
EV.EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some
| ("divide", [EvTimeDuration(d1), EvTimeDuration(d2)]) => EV.EvNumber(d1 /. d2)->Ok->Some
| _ => None
}
}

View File

@ -4,7 +4,6 @@
*/
module Extra_Array = Reducer_Extra_Array
module ErrorValue = Reducer_ErrorValue
@genType.opaque
type internalCode = Object
@ -24,6 +23,7 @@ type rec expressionValue =
| EvTimeDuration(float)
| EvDeclaration(lambdaDeclaration)
| EvTypeIdentifier(string)
| EvModule(record)
and record = Js.Dict.t<expressionValue>
and externalBindings = record
and lambdaValue = {
@ -33,9 +33,6 @@ and lambdaValue = {
}
and lambdaDeclaration = Declaration.declaration<lambdaValue>
@genType
let defaultExternalBindings: externalBindings = Js.Dict.empty()
type functionCall = (string, array<expressionValue>)
let rec toString = aValue =>
@ -60,6 +57,7 @@ let rec toString = aValue =>
| EvTimeDuration(t) => DateTime.Duration.toString(t)
| EvDeclaration(d) => Declaration.toString(d, r => toString(EvLambda(r)))
| EvTypeIdentifier(id) => `#${id}`
| EvModule(m) => `@${m->toStringRecord}`
}
and toStringRecord = aRecord => {
let pairs =
@ -86,6 +84,7 @@ let toStringWithType = aValue =>
| EvTimeDuration(_) => `Date::${toString(aValue)}`
| EvDeclaration(_) => `Declaration::${toString(aValue)}`
| EvTypeIdentifier(_) => `TypeIdentifier::${toString(aValue)}`
| EvModule(_) => `Module::${toString(aValue)}`
}
let argsToString = (args: array<expressionValue>): string => {
@ -133,6 +132,7 @@ type expressionValueType =
| EvtTimeDuration
| EvtDeclaration
| EvtTypeIdentifier
| EvtModule
type functionCallSignature = CallSignature(string, array<expressionValueType>)
type functionDefinitionSignature =
@ -154,6 +154,7 @@ let valueToValueType = value =>
| EvTimeDuration(_) => EvtTimeDuration
| EvDeclaration(_) => EvtDeclaration
| EvTypeIdentifier(_) => EvtTypeIdentifier
| EvModule(_) => EvtModule
}
let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => {
@ -177,6 +178,7 @@ let valueTypeToString = (valueType: expressionValueType): string =>
| EvtTimeDuration => `Duration`
| EvtDeclaration => `Declaration`
| EvtTypeIdentifier => `TypeIdentifier`
| EvtModule => `Module`
}
let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => {

View File

@ -200,8 +200,6 @@ let dispatchToGenericOutput = (
): option<DistributionOperation.outputType> => {
let (fnName, args) = call
switch (fnName, args) {
| ("delta", [EvNumber(f)]) =>
SymbolicDist.Float.makeSafe(f)->SymbolicConstructors.symbolicResultToOutput
| ("triangular" as fnName, [EvNumber(f1), EvNumber(f2), EvNumber(f3)]) =>
SymbolicConstructors.threeFloat(fnName)
->E.R.bind(r => r(f1, f2, f3))
@ -279,8 +277,7 @@ let dispatchToGenericOutput = (
Helpers.toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist, ~env)
| ("toSampleSet", [EvDistribution(dist)]) =>
Helpers.toDistFn(ToSampleSet(env.sampleCount), dist, ~env)
| ("toInternalSampleArray", [EvDistribution(SampleSet(dist))]) =>
Some(FloatArray(SampleSetDist.T.get(dist)))
| ("toList", [EvDistribution(SampleSet(dist))]) => Some(FloatArray(SampleSetDist.T.get(dist)))
| ("fromSamples", [EvArray(inputArray)]) => {
let _wrapInputErrors = x => SampleSetDist.NonNumericInput(x)
let parsedArray = Helpers.parseNumberArray(inputArray)->E.R2.errMap(_wrapInputErrors)

View File

@ -0,0 +1,8 @@
module Bindings = Reducer_Category_Bindings
module Module = Reducer_Category_Module
let m =
Module.emptyModule->Module.defineNumber("pi", Js.Math._PI)->Module.defineNumber("e", Js.Math._E)
let makeBindings = (previousBindings: Bindings.t): Bindings.t =>
previousBindings->Bindings.defineModule("Math", m)

View File

@ -0,0 +1,42 @@
---
sidebar_position: 1
title: Date
---
### makeFromYear
```
Date.makeFromYear: (number) => date
```
```js
makeFromYear(2022.32);
```
### toString
```
toString: (date) => string
```
### subtract
```
subtract: (date, date) => duration
subtract: (date, duration) => date
```
```js
makeFromYear(2040) - makeFromYear(2020); // 20 years
makeFromYear(2040) - years(20); // 2020
```
### add
```
add: (date, duration) => date
```
```js
makeFromYear(2022.32) + years(5);
```

View File

@ -0,0 +1,71 @@
---
sidebar_position: 2
title: Dictionary
---
### toList
```
Dict.toList: (dict<'a>) => list<list<string|a>>
```
```js
Dict.toList({ foo: 3, bar: 20 }); // [["foo", 3], ["bar", 20]]
```
### fromList
```
Dict.fromList: (list<list<string|'a>>) => dict<'a>
```
```js
Dict.fromList([
["foo", 3],
["bar", 20],
]); // {foo: 3, bar: 20}
```
### keys
```
Dict.keys: (dict<'a>) => list<string>
```
```js
Dict.keys({ foo: 3, bar: 20 }); // ["foo", "bar"]
```
### values
```
Dict.values: (dict<'a>) => list<'a>
```
```js
Dict.values({ foo: 3, bar: 20 }); // [3, 20]
```
### merge
```
Dict.merge: (dict<'a>, dict<'b>) => dict<'a|b>
```
```js
first = { a: 1, b: 2 };
snd = { b: 3, c: 5 };
Dict.merge(first, snd); // {a: 1, b: 3, c: 5}
```
### mergeMany
```
Dict.mergeMany: (list<dict<'a>>) => dict<'a>
```
```js
first = { a: 1, b: 2 };
snd = { b: 3, c: 5 };
Dict.mergeMany([first, snd]); // {a: 1, b: 3, c: 5}
```

View File

@ -0,0 +1,647 @@
---
sidebar_position: 3
title: Distribution
---
import TOCInline from "@theme/TOCInline";
<TOCInline toc={toc} />
## Distribution Creation
### Normal Distribution
**Definitions**
```javascript
normal: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
```javascript
normal: (dict<{p5: frValueDistOrNumber, p95: frValueDistOrNumber}>) => distribution
```
```javascript
normal: (dict<{mean: frValueDistOrNumber, stdev: frValueDistOrNumber}>) => distribution
```
**Examples**
```js
normal(5, 1);
normal({ p5: 4, p95: 10 });
normal({ mean: 5, stdev: 2 });
```
### Lognormal Distribution
**Definitions**
```javascript
lognormal: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
```javascript
lognormal: (dict<{p5: frValueDistOrNumber, p95: frValueDistOrNumber}>) => distribution
```
```javascript
lognormal: (dict<{mean: frValueDistOrNumber, stdev: frValueDistOrNumber}>) => distribution
```
**Examples**
```javascript
lognormal(0.5, 0.8);
lognormal({ p5: 4, p95: 10 });
lognormal({ mean: 5, stdev: 2 });
```
### Uniform Distribution
**Definitions**
```javascript
uniform: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
uniform(10, 12);
```
### Beta Distribution
**Definitions**
```javascript
beta: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
beta(20, 25);
```
### Cauchy Distribution
**Definitions**
```javascript
cauchy: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
cauchy(5, 1);
```
### Gamma Distribution
**Definitions**
```javascript
gamma: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
gamma(5, 1);
```
### Logistic Distribution
**Definitions**
```javascript
logistic: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
gamma(5, 1);
```
### To (Distribution)
**Definitions**
```javascript
to: (frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
```javascript
credibleIntervalToDistribution(frValueDistOrNumber, frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
5 to 10
to(5,10)
-5 to 5
```
### Exponential
**Definitions**
```javascript
exponential: (frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
exponential(2);
```
### Bernoulli
**Definitions**
```javascript
bernoulli: (frValueDistOrNumber) => distribution;
```
**Examples**
```javascript
bernoulli(0.5);
```
### toContinuousPointSet
Converts a set of points to a continuous distribution
**Definitions**
```javascript
toContinuousPointSet: (array<dict<{x: numeric, y: numeric}>>) => distribution
```
**Examples**
```javascript
toContinuousPointSet([
{ x: 0, y: 0.1 },
{ x: 1, y: 0.2 },
{ x: 2, y: 0.15 },
{ x: 3, y: 0.1 },
]);
```
### toDiscretePointSet
Converts a set of points to a discrete distribution
**Definitions**
```javascript
toDiscretePointSet: (array<dict<{x: numeric, y: numeric}>>) => distribution
```
**Examples**
```javascript
toDiscretePointSet([
{ x: 0, y: 0.1 },
{ x: 1, y: 0.2 },
{ x: 2, y: 0.15 },
{ x: 3, y: 0.1 },
]);
```
## Functions
### mixture
```javascript
mixture: (...distributionLike, weights:list<float>) => distribution
```
**Examples**
```javascript
mixture(normal(5, 1), normal(10, 1));
mx(normal(5, 1), normal(10, 1), [0.3, 0.7]);
```
### sample
Get one random sample from the distribution
```javascript
sample(distribution) => number
```
**Examples**
```javascript
sample(normal(5, 2));
```
### sampleN
Get n random samples from the distribution
```javascript
sampleN: (distribution, number) => list<number>
```
**Examples**
```javascript
sample: normal(5, 2), 100;
```
### mean
Get the distribution mean
```javascript
mean: (distribution) => number;
```
**Examples**
```javascript
mean: normal(5, 2);
```
### stdev
```javascript
stdev: (distribution) => number;
```
### variance
```javascript
variance: (distribution) => number;
```
### mode
```javascript
mode: (distribution) => number;
```
### cdf
```javascript
cdf: (distribution, number) => number;
```
**Examples**
```javascript
cdf: normal(5, 2), 3;
```
### pdf
```javascript
pdf: (distribution, number) => number;
```
**Examples**
```javascript
pdf(normal(5, 2), 3);
```
### inv
```javascript
inv: (distribution, number) => number;
```
**Examples**
```javascript
inv(normal(5, 2), 0.5);
```
### toPointSet
Converts a distribution to the pointSet format
```javascript
toPointSet: (distribution) => pointSetDistribution;
```
**Examples**
```javascript
toPointSet(normal(5, 2));
```
### toSampleSet
Converts a distribution to the sampleSet format, with n samples
```javascript
toSampleSet: (distribution, number) => sampleSetDistribution;
```
**Examples**
```javascript
toSampleSet(normal(5, 2), 1000);
```
### truncateLeft
Truncates the left side of a distribution. Returns either a pointSet distribution or a symbolic distribution.
```javascript
truncateLeft: (distribution, l => number) => distribution
```
**Examples**
```javascript
truncateLeft(normal(5, 2), 3);
```
### truncateRight
Truncates the right side of a distribution. Returns either a pointSet distribution or a symbolic distribution.
```javascript
truncateRight: (distribution, r => number) => distribution
```
**Examples**
```javascript
truncateLeft(normal(5, 2), 6);
```
## Scoring
### klDivergence
KullbackLeibler divergence between two distributions
```javascript
klDivergence: (distribution, distribution) => number;
```
**Examples**
```javascript
klDivergence(normal(5, 2), normal(5, 4)); // returns 0.57
```
## Display
### toString
```javascript
toString: (distribution) => string;
```
**Examples**
```javascript
toString(normal(5, 2));
```
### toSparkline
Produce a sparkline of length n
```javascript
toSparkline: (distribution, n = 20) => string;
```
**Examples**
```javascript
toSparkline(normal(5, 2), 10);
```
### inspect
Prints the value of the distribution to the Javascript console, then returns the distribution.
```javascript
inspect: (distribution) => distribution;
```
**Examples**
```javascript
inspect(normal(5, 2));
```
## Normalization
### normalize
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1.
```javascript
normalize: (distribution) => distribution;
```
**Examples**
```javascript
normalize(normal(5, 2));
```
### isNormalized
Check of a distribution is normalized. Most distributions are typically normalized, but there are some commands that could produce non-normalized distributions.
```javascript
isNormalized: (distribution) => bool;
```
**Examples**
```javascript
isNormalized(normal(5, 2)); // returns true
```
### integralSum
Get the sum of the integral of a distribution. If the distribution is normalized, this will be 1.
```javascript
integralSum: (distribution) => number;
```
**Examples**
```javascript
integralSum(normal(5, 2));
```
## Algebraic Operations
### add
```javascript
add: (distributionLike, distributionLike) => distribution;
```
### sum
```javascript
sum: (list<distributionLike>) => distribution
```
### multiply
```javascript
multiply: (distributionLike, distributionLike) => distribution;
```
### product
```javascript
product: (list<distributionLike>) => distribution
```
### subtract
```javascript
subtract: (distributionLike, distributionLike) => distribution;
```
### divide
```javascript
divide: (distributionLike, distributionLike) => distribution;
```
### pow
```javascript
pow: (distributionLike, distributionLike) => distribution;
```
### exp
```javascript
exp: (distributionLike, distributionLike) => distribution;
```
### log
```javascript
log: (distributionLike, distributionLike) => distribution;
```
### log10
```javascript
log10: (distributionLike, distributionLike) => distribution;
```
### unaryMinus
```javascript
unaryMinus: (distribution) => distribution;
```
## Pointwise Operations
### dotAdd
```javascript
dotAdd: (distributionLike, distributionLike) => distribution;
```
### dotMultiply
```javascript
dotMultiply: (distributionLike, distributionLike) => distribution;
```
### dotSubtract
```javascript
dotSubtract: (distributionLike, distributionLike) => distribution;
```
### dotDivide
```javascript
dotDivide: (distributionLike, distributionLike) => distribution;
```
### dotPow
```javascript
dotPow: (distributionLike, distributionLike) => distribution;
```
### dotExp
```javascript
dotExp: (distributionLike, distributionLike) => distribution;
```
## Scale Operations
### scaleMultiply
```javascript
scaleMultiply: (distributionLike, number) => distribution;
```
### scalePow
```javascript
scalePow: (distributionLike, number) => distribution;
```
### scaleExp
```javascript
scaleExp: (distributionLike, number) => distribution;
```
### scaleLog
```javascript
scaleLog: (distributionLike, number) => distribution;
```
### scaleLog10
```javascript
scaleLog10: (distributionLike, number) => distribution;
```
## Special
### Declaration (Continuous Function)
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.
```javascript
declareFn: (dict<{fn: lambda, inputs: array<dict<{min: number, max: number}>>}>) => declaration
```
**Examples**
```javascript
declareFn({
fn: {|a,b| a },
inputs: [
{min: 0, max: 100},
{min: 30, max: 50}
]
})
```

View File

@ -0,0 +1,22 @@
---
sidebar_position: 4
title: Point Set Distribution
---
### make
```
PointSet.make: (distribution) => pointSetDist
```
### makeContinuous
```
PointSet.makeContinuous: (list<{x: number, y: number}>) => pointSetDist
```
### makeDiscrete
```
PointSet.makeDiscrete: (list<{x: number, y: number}>) => pointSetDist
```

View File

@ -0,0 +1,44 @@
---
sidebar_position: 5
title: Sample Set Distribution
---
### make
```
SampleSet.make: (distribution) => sampleSet
SampleSet.make: (() => number) => sampleSet
SampleSet.make: (list<number>) => sampleSet
```
### map
```
SampleSet.map: (sampleSet, (number => number)) => sampleSet
```
### map2
```
SampleSet.map2: (sampleSet, sampleSet, ((number, number) => number)) => sampleSet
```
### map3
```
SampleSet.map3: (sampleSet, sampleSet, sampleSet, ((number, number, number) => number)) => sampleSet
```
### toList
```
SampleSet.toList: (sampleSet) => list<number>
```
Gets the internal samples of a sampleSet distribution. This is separate from the sampleN() function, which would shuffle the samples. toList() maintains order and length. Gets the internal samples of a sampleSet distribution. This is separate from the sampleN() function, which would shuffle the samples. toList() maintains order and length.
**Examples**
```
toList(toSampleSet(normal(5,2)))
```

View File

@ -0,0 +1,90 @@
---
sidebar_position: 6
title: Duration
---
import TOCInline from "@theme/TOCInline";
<TOCInline toc={toc} />
### toString
```
toString: (duration) => string
```
## Units
### minutes
```
minutes: (number) => duration
```
### hours
```
hours: (number) => duration
```
### days
```
days: (number) => duration
```
### years
```
years: (number) => duration
```
### toHours
```
toHours: (duration) => number
```
### toMinutes
```
toMinutes: (duration) => number
```
### toDays
```
toDays: (duration) => number
```
### toYears
```
toYears: (duration) => number
```
## Algebra
### add
```
add: (duration, duration) => duration
```
### subtract
```
subtract: (duration, duration) => duration
```
### multiply
```
multiply: (duration, number) => duration
```
### divide
```
divide: (duration, number) => duration
```

View File

@ -0,0 +1,94 @@
---
sidebar_position: 7
title: List
---
### make
```
List.make: (number, 'a) => list<'a>
```
Returns an array of size `n` filled with value `e`.
```js
List.make(4, 1); // creates the list [1, 1, 1, 1]
```
See [Rescript implementation](https://rescript-lang.org/docs/manual/latest/api/belt/array#make)
### toString
```
toString: (list<'a>) => string
```
### length
```
length: (list<'a>) => number
```
### up to
```
List.upTo: (low:number, high:number) => list<number>
```
```js
List.upTo(0, 5); // creates the list [0, 1, 2, 3, 4, 5]
```
Syntax taken from [Ruby](https://apidock.com/ruby/v2_5_5/Integer/upto).
### first
```
first: (list<'a>) => 'a
```
### last
```
last: (list<'a>) => 'a
```
### reverse
```
reverse: (list<'a>) => list<'a>
```
### map
```
map: (list<'a>, a => b) => list<'b>
```
See [Rescript implementation](https://rescript-lang.org/docs/manual/latest/api/belt/array#map).
### reduce
```
reduce: (list<'b>, 'a, ('a, 'b) => 'a) => 'a
```
`reduce(arr, init, f)`
Applies `f` to each element of `arr`. The function `f` has two paramaters, an accumulator and the next value from the array.
```js
reduce([2, 3, 4], 1, {|acc, value| acc + value}) == 10
```
See [Rescript implementation](https://rescript-lang.org/docs/manual/latest/api/belt/array#reduce).
### reduce reverse
```
reduceReverse: (list<'b>, 'a, ('a, 'b) => 'a) => 'a
```
Works like `reduce`, but the function is applied to each item from the last back to the first.
See [Rescript implementation](https://rescript-lang.org/docs/manual/latest/api/belt/array#reducereverse).

View File

@ -0,0 +1,84 @@
---
sidebar_position: 8
title: Math
---
### E
```
Math.E:
```
Euler's number; ≈ 2.718281828459045
### LN2
```
Math.LN2:
```
Natural logarithm of 2; ≈ 0.6931471805599453
### LN10
```
Math.LN10:
```
Natural logarithm of 10; ≈ 2.302585092994046
### LOG2E
```
Math.LOG2E:
```
Base 2 logarithm of E; ≈ 1.4426950408889634Base 2 logarithm of E; ≈ 1.4426950408889634
### LOG10E
```
Math.LOG10E:
```
Base 10 logarithm of E; ≈ 0.4342944819032518
### PI
```
Math.PI:
```
Pi - ratio of the circumference to the diameter of a circle; ≈ 3.141592653589793
### SQRT1_2
```
Math.SQRT1_2:
```
Square root of 1/2; ≈ 0.7071067811865476
### SQRT2
```
Math.SQRT2:
```
Square root of 2; ≈ 1.4142135623730951
### PHI
```
Math.PHI:
```
Phi is the golden ratio. 1.618033988749895
### TAU
```
Math.TAU:
```
Tau is the ratio constant of a circle's circumference to radius, equal to 2 \* pi. 6.283185307179586

View File

@ -0,0 +1,144 @@
---
sidebar_position: 9
title: Number
---
import TOCInline from "@theme/TOCInline";
<TOCInline toc={toc} />
### ceil
```javascript
ceil: (number) => number;
```
### floor
```javascript
floor: (number) => number;
```
### abs
```javascript
abs: (number) => number;
```
### round
```javascript
round: (number) => number;
```
## Statistics
### max
```javascript
max: (list<number>) => number
```
### min
```javascript
min: (list<number>) => number
```
### mean
```javascript
mean: (list<number>) => number
```
### stdev
```javascript
stdev: (list<number>) => number
```
### variance
```javascript
variance: (list<number>) => number
```
## Algebra
### unaryMinus
```javascript
unaryMinus: (number) => number;
```
### equal
```javascript
equal: (number, number) => boolean;
```
### add
```javascript
add: (number, number) => number;
```
### sum
```javascript
sum: (list<number>) => number
```
### cumulative sum
```
cumsum: (list<number>) => list<number>
```
### multiply
```javascript
multiply: (number, number) => number;
```
### product
```javascript
product: (list<number>) => number
```
### cumulative product
```
cumprod: (list<number>) => list<number>
```
### subtract
```javascript
subtract: (number, number) => number;
```
### divide
```javascript
divide: (number, number) => number;
```
### pow
```javascript
pow: (number, number) => number;
```
### exp
```javascript
exp: (number) => number;
```
### log
```javascript
log: (number) => number;
```

View File

@ -1,16 +1,13 @@
---
title: "Distribution Creation"
sidebar_position: 2
sidebar_position: 20
---
import TOCInline from "@theme/TOCInline";
import { SquiggleEditor } from "../../src/components/SquiggleEditor";
import Admonition from "@theme/Admonition";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
<TOCInline toc={toc} maxHeadingLevel={2} />
## To
`(5thPercentile: number) to (95thPercentile: number)`

View File

@ -9,8 +9,8 @@ Squiggle is an _estimation language_, and a syntax for _calculating and expressi
- [Gallery](./Discussions/Gallery)
- [Squiggle playground](/playground)
- [Language basics](./Features/Language)
- [Squiggle functions source of truth](./docs/Features/Functions)
- [Language basics](./Guides/Language)
- [Squiggle functions source of truth](./docs/Guides/Functions)
- [Known bugs](./Discussions/Bugs)
- [Original lesswrong sequence](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3)
- [Author your squiggle models as Observable notebooks](https://observablehq.com/@hazelfire/squiggle)

View File

@ -18,9 +18,7 @@ const config = {
favicon: "img/favicon.ico",
organizationName: "quantified-uncertainty", // Usually your GitHub org/user name.
projectName: "squiggle", // Usually your repo name.
plugins: [],
presets: [
[
"classic",
@ -66,6 +64,12 @@ const config = {
position: "left",
label: "Documentation",
},
{
type: "doc",
docId: "Api/Dictionary",
position: "left",
label: "API",
},
{ to: "/blog", label: "Blog", position: "left" },
{ to: "/playground", label: "Playground", position: "left" },
{

View File

@ -14,6 +14,12 @@
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
apiSidebar: [
{
type: "autogenerated",
dirName: "Api",
},
],
tutorialSidebar: [
{
type: "doc",
@ -22,11 +28,11 @@ const sidebars = {
},
{
type: "category",
label: "Features",
label: "Guides",
items: [
{
type: "autogenerated",
dirName: "Features",
dirName: "Guides",
},
],
},