Merge pull request #1069 from quantified-uncertainty/more-functions

[work in progress] Add more functions
This commit is contained in:
Ozzie Gooen 2022-09-06 13:03:54 -07:00 committed by GitHub
commit 9a67b16eee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 697 additions and 280 deletions

View File

@ -48,6 +48,7 @@
"postcss-cli": "^10.0.0",
"postcss-import": "^14.1.0",
"postcss-loader": "^7.0.1",
"postcss-nesting": "^10.1.10",
"react": "^18.1.0",
"react-scripts": "^5.0.1",
"style-loader": "^3.3.1",

View File

@ -4,6 +4,6 @@ module.exports = {
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
cssnano: {},
},
cssnano: {}
}
};

View File

@ -12,6 +12,7 @@ module Wrappers = {
let evRecord = r => ReducerInterface_InternalExpressionValue.IEvRecord(r)
let evString = r => ReducerInterface_InternalExpressionValue.IEvString(r)
let symbolicEvDistribution = r => r->DistributionTypes.Symbolic->evDistribution
let evArrayOfEvNumber = xs => xs->Belt.Array.map(evNumber)->evArray
}
let getOrError = (a, g) => E.A.get(a, g) |> E.O.toResult(impossibleError)
@ -215,3 +216,39 @@ module Process = {
twoValues(~fn=Helpers.wrapSymbolic(fn), ~values)
}
}
module DefineFn = {
module Numbers = {
let oneToOne = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs
->getOrError(0)
->E.R.bind(Prepare.oneNumber)
->E.R2.fmap(fn)
->E.R2.fmap(Wrappers.evNumber)
},
(),
)
let twoToOne = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs->Prepare.ToValueTuple.twoNumbers->E.R2.fmap(fn)->E.R2.fmap(Wrappers.evNumber)
},
(),
)
let threeToOne = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs->Prepare.ToValueTuple.threeNumbers->E.R2.fmap(fn)->E.R2.fmap(Wrappers.evNumber)
},
(),
)
}
}

View File

@ -1,6 +1,7 @@
let fnList = Belt.Array.concatMany([
FR_Dict.library,
FR_Dist.library,
FR_Danger.library,
FR_Fn.library,
FR_Sampleset.library,
FR_List.library,

View File

@ -0,0 +1,462 @@
/* Notes: See commit 5ce0a6979d9f95d77e4ddbdffc40009de73821e3 for last commit which has more detailed helper functions. These might be useful when coming back to this code after a long time. */
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "Danger"
let requiresNamespace = true
module Combinatorics = {
module Helpers = {
let laplace = ((successes, trials)) => (successes +. 1.0) /. (trials +. 2.0)
let factorial = Stdlib.Math.factorial
let choose = ((n, k)) => factorial(n) /. (factorial(n -. k) *. factorial(k))
let pow = (base, exp) => Js.Math.pow_float(~base, ~exp)
let binomial = ((n, k, p)) => choose((n, k)) *. pow(p, k) *. pow(1.0 -. p, n -. k)
}
module Lib = {
let laplace = Function.make(
~name="laplace",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.laplace(1, 20)`],
~definitions=[DefineFn.Numbers.twoToOne("laplace", Helpers.laplace)],
(),
)
let factorial = Function.make(
~name="factorial",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.factorial(20)`],
~definitions=[DefineFn.Numbers.oneToOne("factorial", Helpers.factorial)],
(),
)
let choose = Function.make(
~name="choose",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.choose(1, 20)`],
~definitions=[DefineFn.Numbers.twoToOne("choose", Helpers.choose)],
(),
)
let binomial = Function.make(
~name="binomial",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.binomial(1, 20, 0.5)`],
~definitions=[DefineFn.Numbers.threeToOne("binomial", Helpers.binomial)],
(),
)
}
}
module Integration = {
module Helpers = {
let integrateFunctionBetweenWithNumIntegrationPoints = (
aLambda,
min: float,
max: float,
numIntegrationPoints: float, // cast as int?
environment,
reducer,
) => {
let applyFunctionAtFloatToFloatOption = (point: float) => {
// Defined here so that it has access to environment, reducer
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
aLambda,
list{pointAsInternalExpression},
environment,
reducer,
)
let result = switch resultAsInternalExpression {
| Ok(IEvNumber(x)) => Ok(x)
| Error(_) =>
Error(
"Error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
)
| _ => Error("Error 2 in Danger.integrate")
}
result
}
// Variables are punctiliously defined because it's otherwise easy to make off-by one errors.
let numTotalPoints = Belt.Float.toInt(numIntegrationPoints) // superflous declaration, but useful to keep track that we are interpreting "numIntegrationPoints" as the total number on which we evaluate the function, not e.g., as the inner integration points.
let numInnerPoints = numTotalPoints - 2
let numOuterPoints = 2
let totalWeight = max -. min
let weightForAnInnerPoint = totalWeight /. E.I.toFloat(numTotalPoints - 1)
let weightForAnOuterPoint = totalWeight /. E.I.toFloat(numTotalPoints - 1) /. 2.0
let innerPointIncrement = (max -. min) /. E.I.toFloat(numTotalPoints - 1)
let innerXs = Belt.Array.makeBy(numInnerPoints, i =>
min +. Belt_Float.fromInt(i + 1) *. innerPointIncrement
)
// Gotcha: makeBy goes from 0 to (n-1): <https://rescript-lang.org/docs/manual/latest/api/belt/array#makeby>
let ysOptions = Belt.Array.map(innerXs, x => applyFunctionAtFloatToFloatOption(x))
/* Logging, with a worked example. */
// Useful for understanding what is happening.
// assuming min = 0, max = 10, numTotalPoints=10, results below:
let verbose = false
if verbose {
Js.Console.log2("numTotalPoints", numTotalPoints) // 5
Js.Console.log2("numInnerPoints", numInnerPoints) // 3
Js.Console.log2("numOuterPoints", numOuterPoints) // always 2
Js.Console.log2("totalWeight", totalWeight) // 10 - 0 = 10
Js.Console.log2("weightForAnInnerPoint", weightForAnInnerPoint) // 10/4 = 2.5
Js.Console.log2("weightForAnOuterPoint", weightForAnOuterPoint) // 10/4/2 = 1.25
Js.Console.log2(
"weightForAnInnerPoint * numInnerPoints + weightForAnOuterPoint * numOuterPoints",
weightForAnInnerPoint *. E.I.toFloat(numInnerPoints) +.
weightForAnOuterPoint *. E.I.toFloat(numOuterPoints),
) // should be 10
Js.Console.log2(
"sum of weights == totalWeight",
weightForAnInnerPoint *. E.I.toFloat(numInnerPoints) +.
weightForAnOuterPoint *. E.I.toFloat(numOuterPoints) == totalWeight,
) // true
Js.Console.log2("innerPointIncrement", innerPointIncrement) // (10-0)/4 = 2.5
Js.Console.log2("innerXs", innerXs) // 2.5, 5, 7.5
Js.Console.log2("ysOptions", ysOptions)
}
let result = switch E.A.R.firstErrorOrOpen(ysOptions) {
| Ok(ys) => {
let innerPointsSum = ys->E.A.reduce(0.0, (a, b) => a +. b)
let resultWithOuterPoints = switch (
applyFunctionAtFloatToFloatOption(min),
applyFunctionAtFloatToFloatOption(max),
) {
| (Ok(yMin), Ok(yMax)) => {
let result =
(yMin +. yMax) *. weightForAnOuterPoint +. innerPointsSum *. weightForAnInnerPoint
let wrappedResult = result->ReducerInterface_InternalExpressionValue.IEvNumber->Ok
wrappedResult
}
| (Error(b), _) => Error(b)
| (_, Error(b)) => Error(b)
}
resultWithOuterPoints
}
| Error(b) =>
Error(
"Integration error 3 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
"Original error: " ++
b,
)
}
result
}
}
module Lib = {
let integrateFunctionBetweenWithNumIntegrationPoints = Function.make(
~name="integrateFunctionBetweenWithNumIntegrationPoints",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
~examples=[`Danger.integrateFunctionBetweenWithNumIntegrationPoints({|x| x+1}, 1, 10, 10)`],
// For the example of integrating x => x+1 between 1 and 10,
// result should be close to 58.5
// [x^2/2 + x]1_10 = (100/2 + 10) - (1/2 + 1) = 60 - 1.5 = 58.5
// https://www.wolframalpha.com/input?i=integrate+x%2B1+from+1+to+10
~definitions=[
FnDefinition.make(
~name="integrateFunctionBetweenWithNumIntegrationPoints",
~inputs=[FRTypeLambda, FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => {
let result = switch inputs {
| [_, _, _, IEvNumber(0.0)] =>
Error("Integration error 4 in Danger.integrate: Increment can't be 0.")
| [
IEvLambda(aLambda),
IEvNumber(min),
IEvNumber(max),
IEvNumber(numIntegrationPoints),
] =>
Helpers.integrateFunctionBetweenWithNumIntegrationPoints(
aLambda,
min,
max,
numIntegrationPoints,
env,
reducer,
)
| _ =>
Error(
"Integration error 5 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))",
)
}
result
},
(),
),
],
(),
)
let integrateFunctionBetweenWithEpsilon = Function.make(
~name="integrateFunctionBetweenWithEpsilon",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
~examples=[`Danger.integrateFunctionBetweenWithEpsilon({|x| x+1}, 1, 10, 0.1)`],
~definitions=[
FnDefinition.make(
~name="integrateFunctionBetweenWithEpsilon",
~inputs=[FRTypeLambda, FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => {
let result = switch inputs {
| [_, _, _, IEvNumber(0.0)] =>
Error("Integration error in Danger.integrate: Increment can't be 0.")
| [IEvLambda(aLambda), IEvNumber(min), IEvNumber(max), IEvNumber(epsilon)] =>
Helpers.integrateFunctionBetweenWithNumIntegrationPoints(
aLambda,
min,
max,
(max -. min) /. epsilon,
env,
reducer,
)->E.R2.errMap(b =>
"Integration error 7 in Danger.integrate. Something went wrong along the way: " ++ b
)
| _ =>
Error(
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))",
)
}
result
},
(),
),
],
(),
)
}
}
module DiminishingReturns = {
module Helpers = {
type diminishingReturnsAccumulatorInner = {
optimalAllocations: array<float>,
currentMarginalReturns: result<array<float>, string>,
}
let findBiggestElementIndex = xs =>
E.A.reducei(xs, 0, (acc, newElement, index) => {
switch newElement > xs[acc] {
| true => index
| false => acc
}
})
type diminishingReturnsAccumulator = result<diminishingReturnsAccumulatorInner, string>
// TODO: This is so complicated, it probably should be its own file. It might also make sense to have it work in Rescript directly, taking in a function rather than a reducer; then something else can wrap that function in the reducer/lambdas/environment.
/*
The key idea for this function is that
1. we keep track of past spending and current marginal returns for each function
2. we look an additional increment in funds
3. we assign it to the function with the best marginal returns
4. we update the spending, and we compute the new returns for that function, with more spending
- But we only compute the new marginal returns for the function we end up assigning the spending to.
5. We continue doing this until all the funding is exhausted
This is currently being done with a reducer, that keeps track of:
- Value of marginal spending for each function
- How much has been assigned to each function.
*/
/*
Two possible algorithms (n=funds/increment, m=num lambdas)
1. O(n): Iterate through value on next n dollars. At each step, only compute the new marginal return of the function which is spent. (This is what we are doing.)
2. O(n*(m-1)): Iterate through all possible spending combinations. The advantage of this option is that it wouldn't assume that the returns of marginal spending are diminishing.
*/
let optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions = (
lambdas,
funds,
approximateIncrement,
environment,
reducer,
) => {
switch (
E.A.length(lambdas) > 1,
funds > 0.0,
approximateIncrement > 0.0,
funds > approximateIncrement,
) {
| (false, _, _, _) =>
Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, number of functions should be greater than 1.",
)
| (_, false, _, _) =>
Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, funds should be greater than 0.",
)
| (_, _, false, _) =>
Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be greater than 0.",
)
| (_, _, _, false) =>
Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be smaller than funds amount.",
)
| (true, true, true, true) => {
let applyFunctionAtPoint = (lambda, point: float) => {
// Defined here so that it has access to environment, reducer
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
lambda,
list{pointAsInternalExpression},
environment,
reducer,
)
switch resultAsInternalExpression {
| Ok(IEvNumber(x)) => Ok(x)
| Error(_) =>
Error(
"Error 1 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
)
| _ =>
Error(
"Error 2 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
)
}
}
let numDivisions = Js.Math.round(funds /. approximateIncrement)
let increment = funds /. numDivisions
let arrayOfIncrements = Belt.Array.make(Belt.Float.toInt(numDivisions), increment)
// ^ make the increment cleanly divide the amount of funds
// nicely simplifies the calculations.
let initAccumulator: diminishingReturnsAccumulator = Ok({
optimalAllocations: Belt.Array.make(E.A.length(lambdas), 0.0),
currentMarginalReturns: E.A.fmap(
lambda => applyFunctionAtPoint(lambda, 0.0),
lambdas,
)->E.A.R.firstErrorOrOpen,
})
let optimalAllocationEndAccumulator = E.A.reduce(arrayOfIncrements, initAccumulator, (
acc,
newIncrement,
) => {
switch acc {
| Ok(accInner) => {
let oldMarginalReturnsWrapped = accInner.currentMarginalReturns
let newAccWrapped = switch oldMarginalReturnsWrapped {
| Ok(oldMarginalReturns) => {
let indexOfBiggestDMR = findBiggestElementIndex(oldMarginalReturns)
let newOptimalAllocations = Belt.Array.copy(accInner.optimalAllocations)
let newOptimalAllocationsi =
newOptimalAllocations[indexOfBiggestDMR] +. newIncrement
newOptimalAllocations[indexOfBiggestDMR] = newOptimalAllocationsi
let lambdai = lambdas[indexOfBiggestDMR]
let newMarginalResultsLambdai = applyFunctionAtPoint(
lambdai,
newOptimalAllocationsi,
)
let newCurrentMarginalReturns = switch newMarginalResultsLambdai {
| Ok(value) => {
let result = Belt.Array.copy(oldMarginalReturns)
result[indexOfBiggestDMR] = value
Ok(result)
}
| Error(b) => Error(b)
}
let newAcc: diminishingReturnsAccumulatorInner = {
optimalAllocations: newOptimalAllocations,
currentMarginalReturns: newCurrentMarginalReturns,
}
Ok(newAcc)
}
| Error(b) => Error(b)
}
newAccWrapped
}
| Error(b) => Error(b)
}
})
let optimalAllocationResult = switch optimalAllocationEndAccumulator {
| Ok(inner) =>
Ok(FunctionRegistry_Helpers.Wrappers.evArrayOfEvNumber(inner.optimalAllocations))
| Error(b) => Error(b)
}
optimalAllocationResult
}
}
}
}
module Lib = {
let optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions = Function.make(
~name="optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
~nameSpace,
~output=EvtArray,
~requiresNamespace=false,
~examples=[
`Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions([{|x| x+1}, {|y| 10}], 100, 0.01)`,
],
~definitions=[
FnDefinition.make(
~name="optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
~inputs=[FRTypeArray(FRTypeLambda), FRTypeNumber, FRTypeNumber],
~run=(inputs, _, environment, reducer) =>
switch inputs {
| [IEvArray(innerlambdas), IEvNumber(funds), IEvNumber(approximateIncrement)] => {
let individuallyWrappedLambdas = E.A.fmap(innerLambda => {
switch innerLambda {
| ReducerInterface_InternalExpressionValue.IEvLambda(lambda) => Ok(lambda)
| _ =>
Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. A member of the array wasn't a function",
)
}
}, innerlambdas)
let wrappedLambdas = E.A.R.firstErrorOrOpen(individuallyWrappedLambdas)
let result = switch wrappedLambdas {
| Ok(lambdas) => {
let result = Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
lambdas,
funds,
approximateIncrement,
environment,
reducer,
)
result
}
| Error(b) => Error(b)
}
result
}
| _ => Error("Error in Danger.diminishingMarginalReturnsForTwoFunctions")
},
(),
),
],
(),
)
}
}
let library = [
// Combinatorics
Combinatorics.Lib.laplace,
Combinatorics.Lib.factorial,
Combinatorics.Lib.choose,
Combinatorics.Lib.binomial,
// Integration
Integration.Lib.integrateFunctionBetweenWithNumIntegrationPoints,
// ^ Integral in terms of function, min, max, epsilon (distance between points)
// Execution time will be less predictable, because it
// will depend on min, max and epsilon together,
// as well and the complexity of the function
Integration.Lib.integrateFunctionBetweenWithEpsilon,
// ^ Integral in terms of function, min, max, num points
// Note that execution time will be more predictable, because it
// will only depend on num points and the complexity of the function
// Diminishing marginal return functions
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions
]

View File

@ -97,7 +97,9 @@ module Internals = {
})
})
)
let result =
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
result
}
}

View File

@ -4,22 +4,6 @@ open FunctionRegistry_Helpers
let nameSpace = "Number"
let requiresNamespace = false
module NumberToNumber = {
let make = (name, fn) =>
FnDefinition.make(
~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(
@ -52,7 +36,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`floor(3.5)`],
~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)],
~definitions=[DefineFn.Numbers.oneToOne("floor", Js.Math.floor_float)],
(),
),
Function.make(
@ -61,7 +45,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`ceil(3.5)`],
~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)],
~definitions=[DefineFn.Numbers.oneToOne("ceil", Js.Math.ceil_float)],
(),
),
Function.make(
@ -70,7 +54,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`abs(3.5)`],
~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)],
~definitions=[DefineFn.Numbers.oneToOne("abs", Js.Math.abs_float)],
(),
),
Function.make(
@ -79,7 +63,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`exp(3.5)`],
~definitions=[NumberToNumber.make("exp", Js.Math.exp)],
~definitions=[DefineFn.Numbers.oneToOne("exp", Js.Math.exp)],
(),
),
Function.make(
@ -88,7 +72,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`log(3.5)`],
~definitions=[NumberToNumber.make("log", Js.Math.log)],
~definitions=[DefineFn.Numbers.oneToOne("log", Js.Math.log)],
(),
),
Function.make(
@ -97,7 +81,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`log10(3.5)`],
~definitions=[NumberToNumber.make("log10", Js.Math.log10)],
~definitions=[DefineFn.Numbers.oneToOne("log10", Js.Math.log10)],
(),
),
Function.make(
@ -106,7 +90,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`log2(3.5)`],
~definitions=[NumberToNumber.make("log2", Js.Math.log2)],
~definitions=[DefineFn.Numbers.oneToOne("log2", Js.Math.log2)],
(),
),
Function.make(
@ -115,7 +99,7 @@ let library = [
~requiresNamespace,
~output=EvtNumber,
~examples=[`round(3.5)`],
~definitions=[NumberToNumber.make("round", Js.Math.round)],
~definitions=[DefineFn.Numbers.oneToOne("round", Js.Math.round)],
(),
),
Function.make(

View File

@ -5,9 +5,7 @@
"use strict";
function peg$subclass(child, parent) {
function C() {
this.constructor = child;
}
function C() { this.constructor = child; }
C.prototype = parent.prototype;
child.prototype = new C();
}
@ -29,15 +27,13 @@ peg$subclass(peg$SyntaxError, Error);
function peg$padEnd(str, targetLength, padString) {
padString = padString || " ";
if (str.length > targetLength) {
return str;
}
if (str.length > targetLength) { return str; }
targetLength -= str.length;
padString += padString.repeat(targetLength);
return str + padString.slice(0, targetLength);
}
peg$SyntaxError.prototype.format = function (sources) {
peg$SyntaxError.prototype.format = function(sources) {
var str = "Error: " + this.message;
if (this.location) {
var src = null;
@ -52,24 +48,15 @@ peg$SyntaxError.prototype.format = function (sources) {
var loc = this.location.source + ":" + s.line + ":" + s.column;
if (src) {
var e = this.location.end;
var filler = peg$padEnd("", s.line.toString().length, " ");
var filler = peg$padEnd("", s.line.toString().length, ' ');
var line = src[s.line - 1];
var last = s.line === e.line ? e.column : line.length + 1;
var hatLen = last - s.column || 1;
str +=
"\n --> " +
loc +
"\n" +
filler +
" |\n" +
s.line +
" | " +
line +
"\n" +
filler +
" | " +
peg$padEnd("", s.column - 1, " ") +
peg$padEnd("", hatLen, "^");
var hatLen = (last - s.column) || 1;
str += "\n --> " + loc + "\n"
+ filler + " |\n"
+ s.line + " | " + line + "\n"
+ filler + " | " + peg$padEnd("", s.column - 1, ' ')
+ peg$padEnd("", hatLen, "^");
} else {
str += "\n at " + loc;
}
@ -77,35 +64,33 @@ peg$SyntaxError.prototype.format = function (sources) {
return str;
};
peg$SyntaxError.buildMessage = function (expected, found) {
peg$SyntaxError.buildMessage = function(expected, found) {
var DESCRIBE_EXPECTATION_FNS = {
literal: function (expectation) {
return '"' + literalEscape(expectation.text) + '"';
literal: function(expectation) {
return "\"" + literalEscape(expectation.text) + "\"";
},
class: function (expectation) {
var escapedParts = expectation.parts.map(function (part) {
class: function(expectation) {
var escapedParts = expectation.parts.map(function(part) {
return Array.isArray(part)
? classEscape(part[0]) + "-" + classEscape(part[1])
: classEscape(part);
});
return (
"[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]"
);
return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
},
any: function () {
any: function() {
return "any character";
},
end: function () {
end: function() {
return "end of input";
},
other: function (expectation) {
other: function(expectation) {
return expectation.description;
},
}
};
function hex(ch) {
@ -115,17 +100,13 @@ peg$SyntaxError.buildMessage = function (expected, found) {
function literalEscape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/"/g, "\\\"")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function (ch) {
return "\\x0" + hex(ch);
})
.replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) {
return "\\x" + hex(ch);
});
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function classEscape(s) {
@ -138,12 +119,8 @@ peg$SyntaxError.buildMessage = function (expected, found) {
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function (ch) {
return "\\x0" + hex(ch);
})
.replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) {
return "\\x" + hex(ch);
});
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function describeExpectation(expectation) {
@ -174,25 +151,17 @@ peg$SyntaxError.buildMessage = function (expected, found) {
return descriptions[0] + " or " + descriptions[1];
default:
return (
descriptions.slice(0, -1).join(", ") +
", or " +
descriptions[descriptions.length - 1]
);
return descriptions.slice(0, -1).join(", ")
+ ", or "
+ descriptions[descriptions.length - 1];
}
}
function describeFound(found) {
return found ? '"' + literalEscape(found) + '"' : "end of input";
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
}
return (
"Expected " +
describeExpected(expected) +
" but " +
describeFound(found) +
" found."
);
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};
function peg$parse(input, options) {
@ -208,7 +177,7 @@ function peg$parse(input, options) {
var peg$c1 = "#include";
var peg$c2 = "as";
var peg$c3 = "'";
var peg$c4 = '"';
var peg$c4 = "\"";
var peg$c5 = "//";
var peg$c6 = "/*";
var peg$c7 = "*/";
@ -228,8 +197,8 @@ function peg$parse(input, options) {
var peg$e3 = peg$otherExpectation("string");
var peg$e4 = peg$literalExpectation("'", false);
var peg$e5 = peg$classExpectation(["'"], true, false);
var peg$e6 = peg$literalExpectation('"', false);
var peg$e7 = peg$classExpectation(['"'], true, false);
var peg$e6 = peg$literalExpectation("\"", false);
var peg$e7 = peg$classExpectation(["\""], true, false);
var peg$e8 = peg$otherExpectation("comment");
var peg$e9 = peg$literalExpectation("//", false);
var peg$e10 = peg$literalExpectation("/*", false);
@ -243,36 +212,16 @@ function peg$parse(input, options) {
var peg$e18 = peg$classExpectation(["\r", "\n"], true, false);
var peg$e19 = peg$otherExpectation("identifier");
var peg$e20 = peg$classExpectation(["_", ["a", "z"]], false, false);
var peg$e21 = peg$classExpectation(
["_", ["a", "z"], ["0", "9"]],
false,
true
);
var peg$e21 = peg$classExpectation(["_", ["a", "z"], ["0", "9"]], false, true);
var peg$f0 = function (head, tail) {
return [head, ...tail].filter((e) => e != "");
};
var peg$f1 = function () {
return [];
};
var peg$f2 = function (file, variable) {
return [!variable ? "" : variable, file];
};
var peg$f3 = function (characters) {
return characters.join("");
};
var peg$f4 = function (characters) {
return characters.join("");
};
var peg$f5 = function () {
return "";
};
var peg$f6 = function () {
return "";
};
var peg$f7 = function () {
return text();
};
var peg$f0 = function(head, tail) {return [head, ...tail].filter( e => e != '');};
var peg$f1 = function() {return [];};
var peg$f2 = function(file, variable) {return [!variable ? '' : variable, file]};
var peg$f3 = function(characters) {return characters.join('');};
var peg$f4 = function(characters) {return characters.join('');};
var peg$f5 = function() { return '';};
var peg$f6 = function() { return '';};
var peg$f7 = function() {return text();};
var peg$currPos = 0;
var peg$savedPos = 0;
var peg$posDetailsCache = [{ line: 1, column: 1 }];
@ -286,9 +235,7 @@ function peg$parse(input, options) {
if ("startRule" in options) {
if (!(options.startRule in peg$startRuleFunctions)) {
throw new Error(
"Can't start parsing from rule \"" + options.startRule + '".'
);
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
}
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
@ -306,7 +253,7 @@ function peg$parse(input, options) {
return {
source: peg$source,
start: peg$savedPos,
end: peg$currPos,
end: peg$currPos
};
}
@ -315,8 +262,7 @@ function peg$parse(input, options) {
}
function expected(description, location) {
location =
location !== undefined
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
@ -328,8 +274,7 @@ function peg$parse(input, options) {
}
function error(message, location) {
location =
location !== undefined
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
@ -341,12 +286,7 @@ function peg$parse(input, options) {
}
function peg$classExpectation(parts, inverted, ignoreCase) {
return {
type: "class",
parts: parts,
inverted: inverted,
ignoreCase: ignoreCase,
};
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
}
function peg$anyExpectation() {
@ -376,7 +316,7 @@ function peg$parse(input, options) {
details = peg$posDetailsCache[p];
details = {
line: details.line,
column: details.column,
column: details.column
};
while (p < pos) {
@ -405,20 +345,18 @@ function peg$parse(input, options) {
start: {
offset: startPos,
line: startPosDetails.line,
column: startPosDetails.column,
column: startPosDetails.column
},
end: {
offset: endPos,
line: endPosDetails.line,
column: endPosDetails.column,
},
column: endPosDetails.column
}
};
}
function peg$fail(expected) {
if (peg$currPos < peg$maxFailPos) {
return;
}
if (peg$currPos < peg$maxFailPos) { return; }
if (peg$currPos > peg$maxFailPos) {
peg$maxFailPos = peg$currPos;
@ -578,9 +516,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e0);
}
if (peg$silentFails === 0) { peg$fail(peg$e0); }
}
peg$silentFails--;
if (s2 === peg$FAILED) {
@ -650,9 +586,7 @@ function peg$parse(input, options) {
peg$currPos += 8;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e1);
}
if (peg$silentFails === 0) { peg$fail(peg$e1); }
}
if (s2 !== peg$FAILED) {
s3 = [];
@ -685,9 +619,7 @@ function peg$parse(input, options) {
peg$currPos += 2;
} else {
s7 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e2);
}
if (peg$silentFails === 0) { peg$fail(peg$e2); }
}
if (s7 !== peg$FAILED) {
s8 = [];
@ -784,9 +716,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e4);
}
if (peg$silentFails === 0) { peg$fail(peg$e4); }
}
if (s2 !== peg$FAILED) {
s3 = [];
@ -795,9 +725,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e5);
}
if (peg$silentFails === 0) { peg$fail(peg$e5); }
}
while (s4 !== peg$FAILED) {
s3.push(s4);
@ -806,9 +734,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e5);
}
if (peg$silentFails === 0) { peg$fail(peg$e5); }
}
}
if (input.charCodeAt(peg$currPos) === 39) {
@ -816,9 +742,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e4);
}
if (peg$silentFails === 0) { peg$fail(peg$e4); }
}
if (s4 !== peg$FAILED) {
s1 = s3;
@ -843,9 +767,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e6);
}
if (peg$silentFails === 0) { peg$fail(peg$e6); }
}
if (s2 !== peg$FAILED) {
s3 = [];
@ -854,9 +776,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e7);
}
if (peg$silentFails === 0) { peg$fail(peg$e7); }
}
while (s4 !== peg$FAILED) {
s3.push(s4);
@ -865,9 +785,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e7);
}
if (peg$silentFails === 0) { peg$fail(peg$e7); }
}
}
if (input.charCodeAt(peg$currPos) === 34) {
@ -875,9 +793,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e6);
}
if (peg$silentFails === 0) { peg$fail(peg$e6); }
}
if (s4 !== peg$FAILED) {
s1 = s3;
@ -898,9 +814,7 @@ function peg$parse(input, options) {
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e3);
}
if (peg$silentFails === 0) { peg$fail(peg$e3); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -963,9 +877,7 @@ function peg$parse(input, options) {
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e9);
}
if (peg$silentFails === 0) { peg$fail(peg$e9); }
}
if (s1 !== peg$FAILED) {
s2 = [];
@ -998,9 +910,7 @@ function peg$parse(input, options) {
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e8);
}
if (peg$silentFails === 0) { peg$fail(peg$e8); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1027,9 +937,7 @@ function peg$parse(input, options) {
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e10);
}
if (peg$silentFails === 0) { peg$fail(peg$e10); }
}
if (s1 !== peg$FAILED) {
s2 = [];
@ -1038,9 +946,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e11);
}
if (peg$silentFails === 0) { peg$fail(peg$e11); }
}
while (s3 !== peg$FAILED) {
s2.push(s3);
@ -1049,9 +955,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e11);
}
if (peg$silentFails === 0) { peg$fail(peg$e11); }
}
}
if (input.substr(peg$currPos, 2) === peg$c7) {
@ -1059,9 +963,7 @@ function peg$parse(input, options) {
peg$currPos += 2;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e12);
}
if (peg$silentFails === 0) { peg$fail(peg$e12); }
}
if (s3 !== peg$FAILED) {
peg$savedPos = s0;
@ -1077,9 +979,7 @@ function peg$parse(input, options) {
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e8);
}
if (peg$silentFails === 0) { peg$fail(peg$e8); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1105,16 +1005,12 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e14);
}
if (peg$silentFails === 0) { peg$fail(peg$e14); }
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e13);
}
if (peg$silentFails === 0) { peg$fail(peg$e13); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1140,16 +1036,12 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e16);
}
if (peg$silentFails === 0) { peg$fail(peg$e16); }
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e15);
}
if (peg$silentFails === 0) { peg$fail(peg$e15); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1175,16 +1067,12 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e18);
}
if (peg$silentFails === 0) { peg$fail(peg$e18); }
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e17);
}
if (peg$silentFails === 0) { peg$fail(peg$e17); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1213,9 +1101,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e20);
}
if (peg$silentFails === 0) { peg$fail(peg$e20); }
}
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
@ -1225,9 +1111,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e20);
}
if (peg$silentFails === 0) { peg$fail(peg$e20); }
}
}
} else {
@ -1240,9 +1124,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e21);
}
if (peg$silentFails === 0) { peg$fail(peg$e21); }
}
while (s4 !== peg$FAILED) {
s3.push(s4);
@ -1251,9 +1133,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e21);
}
if (peg$silentFails === 0) { peg$fail(peg$e21); }
}
}
s2 = [s2, s3];
@ -1270,9 +1150,7 @@ function peg$parse(input, options) {
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$e19);
}
if (peg$silentFails === 0) { peg$fail(peg$e19); }
}
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
@ -1301,5 +1179,5 @@ function peg$parse(input, options) {
module.exports = {
SyntaxError: peg$SyntaxError,
parse: peg$parse,
parse: peg$parse
};

View File

@ -47,3 +47,7 @@ module Random = {
@module external sample: (array<float>, sampleArgs) => array<float> = "@stdlib/random/sample"
let sample = sample
}
module Math = {
@module external factorial: float => float = "@stdlib/math/base/special/factorial"
}

View File

@ -0,0 +1,86 @@
---
sidebar_position: 10
title: Danger
---
The Danger library contains newer experimental functions which are less stable than Squiggle as a whole. Beware: their name, behavior, namespace or existence may change at any time.
### laplace
```js
Danger.laplace: (number, number) => number
```
Calculates the probability implied by [Laplace's rule of succession](https://en.wikipedia.org/wiki/Rule_of_succession)
```js
trials = 10
successes = 1
Danger.laplace(trials, successes) // (successes + 1) / (trials + 2) = 2 / 12 = 0.1666
```
### factorial
```js
Danger.factorial: (number) => number
```
Returns the factorial of a number
### choose
```js
Danger.choose: (number, number) => number
```
`Danger.choose(n,k)` returns `factorial(n) / (factorial(n - k) *.factorial(k))`, i.e., the number of ways you can choose k items from n choices, without repetition. This function is also known as the [binomial coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient).
### binomial
```js
Danger.binomial: (number, number, number) => number
```
`Danger.binomial(n, k, p)` returns `choose((n, k)) * pow(p, k) * pow(1 - p, n - k)`, i.e., the probability that an event of probability p will happen exactly k times in n draws.
### integrateFunctionBetweenWithNumIntegrationPoints
```js
Danger.integrateFunctionBetweenWithNumIntegrationPoints: (number => number, number, number, number) => number
```
`Danger.integrateFunctionBetweenWithNumIntegrationPoints(f, min, max, numIntegrationPoints)` integrates the function `f` between `min` and `max`, and computes `numIntegrationPoints` in between to do so.
Note that the function `f` has to take in and return numbers. To integrate a function which returns distributios, use:
```js
auxiliaryF(x) = mean(f(x))
Danger.integrateFunctionBetweenWithNumIntegrationPoints(auxiliaryF, min, max, numIntegrationPoints)
```
### integrateFunctionBetweenWithEpsilon
```js
Danger.integrateFunctionBetweenWithEpsilon: (number => number, number, number, number) => number
```
`Danger.integrateFunctionBetweenWithEpsilon(f, min, max, epsilon)` integrates the function `f` between `min` and `max`, and uses an interval of `epsilon` between integration points when doing so. This makes its runtime less predictable than `integrateFunctionBetweenWithNumIntegrationPoints`, because runtime will not only depend on `epsilon`, but also on `min` and `max`.
Same caveats as `integrateFunctionBetweenWithNumIntegrationPoints` apply.
### optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions
```js
Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions: (array<number => number>, number, number) => number
```
`Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions([f1, f2], funds, approximateIncrement)` computes the optimal allocation of $`funds` between `f1` and `f2`. For the answer given to be correct, `f1` and `f2` will have to be decreasing, i.e., if `x > y`, then `f_i(x) < f_i(y)`.
Example:
```js
Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions({|x| 20-x}, {|y| 10}, 100, 0.01)
```
Note also that the array ought to have more than one function in it.

View File

@ -2487,32 +2487,6 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@quri/squiggle-components@^0.3":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@quri/squiggle-components/-/squiggle-components-0.3.2.tgz#4fe9ffb02891704a7bc2ea2f87d5bd45714fcef1"
integrity sha512-Lp0cXrmt2FqVxNpv8Eq7V/femNZ0FeL4bbFo3/v/ApQM1T/OgRJUno7I4t7dPtd4lbuzBVpJpFtnKm7cmBHd5w==
dependencies:
"@floating-ui/react-dom" "^1.0.0"
"@floating-ui/react-dom-interactions" "^0.9.3"
"@headlessui/react" "^1.6.6"
"@heroicons/react" "^1.0.6"
"@hookform/resolvers" "^2.9.7"
"@quri/squiggle-lang" "^0.3.0"
"@react-hook/size" "^2.1.2"
clsx "^1.2.1"
framer-motion "^7.2.1"
lodash "^4.17.21"
react "^18.1.0"
react-ace "^10.1.0"
react-hook-form "^7.34.2"
react-use "^17.4.0"
react-vega "^7.6.0"
vega "^5.22.1"
vega-embed "^6.21.0"
vega-lite "^5.5.0"
vscode-uri "^3.0.3"
yup "^0.32.11"
"@quri/squiggle-lang@^0.2.11":
version "0.2.12"
resolved "https://registry.yarnpkg.com/@quri/squiggle-lang/-/squiggle-lang-0.2.12.tgz#e8fdb22a84aa75df71c071d1ed4ae5c55f15d447"
@ -2525,18 +2499,6 @@
mathjs "^11.0.1"
pdfast "^0.2.0"
"@quri/squiggle-lang@^0.3.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@quri/squiggle-lang/-/squiggle-lang-0.3.1.tgz#b34f340a0adb13602d322869678413c84e20d2e4"
integrity sha512-JBuXkenhjdXI3xYfAimQz8kbVoUaqoEav0KlnOCCYIhZc4SHRc+/qKGu25IC6H87aSAkBUacRkrLnXLFDfayKw==
dependencies:
"@rescript/std" "^9.1.4"
"@stdlib/stats" "^0.0.13"
jstat "^1.9.5"
lodash "^4.17.21"
mathjs "^11.1.0"
pdfast "^0.2.0"
"@react-hook/latest@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80"