Merge pull request #1069 from quantified-uncertainty/more-functions
[work in progress] Add more functions
This commit is contained in:
		
						commit
						9a67b16eee
					
				|  | @ -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", | ||||
|  |  | |||
|  | @ -4,6 +4,6 @@ module.exports = { | |||
|         "tailwindcss/nesting": {}, | ||||
|         tailwindcss: {}, | ||||
|         autoprefixer: {}, | ||||
|     cssnano: {}, | ||||
|   }, | ||||
|         cssnano: {} | ||||
|     } | ||||
| }; | ||||
|  |  | |||
|  | @ -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) | ||||
|         }, | ||||
|         (), | ||||
|       ) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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 | ||||
| ] | ||||
|  | @ -97,7 +97,9 @@ module Internals = { | |||
|         }) | ||||
|       }) | ||||
|     ) | ||||
|     let result = | ||||
|       rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray) | ||||
|     result | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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( | ||||
|  |  | |||
|  | @ -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 | ||||
| }; | ||||
|  |  | |||
|  | @ -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" | ||||
| } | ||||
|  |  | |||
							
								
								
									
										86
									
								
								packages/website/docs/Api/Danger.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								packages/website/docs/Api/Danger.md
									
									
									
									
									
										Normal 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. | ||||
							
								
								
									
										38
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								yarn.lock
									
									
									
									
									
								
							|  | @ -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" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user