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-cli": "^10.0.0", | ||||||
|     "postcss-import": "^14.1.0", |     "postcss-import": "^14.1.0", | ||||||
|     "postcss-loader": "^7.0.1", |     "postcss-loader": "^7.0.1", | ||||||
|  |     "postcss-nesting": "^10.1.10", | ||||||
|     "react": "^18.1.0", |     "react": "^18.1.0", | ||||||
|     "react-scripts": "^5.0.1", |     "react-scripts": "^5.0.1", | ||||||
|     "style-loader": "^3.3.1", |     "style-loader": "^3.3.1", | ||||||
|  |  | ||||||
|  | @ -4,6 +4,6 @@ module.exports = { | ||||||
|         "tailwindcss/nesting": {}, |         "tailwindcss/nesting": {}, | ||||||
|         tailwindcss: {}, |         tailwindcss: {}, | ||||||
|         autoprefixer: {}, |         autoprefixer: {}, | ||||||
|     cssnano: {}, |         cssnano: {} | ||||||
|   }, |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ module Wrappers = { | ||||||
|   let evRecord = r => ReducerInterface_InternalExpressionValue.IEvRecord(r) |   let evRecord = r => ReducerInterface_InternalExpressionValue.IEvRecord(r) | ||||||
|   let evString = r => ReducerInterface_InternalExpressionValue.IEvString(r) |   let evString = r => ReducerInterface_InternalExpressionValue.IEvString(r) | ||||||
|   let symbolicEvDistribution = r => r->DistributionTypes.Symbolic->evDistribution |   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) | 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) |       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([ | let fnList = Belt.Array.concatMany([ | ||||||
|   FR_Dict.library, |   FR_Dict.library, | ||||||
|   FR_Dist.library, |   FR_Dist.library, | ||||||
|  |   FR_Danger.library, | ||||||
|   FR_Fn.library, |   FR_Fn.library, | ||||||
|   FR_Sampleset.library, |   FR_Sampleset.library, | ||||||
|   FR_List.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) |       rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray) | ||||||
|  |     result | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,22 +4,6 @@ open FunctionRegistry_Helpers | ||||||
| let nameSpace = "Number" | let nameSpace = "Number" | ||||||
| let requiresNamespace = false | 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 = { | module ArrayNumberDist = { | ||||||
|   let make = (name, fn) => { |   let make = (name, fn) => { | ||||||
|     FnDefinition.make( |     FnDefinition.make( | ||||||
|  | @ -52,7 +36,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`floor(3.5)`], |     ~examples=[`floor(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], |     ~definitions=[DefineFn.Numbers.oneToOne("floor", Js.Math.floor_float)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -61,7 +45,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`ceil(3.5)`], |     ~examples=[`ceil(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], |     ~definitions=[DefineFn.Numbers.oneToOne("ceil", Js.Math.ceil_float)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -70,7 +54,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`abs(3.5)`], |     ~examples=[`abs(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], |     ~definitions=[DefineFn.Numbers.oneToOne("abs", Js.Math.abs_float)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -79,7 +63,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`exp(3.5)`], |     ~examples=[`exp(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], |     ~definitions=[DefineFn.Numbers.oneToOne("exp", Js.Math.exp)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -88,7 +72,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`log(3.5)`], |     ~examples=[`log(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("log", Js.Math.log)], |     ~definitions=[DefineFn.Numbers.oneToOne("log", Js.Math.log)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -97,7 +81,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`log10(3.5)`], |     ~examples=[`log10(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], |     ~definitions=[DefineFn.Numbers.oneToOne("log10", Js.Math.log10)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -106,7 +90,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`log2(3.5)`], |     ~examples=[`log2(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], |     ~definitions=[DefineFn.Numbers.oneToOne("log2", Js.Math.log2)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  | @ -115,7 +99,7 @@ let library = [ | ||||||
|     ~requiresNamespace, |     ~requiresNamespace, | ||||||
|     ~output=EvtNumber, |     ~output=EvtNumber, | ||||||
|     ~examples=[`round(3.5)`], |     ~examples=[`round(3.5)`], | ||||||
|     ~definitions=[NumberToNumber.make("round", Js.Math.round)], |     ~definitions=[DefineFn.Numbers.oneToOne("round", Js.Math.round)], | ||||||
|     (), |     (), | ||||||
|   ), |   ), | ||||||
|   Function.make( |   Function.make( | ||||||
|  |  | ||||||
|  | @ -5,9 +5,7 @@ | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function peg$subclass(child, parent) { | function peg$subclass(child, parent) { | ||||||
|   function C() { |   function C() { this.constructor = child; } | ||||||
|     this.constructor = child; |  | ||||||
|   } |  | ||||||
|   C.prototype = parent.prototype; |   C.prototype = parent.prototype; | ||||||
|   child.prototype = new C(); |   child.prototype = new C(); | ||||||
| } | } | ||||||
|  | @ -29,9 +27,7 @@ peg$subclass(peg$SyntaxError, Error); | ||||||
| 
 | 
 | ||||||
| function peg$padEnd(str, targetLength, padString) { | function peg$padEnd(str, targetLength, padString) { | ||||||
|   padString = padString || " "; |   padString = padString || " "; | ||||||
|   if (str.length > targetLength) { |   if (str.length > targetLength) { return str; } | ||||||
|     return str; |  | ||||||
|   } |  | ||||||
|   targetLength -= str.length; |   targetLength -= str.length; | ||||||
|   padString += padString.repeat(targetLength); |   padString += padString.repeat(targetLength); | ||||||
|   return str + padString.slice(0, targetLength); |   return str + padString.slice(0, targetLength); | ||||||
|  | @ -52,24 +48,15 @@ peg$SyntaxError.prototype.format = function (sources) { | ||||||
|     var loc = this.location.source + ":" + s.line + ":" + s.column; |     var loc = this.location.source + ":" + s.line + ":" + s.column; | ||||||
|     if (src) { |     if (src) { | ||||||
|       var e = this.location.end; |       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 line = src[s.line - 1]; | ||||||
|       var last = s.line === e.line ? e.column : line.length + 1; |       var last = s.line === e.line ? e.column : line.length + 1; | ||||||
|       var hatLen = last - s.column || 1; |       var hatLen = (last - s.column) || 1; | ||||||
|       str += |       str += "\n --> " + loc + "\n" | ||||||
|         "\n --> " + |           + filler + " |\n" | ||||||
|         loc + |           + s.line + " | " + line + "\n" | ||||||
|         "\n" + |           + filler + " | " + peg$padEnd("", s.column - 1, ' ') | ||||||
|         filler + |           + peg$padEnd("", hatLen, "^"); | ||||||
|         " |\n" + |  | ||||||
|         s.line + |  | ||||||
|         " | " + |  | ||||||
|         line + |  | ||||||
|         "\n" + |  | ||||||
|         filler + |  | ||||||
|         " | " + |  | ||||||
|         peg$padEnd("", s.column - 1, " ") + |  | ||||||
|         peg$padEnd("", hatLen, "^"); |  | ||||||
|     } else { |     } else { | ||||||
|       str += "\n at " + loc; |       str += "\n at " + loc; | ||||||
|     } |     } | ||||||
|  | @ -80,7 +67,7 @@ peg$SyntaxError.prototype.format = function (sources) { | ||||||
| peg$SyntaxError.buildMessage = function(expected, found) { | peg$SyntaxError.buildMessage = function(expected, found) { | ||||||
|   var DESCRIBE_EXPECTATION_FNS = { |   var DESCRIBE_EXPECTATION_FNS = { | ||||||
|     literal: function(expectation) { |     literal: function(expectation) { | ||||||
|       return '"' + literalEscape(expectation.text) + '"'; |       return "\"" + literalEscape(expectation.text) + "\""; | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     class: function(expectation) { |     class: function(expectation) { | ||||||
|  | @ -90,9 +77,7 @@ peg$SyntaxError.buildMessage = function (expected, found) { | ||||||
|           : classEscape(part); |           : classEscape(part); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       return ( |       return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]"; | ||||||
|         "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]" |  | ||||||
|       ); |  | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     any: function() { |     any: function() { | ||||||
|  | @ -105,7 +90,7 @@ peg$SyntaxError.buildMessage = function (expected, found) { | ||||||
| 
 | 
 | ||||||
|     other: function(expectation) { |     other: function(expectation) { | ||||||
|       return expectation.description; |       return expectation.description; | ||||||
|     }, |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   function hex(ch) { |   function hex(ch) { | ||||||
|  | @ -115,17 +100,13 @@ peg$SyntaxError.buildMessage = function (expected, found) { | ||||||
|   function literalEscape(s) { |   function literalEscape(s) { | ||||||
|     return s |     return s | ||||||
|       .replace(/\\/g, "\\\\") |       .replace(/\\/g, "\\\\") | ||||||
|       .replace(/"/g, '\\"') |       .replace(/"/g,  "\\\"") | ||||||
|       .replace(/\0/g, "\\0") |       .replace(/\0/g, "\\0") | ||||||
|       .replace(/\t/g, "\\t") |       .replace(/\t/g, "\\t") | ||||||
|       .replace(/\n/g, "\\n") |       .replace(/\n/g, "\\n") | ||||||
|       .replace(/\r/g, "\\r") |       .replace(/\r/g, "\\r") | ||||||
|       .replace(/[\x00-\x0F]/g, function (ch) { |       .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); }) | ||||||
|         return "\\x0" + hex(ch); |       .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); }); | ||||||
|       }) |  | ||||||
|       .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { |  | ||||||
|         return "\\x" + hex(ch); |  | ||||||
|       }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function classEscape(s) { |   function classEscape(s) { | ||||||
|  | @ -138,12 +119,8 @@ peg$SyntaxError.buildMessage = function (expected, found) { | ||||||
|       .replace(/\t/g, "\\t") |       .replace(/\t/g, "\\t") | ||||||
|       .replace(/\n/g, "\\n") |       .replace(/\n/g, "\\n") | ||||||
|       .replace(/\r/g, "\\r") |       .replace(/\r/g, "\\r") | ||||||
|       .replace(/[\x00-\x0F]/g, function (ch) { |       .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); }) | ||||||
|         return "\\x0" + hex(ch); |       .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); }); | ||||||
|       }) |  | ||||||
|       .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { |  | ||||||
|         return "\\x" + hex(ch); |  | ||||||
|       }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function describeExpectation(expectation) { |   function describeExpectation(expectation) { | ||||||
|  | @ -174,25 +151,17 @@ peg$SyntaxError.buildMessage = function (expected, found) { | ||||||
|         return descriptions[0] + " or " + descriptions[1]; |         return descriptions[0] + " or " + descriptions[1]; | ||||||
| 
 | 
 | ||||||
|       default: |       default: | ||||||
|         return ( |         return descriptions.slice(0, -1).join(", ") | ||||||
|           descriptions.slice(0, -1).join(", ") + |           + ", or " | ||||||
|           ", or " + |           + descriptions[descriptions.length - 1]; | ||||||
|           descriptions[descriptions.length - 1] |  | ||||||
|         ); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function describeFound(found) { |   function describeFound(found) { | ||||||
|     return found ? '"' + literalEscape(found) + '"' : "end of input"; |     return found ? "\"" + literalEscape(found) + "\"" : "end of input"; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return ( |   return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; | ||||||
|     "Expected " + |  | ||||||
|     describeExpected(expected) + |  | ||||||
|     " but " + |  | ||||||
|     describeFound(found) + |  | ||||||
|     " found." |  | ||||||
|   ); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function peg$parse(input, options) { | function peg$parse(input, options) { | ||||||
|  | @ -208,7 +177,7 @@ function peg$parse(input, options) { | ||||||
|   var peg$c1 = "#include"; |   var peg$c1 = "#include"; | ||||||
|   var peg$c2 = "as"; |   var peg$c2 = "as"; | ||||||
|   var peg$c3 = "'"; |   var peg$c3 = "'"; | ||||||
|   var peg$c4 = '"'; |   var peg$c4 = "\""; | ||||||
|   var peg$c5 = "//"; |   var peg$c5 = "//"; | ||||||
|   var peg$c6 = "/*"; |   var peg$c6 = "/*"; | ||||||
|   var peg$c7 = "*/"; |   var peg$c7 = "*/"; | ||||||
|  | @ -228,8 +197,8 @@ function peg$parse(input, options) { | ||||||
|   var peg$e3 = peg$otherExpectation("string"); |   var peg$e3 = peg$otherExpectation("string"); | ||||||
|   var peg$e4 = peg$literalExpectation("'", false); |   var peg$e4 = peg$literalExpectation("'", false); | ||||||
|   var peg$e5 = peg$classExpectation(["'"], true, false); |   var peg$e5 = peg$classExpectation(["'"], true, false); | ||||||
|   var peg$e6 = peg$literalExpectation('"', false); |   var peg$e6 = peg$literalExpectation("\"", false); | ||||||
|   var peg$e7 = peg$classExpectation(['"'], true, false); |   var peg$e7 = peg$classExpectation(["\""], true, false); | ||||||
|   var peg$e8 = peg$otherExpectation("comment"); |   var peg$e8 = peg$otherExpectation("comment"); | ||||||
|   var peg$e9 = peg$literalExpectation("//", false); |   var peg$e9 = peg$literalExpectation("//", false); | ||||||
|   var peg$e10 = 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$e18 = peg$classExpectation(["\r", "\n"], true, false); | ||||||
|   var peg$e19 = peg$otherExpectation("identifier"); |   var peg$e19 = peg$otherExpectation("identifier"); | ||||||
|   var peg$e20 = peg$classExpectation(["_", ["a", "z"]], false, false); |   var peg$e20 = peg$classExpectation(["_", ["a", "z"]], false, false); | ||||||
|   var peg$e21 = peg$classExpectation( |   var peg$e21 = peg$classExpectation(["_", ["a", "z"], ["0", "9"]], false, true); | ||||||
|     ["_", ["a", "z"], ["0", "9"]], |  | ||||||
|     false, |  | ||||||
|     true |  | ||||||
|   ); |  | ||||||
| 
 | 
 | ||||||
|   var peg$f0 = function (head, tail) { |   var peg$f0 = function(head, tail) {return [head, ...tail].filter( e => e != '');}; | ||||||
|     return [head, ...tail].filter((e) => e != ""); |   var peg$f1 = function() {return [];}; | ||||||
|   }; |   var peg$f2 = function(file, variable) {return [!variable ? '' : variable, file]}; | ||||||
|   var peg$f1 = function () { |   var peg$f3 = function(characters) {return characters.join('');}; | ||||||
|     return []; |   var peg$f4 = function(characters) {return characters.join('');}; | ||||||
|   }; |   var peg$f5 = function() { return '';}; | ||||||
|   var peg$f2 = function (file, variable) { |   var peg$f6 = function() { return '';}; | ||||||
|     return [!variable ? "" : variable, file]; |   var peg$f7 = function() {return text();}; | ||||||
|   }; |  | ||||||
|   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$currPos = 0; | ||||||
|   var peg$savedPos = 0; |   var peg$savedPos = 0; | ||||||
|   var peg$posDetailsCache = [{ line: 1, column: 1 }]; |   var peg$posDetailsCache = [{ line: 1, column: 1 }]; | ||||||
|  | @ -286,9 +235,7 @@ function peg$parse(input, options) { | ||||||
| 
 | 
 | ||||||
|   if ("startRule" in options) { |   if ("startRule" in options) { | ||||||
|     if (!(options.startRule in peg$startRuleFunctions)) { |     if (!(options.startRule in peg$startRuleFunctions)) { | ||||||
|       throw new Error( |       throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); | ||||||
|         "Can't start parsing from rule \"" + options.startRule + '".' |  | ||||||
|       ); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; |     peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; | ||||||
|  | @ -306,7 +253,7 @@ function peg$parse(input, options) { | ||||||
|     return { |     return { | ||||||
|       source: peg$source, |       source: peg$source, | ||||||
|       start: peg$savedPos, |       start: peg$savedPos, | ||||||
|       end: peg$currPos, |       end: peg$currPos | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -315,8 +262,7 @@ function peg$parse(input, options) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function expected(description, location) { |   function expected(description, location) { | ||||||
|     location = |     location = location !== undefined | ||||||
|       location !== undefined |  | ||||||
|       ? location |       ? location | ||||||
|       : peg$computeLocation(peg$savedPos, peg$currPos); |       : peg$computeLocation(peg$savedPos, peg$currPos); | ||||||
| 
 | 
 | ||||||
|  | @ -328,8 +274,7 @@ function peg$parse(input, options) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function error(message, location) { |   function error(message, location) { | ||||||
|     location = |     location = location !== undefined | ||||||
|       location !== undefined |  | ||||||
|       ? location |       ? location | ||||||
|       : peg$computeLocation(peg$savedPos, peg$currPos); |       : peg$computeLocation(peg$savedPos, peg$currPos); | ||||||
| 
 | 
 | ||||||
|  | @ -341,12 +286,7 @@ function peg$parse(input, options) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function peg$classExpectation(parts, inverted, ignoreCase) { |   function peg$classExpectation(parts, inverted, ignoreCase) { | ||||||
|     return { |     return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; | ||||||
|       type: "class", |  | ||||||
|       parts: parts, |  | ||||||
|       inverted: inverted, |  | ||||||
|       ignoreCase: ignoreCase, |  | ||||||
|     }; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function peg$anyExpectation() { |   function peg$anyExpectation() { | ||||||
|  | @ -376,7 +316,7 @@ function peg$parse(input, options) { | ||||||
|       details = peg$posDetailsCache[p]; |       details = peg$posDetailsCache[p]; | ||||||
|       details = { |       details = { | ||||||
|         line: details.line, |         line: details.line, | ||||||
|         column: details.column, |         column: details.column | ||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|       while (p < pos) { |       while (p < pos) { | ||||||
|  | @ -405,20 +345,18 @@ function peg$parse(input, options) { | ||||||
|       start: { |       start: { | ||||||
|         offset: startPos, |         offset: startPos, | ||||||
|         line: startPosDetails.line, |         line: startPosDetails.line, | ||||||
|         column: startPosDetails.column, |         column: startPosDetails.column | ||||||
|       }, |       }, | ||||||
|       end: { |       end: { | ||||||
|         offset: endPos, |         offset: endPos, | ||||||
|         line: endPosDetails.line, |         line: endPosDetails.line, | ||||||
|         column: endPosDetails.column, |         column: endPosDetails.column | ||||||
|       }, |       } | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function peg$fail(expected) { |   function peg$fail(expected) { | ||||||
|     if (peg$currPos < peg$maxFailPos) { |     if (peg$currPos < peg$maxFailPos) { return; } | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (peg$currPos > peg$maxFailPos) { |     if (peg$currPos > peg$maxFailPos) { | ||||||
|       peg$maxFailPos = peg$currPos; |       peg$maxFailPos = peg$currPos; | ||||||
|  | @ -578,9 +516,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s2 = peg$FAILED; |         s2 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e0); } | ||||||
|           peg$fail(peg$e0); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       peg$silentFails--; |       peg$silentFails--; | ||||||
|       if (s2 === peg$FAILED) { |       if (s2 === peg$FAILED) { | ||||||
|  | @ -650,9 +586,7 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos += 8; |       peg$currPos += 8; | ||||||
|     } else { |     } else { | ||||||
|       s2 = peg$FAILED; |       s2 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e1); } | ||||||
|         peg$fail(peg$e1); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     if (s2 !== peg$FAILED) { |     if (s2 !== peg$FAILED) { | ||||||
|       s3 = []; |       s3 = []; | ||||||
|  | @ -685,9 +619,7 @@ function peg$parse(input, options) { | ||||||
|               peg$currPos += 2; |               peg$currPos += 2; | ||||||
|             } else { |             } else { | ||||||
|               s7 = peg$FAILED; |               s7 = peg$FAILED; | ||||||
|               if (peg$silentFails === 0) { |               if (peg$silentFails === 0) { peg$fail(peg$e2); } | ||||||
|                 peg$fail(peg$e2); |  | ||||||
|               } |  | ||||||
|             } |             } | ||||||
|             if (s7 !== peg$FAILED) { |             if (s7 !== peg$FAILED) { | ||||||
|               s8 = []; |               s8 = []; | ||||||
|  | @ -784,9 +716,7 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos++; |       peg$currPos++; | ||||||
|     } else { |     } else { | ||||||
|       s2 = peg$FAILED; |       s2 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e4); } | ||||||
|         peg$fail(peg$e4); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     if (s2 !== peg$FAILED) { |     if (s2 !== peg$FAILED) { | ||||||
|       s3 = []; |       s3 = []; | ||||||
|  | @ -795,9 +725,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s4 = peg$FAILED; |         s4 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e5); } | ||||||
|           peg$fail(peg$e5); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       while (s4 !== peg$FAILED) { |       while (s4 !== peg$FAILED) { | ||||||
|         s3.push(s4); |         s3.push(s4); | ||||||
|  | @ -806,9 +734,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s4 = peg$FAILED; |           s4 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e5); } | ||||||
|             peg$fail(peg$e5); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if (input.charCodeAt(peg$currPos) === 39) { |       if (input.charCodeAt(peg$currPos) === 39) { | ||||||
|  | @ -816,9 +742,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s4 = peg$FAILED; |         s4 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e4); } | ||||||
|           peg$fail(peg$e4); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       if (s4 !== peg$FAILED) { |       if (s4 !== peg$FAILED) { | ||||||
|         s1 = s3; |         s1 = s3; | ||||||
|  | @ -843,9 +767,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s2 = peg$FAILED; |         s2 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e6); } | ||||||
|           peg$fail(peg$e6); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       if (s2 !== peg$FAILED) { |       if (s2 !== peg$FAILED) { | ||||||
|         s3 = []; |         s3 = []; | ||||||
|  | @ -854,9 +776,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s4 = peg$FAILED; |           s4 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e7); } | ||||||
|             peg$fail(peg$e7); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|         while (s4 !== peg$FAILED) { |         while (s4 !== peg$FAILED) { | ||||||
|           s3.push(s4); |           s3.push(s4); | ||||||
|  | @ -865,9 +785,7 @@ function peg$parse(input, options) { | ||||||
|             peg$currPos++; |             peg$currPos++; | ||||||
|           } else { |           } else { | ||||||
|             s4 = peg$FAILED; |             s4 = peg$FAILED; | ||||||
|             if (peg$silentFails === 0) { |             if (peg$silentFails === 0) { peg$fail(peg$e7); } | ||||||
|               peg$fail(peg$e7); |  | ||||||
|             } |  | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         if (input.charCodeAt(peg$currPos) === 34) { |         if (input.charCodeAt(peg$currPos) === 34) { | ||||||
|  | @ -875,9 +793,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s4 = peg$FAILED; |           s4 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e6); } | ||||||
|             peg$fail(peg$e6); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|         if (s4 !== peg$FAILED) { |         if (s4 !== peg$FAILED) { | ||||||
|           s1 = s3; |           s1 = s3; | ||||||
|  | @ -898,9 +814,7 @@ function peg$parse(input, options) { | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e3); } | ||||||
|         peg$fail(peg$e3); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -963,9 +877,7 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos += 2; |       peg$currPos += 2; | ||||||
|     } else { |     } else { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e9); } | ||||||
|         peg$fail(peg$e9); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     if (s1 !== peg$FAILED) { |     if (s1 !== peg$FAILED) { | ||||||
|       s2 = []; |       s2 = []; | ||||||
|  | @ -998,9 +910,7 @@ function peg$parse(input, options) { | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e8); } | ||||||
|         peg$fail(peg$e8); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1027,9 +937,7 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos += 2; |       peg$currPos += 2; | ||||||
|     } else { |     } else { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e10); } | ||||||
|         peg$fail(peg$e10); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     if (s1 !== peg$FAILED) { |     if (s1 !== peg$FAILED) { | ||||||
|       s2 = []; |       s2 = []; | ||||||
|  | @ -1038,9 +946,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s3 = peg$FAILED; |         s3 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e11); } | ||||||
|           peg$fail(peg$e11); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       while (s3 !== peg$FAILED) { |       while (s3 !== peg$FAILED) { | ||||||
|         s2.push(s3); |         s2.push(s3); | ||||||
|  | @ -1049,9 +955,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s3 = peg$FAILED; |           s3 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e11); } | ||||||
|             peg$fail(peg$e11); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if (input.substr(peg$currPos, 2) === peg$c7) { |       if (input.substr(peg$currPos, 2) === peg$c7) { | ||||||
|  | @ -1059,9 +963,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos += 2; |         peg$currPos += 2; | ||||||
|       } else { |       } else { | ||||||
|         s3 = peg$FAILED; |         s3 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e12); } | ||||||
|           peg$fail(peg$e12); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       if (s3 !== peg$FAILED) { |       if (s3 !== peg$FAILED) { | ||||||
|         peg$savedPos = s0; |         peg$savedPos = s0; | ||||||
|  | @ -1077,9 +979,7 @@ function peg$parse(input, options) { | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e8); } | ||||||
|         peg$fail(peg$e8); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1105,16 +1005,12 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos++; |       peg$currPos++; | ||||||
|     } else { |     } else { | ||||||
|       s0 = peg$FAILED; |       s0 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e14); } | ||||||
|         peg$fail(peg$e14); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e13); } | ||||||
|         peg$fail(peg$e13); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1140,16 +1036,12 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos++; |       peg$currPos++; | ||||||
|     } else { |     } else { | ||||||
|       s0 = peg$FAILED; |       s0 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e16); } | ||||||
|         peg$fail(peg$e16); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e15); } | ||||||
|         peg$fail(peg$e15); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1175,16 +1067,12 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos++; |       peg$currPos++; | ||||||
|     } else { |     } else { | ||||||
|       s0 = peg$FAILED; |       s0 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e18); } | ||||||
|         peg$fail(peg$e18); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e17); } | ||||||
|         peg$fail(peg$e17); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1213,9 +1101,7 @@ function peg$parse(input, options) { | ||||||
|       peg$currPos++; |       peg$currPos++; | ||||||
|     } else { |     } else { | ||||||
|       s3 = peg$FAILED; |       s3 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e20); } | ||||||
|         peg$fail(peg$e20); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     if (s3 !== peg$FAILED) { |     if (s3 !== peg$FAILED) { | ||||||
|       while (s3 !== peg$FAILED) { |       while (s3 !== peg$FAILED) { | ||||||
|  | @ -1225,9 +1111,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s3 = peg$FAILED; |           s3 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e20); } | ||||||
|             peg$fail(peg$e20); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|  | @ -1240,9 +1124,7 @@ function peg$parse(input, options) { | ||||||
|         peg$currPos++; |         peg$currPos++; | ||||||
|       } else { |       } else { | ||||||
|         s4 = peg$FAILED; |         s4 = peg$FAILED; | ||||||
|         if (peg$silentFails === 0) { |         if (peg$silentFails === 0) { peg$fail(peg$e21); } | ||||||
|           peg$fail(peg$e21); |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|       while (s4 !== peg$FAILED) { |       while (s4 !== peg$FAILED) { | ||||||
|         s3.push(s4); |         s3.push(s4); | ||||||
|  | @ -1251,9 +1133,7 @@ function peg$parse(input, options) { | ||||||
|           peg$currPos++; |           peg$currPos++; | ||||||
|         } else { |         } else { | ||||||
|           s4 = peg$FAILED; |           s4 = peg$FAILED; | ||||||
|           if (peg$silentFails === 0) { |           if (peg$silentFails === 0) { peg$fail(peg$e21); } | ||||||
|             peg$fail(peg$e21); |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       s2 = [s2, s3]; |       s2 = [s2, s3]; | ||||||
|  | @ -1270,9 +1150,7 @@ function peg$parse(input, options) { | ||||||
|     peg$silentFails--; |     peg$silentFails--; | ||||||
|     if (s0 === peg$FAILED) { |     if (s0 === peg$FAILED) { | ||||||
|       s1 = peg$FAILED; |       s1 = peg$FAILED; | ||||||
|       if (peg$silentFails === 0) { |       if (peg$silentFails === 0) { peg$fail(peg$e19); } | ||||||
|         peg$fail(peg$e19); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; |     peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | ||||||
|  | @ -1301,5 +1179,5 @@ function peg$parse(input, options) { | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|   SyntaxError: peg$SyntaxError, |   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" |   @module external sample: (array<float>, sampleArgs) => array<float> = "@stdlib/random/sample" | ||||||
|   let sample = 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" |   resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" | ||||||
|   integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== |   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": | "@quri/squiggle-lang@^0.2.11": | ||||||
|   version "0.2.12" |   version "0.2.12" | ||||||
|   resolved "https://registry.yarnpkg.com/@quri/squiggle-lang/-/squiggle-lang-0.2.12.tgz#e8fdb22a84aa75df71c071d1ed4ae5c55f15d447" |   resolved "https://registry.yarnpkg.com/@quri/squiggle-lang/-/squiggle-lang-0.2.12.tgz#e8fdb22a84aa75df71c071d1ed4ae5c55f15d447" | ||||||
|  | @ -2525,18 +2499,6 @@ | ||||||
|     mathjs "^11.0.1" |     mathjs "^11.0.1" | ||||||
|     pdfast "^0.2.0" |     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": | "@react-hook/latest@^1.0.2": | ||||||
|   version "1.0.3" |   version "1.0.3" | ||||||
|   resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" |   resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user