cleanup: More Dangers cleanup

and formatting
This commit is contained in:
NunoSempere 2022-09-06 14:24:44 +02:00
parent ae71bb8ec5
commit 60e42cf1e8
2 changed files with 442 additions and 408 deletions

View File

@ -233,17 +233,12 @@ module Integration = {
} }
} }
module Internals = { module DiminishingReturns = {
// Diminishing returns module Helpers = {
// Helpers
type diminishingReturnsAccumulatorInner = { type diminishingReturnsAccumulatorInner = {
optimalAllocations: array<float>, optimalAllocations: array<float>,
currentMarginalReturns: result<array<float>, string>, currentMarginalReturns: result<array<float>, string>,
} }
// Cannot be be done by Js.Math.max_int or maxMany_int
// because that function returns the value of the element
// not of the index.
let findBiggestElementIndex = xs => let findBiggestElementIndex = xs =>
E.A.reducei(xs, 0, (acc, newElement, index) => { E.A.reducei(xs, 0, (acc, newElement, index) => {
switch newElement > xs[acc] { switch newElement > xs[acc] {
@ -253,7 +248,19 @@ module Internals = {
}) })
type diminishingReturnsAccumulator = result<diminishingReturnsAccumulatorInner, string> 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. //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.
let diminishingMarginalReturnsForManyFunctions = ( /*
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.
*/
let optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions = (
lambdas, lambdas,
funds, funds,
approximateIncrement, approximateIncrement,
@ -263,7 +270,7 @@ module Internals = {
/* /*
Two possible algorithms (n=funds/increment, m=num lambdas) 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 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
2. O(n*m): Iterate through all possible spending combinations. Fun is, it doesn't assume that the returns of marginal spending are diminishing. 2. O(n*m): 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 applyFunctionAtPoint = (lambda, point: float) => { let applyFunctionAtPoint = (lambda, point: float) => {
// Defined here so that it has access to environment, reducer // Defined here so that it has access to environment, reducer
@ -278,9 +285,12 @@ module Internals = {
| Ok(IEvNumber(x)) => Ok(x) | Ok(IEvNumber(x)) => Ok(x)
| Error(_) => | Error(_) =>
Error( Error(
"Error 1 in Danger.diminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead", "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",
) )
| _ => Error("Error 2 in Danger.diminishingMarginalReturnsForManyFunctions")
} }
} }
@ -307,10 +317,14 @@ module Internals = {
| Ok(oldMarginalReturns) => { | Ok(oldMarginalReturns) => {
let indexOfBiggestDMR = findBiggestElementIndex(oldMarginalReturns) let indexOfBiggestDMR = findBiggestElementIndex(oldMarginalReturns)
let newOptimalAllocations = Belt.Array.copy(accInner.optimalAllocations) let newOptimalAllocations = Belt.Array.copy(accInner.optimalAllocations)
let newOptimalAllocationsi = newOptimalAllocations[indexOfBiggestDMR] +. newIncrement let newOptimalAllocationsi =
newOptimalAllocations[indexOfBiggestDMR] +. newIncrement
newOptimalAllocations[indexOfBiggestDMR] = newOptimalAllocationsi newOptimalAllocations[indexOfBiggestDMR] = newOptimalAllocationsi
let lambdai = lambdas[indexOfBiggestDMR] let lambdai = lambdas[indexOfBiggestDMR]
let newMarginalResultsLambdai = applyFunctionAtPoint(lambdai, newOptimalAllocationsi) let newMarginalResultsLambdai = applyFunctionAtPoint(
lambdai,
newOptimalAllocationsi,
)
let newCurrentMarginalReturns = switch newMarginalResultsLambdai { let newCurrentMarginalReturns = switch newMarginalResultsLambdai {
| Ok(value) => { | Ok(value) => {
let result = Belt.Array.copy(oldMarginalReturns) let result = Belt.Array.copy(oldMarginalReturns)
@ -335,7 +349,8 @@ module Internals = {
}) })
let optimalAllocationResult = switch optimalAllocationEndAccumulator { let optimalAllocationResult = switch optimalAllocationEndAccumulator {
| Ok(inner) => Ok(FunctionRegistry_Helpers.Wrappers.evArrayOfEvNumber(inner.optimalAllocations)) | Ok(inner) =>
Ok(FunctionRegistry_Helpers.Wrappers.evArrayOfEvNumber(inner.optimalAllocations))
| Error(b) => Error(b) | Error(b) => Error(b)
} }
@ -345,37 +360,18 @@ module Internals = {
// ^ helper with the same type as what the result should be. Useful for debugging. // ^ helper with the same type as what the result should be. Useful for debugging.
} }
} }
module Lib = {
let library = [ let optimalAllocationGivenDiminishingMarginalReturnsFunctions2 = Function.make(
// Combinatorics ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions2",
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
// There are functions diminishingMarginalReturnsForFunctions2 through diminishingMarginalReturnsForFunctions7
// Because of this bug: <https://github.com/quantified-uncertainty/squiggle/issues/1090>
// As soon as that is fixed, I will simplify this monstrosity.
Function.make(
~name="diminishingMarginalReturnsForFunctions2",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[`Danger.diminishingMarginalReturnsForFunctions2({|x| 20-x}, {|y| 10}, 100, 0.01)`], ~examples=[
`Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions2({|x| 20-x}, {|y| 10}, 100, 0.01)`,
],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions2", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions2",
~inputs=[FRTypeLambda, FRTypeLambda, FRTypeNumber, FRTypeNumber], ~inputs=[FRTypeLambda, FRTypeLambda, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => ~run=(inputs, _, env, reducer) =>
switch inputs { switch inputs {
@ -385,31 +381,32 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2], [lambda1, lambda2],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions2") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions2")
}, },
(), (),
), ),
], ],
(), (),
), )
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsFunctions3 = Function.make(
~name="diminishingMarginalReturnsForFunctions3", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions3",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForFunctions3({|x| x+1}, {|y| 10}, {|z| 20-2*z}, 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions3({|x| x+1}, {|y| 10}, {|z| 20-2*z}, 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions3", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions3",
~inputs=[FRTypeLambda, FRTypeLambda, FRTypeLambda, FRTypeNumber, FRTypeNumber], ~inputs=[FRTypeLambda, FRTypeLambda, FRTypeLambda, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => ~run=(inputs, _, env, reducer) =>
switch inputs { switch inputs {
@ -420,31 +417,32 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2, lambda3], [lambda1, lambda2, lambda3],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions3") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions3")
}, },
(), (),
), ),
], ],
(), (),
), )
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsFunctions4 = Function.make(
~name="diminishingMarginalReturnsForFunctions4", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions4",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForFunctions4({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions4({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions4", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions4",
~inputs=[ ~inputs=[
FRTypeLambda, FRTypeLambda,
FRTypeLambda, FRTypeLambda,
@ -463,31 +461,32 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2, lambda3, lambda4], [lambda1, lambda2, lambda3, lambda4],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions4") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions4")
}, },
(), (),
), ),
], ],
(), (),
), )
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsFunctions5 = Function.make(
~name="diminishingMarginalReturnsForFunctions5", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions5",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForFunctions5({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions5({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions5", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions5",
~inputs=[ ~inputs=[
FRTypeLambda, FRTypeLambda,
FRTypeLambda, FRTypeLambda,
@ -508,31 +507,32 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2, lambda3, lambda4, lambda5], [lambda1, lambda2, lambda3, lambda4, lambda5],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions5") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions5")
}, },
(), (),
), ),
], ],
(), (),
), )
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsFunctions6 = Function.make(
~name="diminishingMarginalReturnsForFunctions6", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions6",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForFunctions6({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, {|c| 19-c}, 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions6({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, {|c| 19-c}, 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions6", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions6",
~inputs=[ ~inputs=[
FRTypeLambda, FRTypeLambda,
FRTypeLambda, FRTypeLambda,
@ -555,31 +555,32 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2, lambda3, lambda4, lambda5, lambda6], [lambda1, lambda2, lambda3, lambda4, lambda5, lambda6],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions6") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions6")
}, },
(), (),
), ),
], ],
(), (),
), )
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsFunctions7 = Function.make(
~name="diminishingMarginalReturnsForFunctions7", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions7",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForFunctions7({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, {|c| 19-c}, {|d| 20-d/2}, 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions7({|x| x+1}, {|y| 10}, {|z| 20-2*z}, {|a| 15-a}, {|b| 17-b}, {|c| 19-c}, {|d| 20-d/2}, 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForFunctions7", ~name="optimalAllocationGivenDiminishingMarginalReturnsFunctions7",
~inputs=[ ~inputs=[
FRTypeLambda, FRTypeLambda,
FRTypeLambda, FRTypeLambda,
@ -604,33 +605,35 @@ let library = [
IEvNumber(funds), IEvNumber(funds),
IEvNumber(approximateIncrement), IEvNumber(approximateIncrement),
] => ] =>
Internals.diminishingMarginalReturnsForManyFunctions( Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
[lambda1, lambda2, lambda3, lambda4, lambda5, lambda6, lambda7], [lambda1, lambda2, lambda3, lambda4, lambda5, lambda6, lambda7],
funds, funds,
approximateIncrement, approximateIncrement,
env, env,
reducer, reducer,
) )
| _ => Error("Error in Danger.diminishingMarginalReturnsForFunctions4") | _ =>
Error("Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsFunctions7")
}, },
(), (),
), ),
], ],
(), (),
), )
// The following will compile, but not work, because of this bug: <https://github.com/quantified-uncertainty/squiggle/issues/558> Instead, I am creating different functions for different numbers of inputs above. // The following will compile, but not work, because of this bug: <https://github.com/quantified-uncertainty/squiggle/issues/558> Instead, I am creating different functions for different numbers of inputs above.
/* @dead
Function.make( let optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions = Function.make(
~name="diminishingMarginalReturnsForManyFunctions", ~name="optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
~nameSpace, ~nameSpace,
~output=EvtArray, ~output=EvtArray,
~requiresNamespace=false, ~requiresNamespace=false,
~examples=[ ~examples=[
`Danger.diminishingMarginalReturnsForManyFunctions([{|x| x+1}, {|y| 10}], 100, 0.01)`, `Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions([{|x| x+1}, {|y| 10}], 100, 0.01)`,
], ],
~definitions=[ ~definitions=[
FnDefinition.make( FnDefinition.make(
~name="diminishingMarginalReturnsForManyFunctions", ~name="optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
~inputs=[FRTypeArray(FRTypeLambda), FRTypeNumber, FRTypeNumber], ~inputs=[FRTypeArray(FRTypeLambda), FRTypeNumber, FRTypeNumber],
~run=(inputs, _, environment, reducer) => ~run=(inputs, _, environment, reducer) =>
switch inputs { switch inputs {
@ -640,14 +643,14 @@ let library = [
| ReducerInterface_InternalExpressionValue.IEvLambda(lambda) => Ok(lambda) | ReducerInterface_InternalExpressionValue.IEvLambda(lambda) => Ok(lambda)
| _ => | _ =>
Error( Error(
"Error in Danger.diminishingMarginalReturnsForManyFunctions. A member of the array wasn't a function", "Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. A member of the array wasn't a function",
) )
} }
}, innerlambdas) }, innerlambdas)
let wrappedLambdas = E.A.R.firstErrorOrOpen(individuallyWrappedLambdas) let wrappedLambdas = E.A.R.firstErrorOrOpen(individuallyWrappedLambdas)
let result = switch wrappedLambdas { let result = switch wrappedLambdas {
| Ok(lambdas) => { | Ok(lambdas) => {
let result = Internals.diminishingMarginalReturnsForManyFunctions( let result = Helpers.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions(
lambdas, lambdas,
funds, funds,
approximateIncrement, approximateIncrement,
@ -658,7 +661,7 @@ let library = [
} }
| Error(b) => Error(b) | Error(b) => Error(b)
} }
result //Error("wtf man") result
} }
| _ => Error("Error in Danger.diminishingMarginalReturnsForTwoFunctions") | _ => Error("Error in Danger.diminishingMarginalReturnsForTwoFunctions")
}, },
@ -666,6 +669,37 @@ let library = [
), ),
], ],
(), (),
), )
*/ }
}
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
// There are functions optimalAllocationGivenDiminishingMarginalReturnsFunctions2 through optimalAllocationGivenDiminishingMarginalReturnsFunctions7
// because of this bug: <https://github.com/quantified-uncertainty/squiggle/issues/1090>
// As soon as that is fixed, I will delete this bag of functions
// and uncomment the function below
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions2,
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions3,
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions4,
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions5,
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions6,
DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsFunctions7,
// DiminishingReturns.Lib.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions
] ]