Cleanup part 1
This commit is contained in:
parent
1421c6a9b1
commit
255c1763e5
|
@ -1 +1 @@
|
||||||
let entries = EntryTypes.[ExpressionTreeExamples.entry];
|
let entries = [];
|
|
@ -1,88 +0,0 @@
|
||||||
// Examples:
|
|
||||||
// mm(floor(uniform(30,35)), normal(50,20), [.25,.5])
|
|
||||||
// mm(floor(normal(28,4)), normal(32,2), uniform(20,24), [.5,.2,.1])
|
|
||||||
// mm(5 to 20, floor(normal(20,2)), [.5, .5])"
|
|
||||||
// floor(3 to 4)
|
|
||||||
// uniform(0,1) > 0.3 ? lognormal(6.652, -0.41): 0
|
|
||||||
|
|
||||||
// let timeDist ={
|
|
||||||
// let ingredients = DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
// ~guesstimatorString="(floor(10 to 15))",
|
|
||||||
// ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}),
|
|
||||||
// ~unit=
|
|
||||||
// DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
|
|
||||||
// ());
|
|
||||||
// let inputs = DistPlusRenderer.Inputs.make(~distPlusIngredients=ingredients,())
|
|
||||||
// inputs |> DistPlusRenderer.run
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let setup = dist =>
|
|
||||||
// DistPlusRenderer.Inputs.make(~distPlusIngredients=dist,())
|
|
||||||
// |> DistPlusRenderer.run
|
|
||||||
// |> E.R.fmap(distPlus => <DistPlusPlot distPlus />)
|
|
||||||
// |> E.R.toOption
|
|
||||||
// |> E.O.toExn("")
|
|
||||||
|
|
||||||
// let simpleExample = (name, guesstimatorString) =>
|
|
||||||
// <>
|
|
||||||
// <h3 className="text-gray-600 text-lg font-bold">
|
|
||||||
// {name |> ReasonReact.string}
|
|
||||||
// </h3>
|
|
||||||
// {setup(DistPlusRenderer.Inputs.Ingredients.make(~guesstimatorString, ()))}
|
|
||||||
// </>;
|
|
||||||
|
|
||||||
// let timeExample = (name, guesstimatorString) =>
|
|
||||||
// <>
|
|
||||||
// <h3 className="text-gray-600 text-lg font-bold">
|
|
||||||
// {name |> ReasonReact.string}
|
|
||||||
// </h3>
|
|
||||||
// {setup(
|
|
||||||
// DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
// ~guesstimatorString,
|
|
||||||
// ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
|
|
||||||
// (),
|
|
||||||
// ),
|
|
||||||
// )}
|
|
||||||
// </>;
|
|
||||||
|
|
||||||
// let distributions = () =>
|
|
||||||
// <div>
|
|
||||||
// <div>
|
|
||||||
// <h2 className="text-gray-800 text-xl font-bold">
|
|
||||||
// {"Initial Section" |> ReasonReact.string}
|
|
||||||
// </h2>
|
|
||||||
// {simpleExample("Continuous", "5 to 20")}
|
|
||||||
// {simpleExample("Continuous, wide range", "1 to 1000000")}
|
|
||||||
// {simpleExample("Continuous, tiny values", "0.000000001 to 0.00000001")}
|
|
||||||
// {simpleExample(
|
|
||||||
// "Continuous large values",
|
|
||||||
// "50000000000000 to 200000000000000000",
|
|
||||||
// )}
|
|
||||||
// {simpleExample("Discrete", "floor(10 to 20)")}
|
|
||||||
// {simpleExample(
|
|
||||||
// "Discrete and below 0, normal(10,30)",
|
|
||||||
// "floor(normal(10,30))",
|
|
||||||
// )}
|
|
||||||
// {simpleExample("Discrete, wide range", "floor(10 to 200000)")}
|
|
||||||
// {simpleExample("Mixed", "mm(5 to 20, floor(20 to 30), [.5,.5])")}
|
|
||||||
// {simpleExample("Mixed, Early-Discrete Point", "mm(1, 5 to 20, [.5,.5])")}
|
|
||||||
// {simpleExample(
|
|
||||||
// "Mixed, Two-Discrete Points",
|
|
||||||
// "mm(0,10, 5 to 20, [.5,.5,.5])",
|
|
||||||
// )}
|
|
||||||
// <h2 className="text-gray-800 text-xl font-bold">
|
|
||||||
// {"Over Time" |> ReasonReact.string}
|
|
||||||
// </h2>
|
|
||||||
// {timeExample("Continuous", "5 to 20")}
|
|
||||||
// {timeExample("Continuous Over Long Period", "500 to 200000")}
|
|
||||||
// {timeExample("Continuous Over Short Period", "0.0001 to 0.001")}
|
|
||||||
// {timeExample(
|
|
||||||
// "Continuous Over Very Long Period",
|
|
||||||
// "500 to 20000000000000",
|
|
||||||
// )}
|
|
||||||
// {timeExample("Discrete", "floor(5 to 20)")}
|
|
||||||
// {timeExample("Mixed", "mm(5 to 20, floor(5 to 20), [.5,.5])")}
|
|
||||||
// </div>
|
|
||||||
// </div>;
|
|
||||||
|
|
||||||
// let entry = EntryTypes.(entry(~title="Mixed Distributions", ~render=distributions));
|
|
|
@ -1,72 +0,0 @@
|
||||||
// let setup = dist =>
|
|
||||||
// DistPlusRenderer.Inputs.make(~distPlusIngredients=dist, ())
|
|
||||||
// |> DistPlusRenderer.run
|
|
||||||
// |> E.R.fmap(distPlus => <DistPlusPlot distPlus />)
|
|
||||||
// |> E.R.toOption
|
|
||||||
// |> E.O.toExn("")
|
|
||||||
|
|
||||||
// let simpleExample = (guesstimatorString, ~problem="", ()) =>
|
|
||||||
// <>
|
|
||||||
// <p> {guesstimatorString |> ReasonReact.string} </p>
|
|
||||||
// <p> {problem |> (e => "problem: " ++ e) |> ReasonReact.string} </p>
|
|
||||||
// {setup(
|
|
||||||
// DistPlusRenderer.Inputs.Ingredients.make(~guesstimatorString, ()),
|
|
||||||
// )}
|
|
||||||
// </>;
|
|
||||||
|
|
||||||
let distributions = () =>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<h2 className="text-gray-800 text-xl font-bold">
|
|
||||||
{"Initial Section" |> ReasonReact.string}
|
|
||||||
</h2>
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(-1, 1) + normal(5, 2)",
|
|
||||||
// ~problem="Tails look too flat",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "mm(normal(4,2), normal(10,1))",
|
|
||||||
// ~problem="Tails look too flat",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(-1, 1) * normal(5, 2)",
|
|
||||||
// ~problem="This looks really weird",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(1,2) * normal(2,2) * normal(3,1)",
|
|
||||||
// ~problem="Seems like important parts are cut off",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "mm(uniform(0, 1) , normal(3,2))",
|
|
||||||
// ~problem="Uniform distribution seems to break multimodal",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "truncate(mm(1 to 10, 10 to 30), 10, 20)",
|
|
||||||
// ~problem="Truncate seems to have no effect",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(5,2)*(10^3)",
|
|
||||||
// ~problem="Multiplied items should be evaluated.",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(5,10*3)",
|
|
||||||
// ~problem="At least simple operations in the distributions should be evaluated.",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
// {simpleExample(
|
|
||||||
// "normal(5,10)^3",
|
|
||||||
// ~problem="Exponentiation not yet supported",
|
|
||||||
// (),
|
|
||||||
// )}
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
let entry =
|
|
||||||
EntryTypes.(entry(~title="ExpressionTree", ~render=distributions));
|
|
20
src/App.re
20
src/App.re
|
@ -1,26 +1,15 @@
|
||||||
type route =
|
type route =
|
||||||
| Model(string)
|
|
||||||
| DistBuilder
|
| DistBuilder
|
||||||
| Home
|
| Home
|
||||||
| NotFound;
|
| NotFound;
|
||||||
|
|
||||||
let routeToPath = route =>
|
let routeToPath = route =>
|
||||||
switch (route) {
|
switch (route) {
|
||||||
| Model(modelId) => "/m/" ++ modelId
|
|
||||||
| DistBuilder => "/dist-builder"
|
| DistBuilder => "/dist-builder"
|
||||||
| Home => "/"
|
| Home => "/"
|
||||||
| _ => "/"
|
| _ => "/"
|
||||||
};
|
};
|
||||||
|
|
||||||
module Models = {
|
|
||||||
let all = [|
|
|
||||||
EAFunds.Interface.model,
|
|
||||||
GlobalCatastrophe.Interface.model,
|
|
||||||
Human.Interface.model,
|
|
||||||
|];
|
|
||||||
let getById = id => E.A.getBy(all, r => r.id == id);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Menu = {
|
module Menu = {
|
||||||
module Styles = {
|
module Styles = {
|
||||||
open Css;
|
open Css;
|
||||||
|
@ -82,7 +71,6 @@ let make = () => {
|
||||||
|
|
||||||
let routing =
|
let routing =
|
||||||
switch (url.path) {
|
switch (url.path) {
|
||||||
| ["m", modelId] => Model(modelId)
|
|
||||||
| ["dist-builder"] => DistBuilder
|
| ["dist-builder"] => DistBuilder
|
||||||
| [] => Home
|
| [] => Home
|
||||||
| _ => NotFound
|
| _ => NotFound
|
||||||
|
@ -91,14 +79,6 @@ let make = () => {
|
||||||
<>
|
<>
|
||||||
<Menu />
|
<Menu />
|
||||||
{switch (routing) {
|
{switch (routing) {
|
||||||
| Model(id) =>
|
|
||||||
(
|
|
||||||
switch (Models.getById(id)) {
|
|
||||||
| Some(model) => <FormBuilder.ModelForm model key=id />
|
|
||||||
| None => <div> {"Page is not found" |> R.ste} </div>
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> fixedLength
|
|
||||||
| DistBuilder => <DistBuilder />
|
| DistBuilder => <DistBuilder />
|
||||||
| Home => <Home />
|
| Home => <Home />
|
||||||
| _ => fixedLength({"Page is not found" |> R.ste})
|
| _ => fixedLength({"Page is not found" |> R.ste})
|
||||||
|
|
|
@ -21,7 +21,6 @@ export class CodeEditor extends React.Component {
|
||||||
mode="golang"
|
mode="golang"
|
||||||
height="400px"
|
height="400px"
|
||||||
width="100%"
|
width="100%"
|
||||||
keyboardHandler="vim"
|
|
||||||
theme="github"
|
theme="github"
|
||||||
showGutter={false}
|
showGutter={false}
|
||||||
highlightActiveLine={false}
|
highlightActiveLine={false}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Highly Speculative Forecasts</title>
|
<title>Squiggle Language</title>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
||||||
<link href="./styles/index.css" rel="stylesheet">
|
<link href="./styles/index.css" rel="stylesheet">
|
||||||
<script src="./Index.re" defer></script>
|
<script src="./Index.re" defer></script>
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
open Prop;
|
|
||||||
|
|
||||||
type formState = {
|
|
||||||
combo: Combo.t,
|
|
||||||
setCombo: (Combo.t => Combo.t) => unit,
|
|
||||||
setInputValue: (Combo.t, string, option(Value.t)) => unit,
|
|
||||||
};
|
|
||||||
|
|
||||||
let makeHelpers = (combo): formState => {
|
|
||||||
let (combo, setCombo) = React.useState(() => combo);
|
|
||||||
let setInputValue = (combo, id, newValue) =>
|
|
||||||
setCombo(_ => Combo.updateInputValue(combo, id, newValue));
|
|
||||||
{combo, setCombo, setInputValue};
|
|
||||||
};
|
|
||||||
|
|
||||||
let propValue = (t: Prop.Value.t) => {
|
|
||||||
switch (t) {
|
|
||||||
| SelectSingle(r) => r |> ReasonReact.string
|
|
||||||
| ConditionalArray(r) => "Array" |> ReasonReact.string
|
|
||||||
| DistPlusIngredients((r: DistPlusRenderer.Inputs.ingredients)) =>
|
|
||||||
let newDistribution =
|
|
||||||
DistPlusRenderer.Inputs.make(
|
|
||||||
~distPlusIngredients=r,
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
|> DistPlusRenderer.run;
|
|
||||||
switch (newDistribution) {
|
|
||||||
| Ok(distribution) => <div> <DistPlusPlot distPlus=distribution /> </div>
|
|
||||||
// <input
|
|
||||||
// readOnly=true
|
|
||||||
// className="shadow appearance-none border w-1/3 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
|
||||||
// value={r.guesstimatorString}
|
|
||||||
// />
|
|
||||||
// <select
|
|
||||||
// defaultValue="years"
|
|
||||||
// readOnly=true
|
|
||||||
// className="appearance-none w-32 bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline">
|
|
||||||
// <option> {"years" |> ReasonReact.string} </option>
|
|
||||||
// </select>
|
|
||||||
// <div
|
|
||||||
// className="w-1/3 border w-1/2 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline bg-white">
|
|
||||||
// {"30 to infinity, 80% mass" |> ReasonReact.string}
|
|
||||||
// </div>
|
|
||||||
| Error(e) => e |> ReasonReact.string
|
|
||||||
};
|
|
||||||
| FloatCdf(_) => <div />
|
|
||||||
| Probability(r) =>
|
|
||||||
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string
|
|
||||||
| DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string
|
|
||||||
| FloatPoint(r) => r |> Js.Float.toFixed |> ReasonReact.string
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module ModelForm = {
|
|
||||||
let handleChange = (handleChange, event) =>
|
|
||||||
handleChange(ReactEvent.Form.target(event)##value);
|
|
||||||
|
|
||||||
[@react.component]
|
|
||||||
let make = (~model: Model.t) => {
|
|
||||||
let formState = makeHelpers(Combo.fromModel(model));
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="bg-white rounded px-8 pt-6 pb-8 mb-4 mt-6 border-gray-200 border-solid border-2">
|
|
||||||
<h1 className="text-gray-800 text-xl font-bold">
|
|
||||||
{model.name |> ReasonReact.string}
|
|
||||||
</h1>
|
|
||||||
<p> {model.description |> ReasonReact.string} </p>
|
|
||||||
<p> {model.author |> ReasonReact.string} </p>
|
|
||||||
<ForetoldComponents.Link
|
|
||||||
href={
|
|
||||||
"https://github.com/foretold-app/estiband/blob/master/src/models/"
|
|
||||||
++ model.fileName
|
|
||||||
}>
|
|
||||||
{"Model Code" |> ReasonReact.string}
|
|
||||||
</ForetoldComponents.Link>
|
|
||||||
{Combo.inputTypeValuePairs(formState.combo)
|
|
||||||
|> E.A.fmap(((type_: TypeWithMetadata.t, value)) =>
|
|
||||||
<div className="box-border">
|
|
||||||
<label
|
|
||||||
className="block text-gray-700 text-sm font-bold mb-2 w-32 mt-3">
|
|
||||||
{type_.name |> ReasonReact.string}
|
|
||||||
</label>
|
|
||||||
<ValueForm
|
|
||||||
type_
|
|
||||||
value
|
|
||||||
onChange={newValue =>
|
|
||||||
formState.setInputValue(
|
|
||||||
formState.combo,
|
|
||||||
type_.id,
|
|
||||||
newValue,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|> ReasonReact.array}
|
|
||||||
<div className="bg-green-100 p-2 rounded-sm mt-6 text-lg">
|
|
||||||
{model.run(Prop.Combo.InputValues.toValueArray(formState.combo))
|
|
||||||
|> R.O.fmapOrNull(propValue)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,329 +0,0 @@
|
||||||
module Value = {
|
|
||||||
type conditional = {
|
|
||||||
name: string,
|
|
||||||
truthValue: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
type t =
|
|
||||||
| SelectSingle(string)
|
|
||||||
| DateTime(MomentRe.Moment.t)
|
|
||||||
| FloatPoint(float)
|
|
||||||
| Probability(float)
|
|
||||||
| DistPlusIngredients(DistPlusRenderer.Inputs.ingredients)
|
|
||||||
| ConditionalArray(array(conditional))
|
|
||||||
| FloatCdf(string);
|
|
||||||
|
|
||||||
module ConditionalArray = {
|
|
||||||
let get = (conditionals: array(conditional), name: string) =>
|
|
||||||
Belt.Array.getBy(conditionals, (c: conditional) => c.name == name);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module ValueCombination = {
|
|
||||||
type pointsToEvenlySample = int;
|
|
||||||
|
|
||||||
type dateTimeRange = {
|
|
||||||
startTime: MomentRe.Moment.t,
|
|
||||||
endTime: MomentRe.Moment.t,
|
|
||||||
pointsWithin: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type floatPointRange = {
|
|
||||||
startTime: float,
|
|
||||||
endTime: float,
|
|
||||||
pointsWithin: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type range('a) = {
|
|
||||||
beginning: 'a,
|
|
||||||
ending: 'a,
|
|
||||||
pointsToEvenlySample,
|
|
||||||
};
|
|
||||||
|
|
||||||
type t =
|
|
||||||
| SelectSingle
|
|
||||||
| DateTime(range(MomentRe.Moment.t))
|
|
||||||
| FloatPoint(range(MomentRe.Moment.t))
|
|
||||||
| Probability(pointsToEvenlySample);
|
|
||||||
};
|
|
||||||
|
|
||||||
module ValueCluster = {
|
|
||||||
type conditional = {
|
|
||||||
name: string,
|
|
||||||
truthValue: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
type pointsToEvenlySample = int;
|
|
||||||
|
|
||||||
type dateTimeRange = {
|
|
||||||
startTime: MomentRe.Moment.t,
|
|
||||||
endTime: MomentRe.Moment.t,
|
|
||||||
pointsWithin: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type floatPointRange = {
|
|
||||||
startTime: float,
|
|
||||||
endTime: float,
|
|
||||||
pointsWithin: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type range('a) = {
|
|
||||||
beginning: 'a,
|
|
||||||
ending: 'a,
|
|
||||||
pointsToEvenlySample,
|
|
||||||
};
|
|
||||||
|
|
||||||
type t =
|
|
||||||
| SelectSingle([ | `combination | `item(string)])
|
|
||||||
| DateTime(
|
|
||||||
[
|
|
||||||
| `combination(range(MomentRe.Moment.t))
|
|
||||||
| `item(MomentRe.Moment.t)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
| FloatPoint(
|
|
||||||
[ | `combination(range(MomentRe.Moment.t)) | `item(string)],
|
|
||||||
)
|
|
||||||
| Probability([ | `item(string)])
|
|
||||||
| DistPlusIngredients([ | `item(DistPlusRenderer.Inputs.ingredients)])
|
|
||||||
| ConditionalArray([ | `item(array(conditional))])
|
|
||||||
| FloatCdf([ | `item(string)]);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Type = {
|
|
||||||
type selectOption = {
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
type selectSingle = {
|
|
||||||
options: list(selectOption),
|
|
||||||
default: option(string),
|
|
||||||
};
|
|
||||||
|
|
||||||
type conditionals = {
|
|
||||||
defaults: array(Value.conditional),
|
|
||||||
options: array(string),
|
|
||||||
};
|
|
||||||
|
|
||||||
let makeConditionals = (defaults, options): conditionals => {
|
|
||||||
defaults,
|
|
||||||
options,
|
|
||||||
};
|
|
||||||
|
|
||||||
type floatPoint = {validatations: list(float => bool)};
|
|
||||||
|
|
||||||
type withDefaultMinMax('a) = {
|
|
||||||
default: option('a),
|
|
||||||
min: option('a),
|
|
||||||
max: option('a),
|
|
||||||
};
|
|
||||||
|
|
||||||
type withDefault('a) = {default: option('a)};
|
|
||||||
|
|
||||||
type t =
|
|
||||||
| SelectSingle(selectSingle)
|
|
||||||
| FloatPoint(withDefaultMinMax(float))
|
|
||||||
| Probability(withDefault(float))
|
|
||||||
| DateTime(withDefaultMinMax(MomentRe.Moment.t))
|
|
||||||
| Year(withDefaultMinMax(float))
|
|
||||||
| Conditionals(conditionals)
|
|
||||||
| FloatCdf;
|
|
||||||
|
|
||||||
let default = (t: t) =>
|
|
||||||
switch (t) {
|
|
||||||
| Conditionals(s) => Some(Value.ConditionalArray(s.defaults))
|
|
||||||
| Year(r) => r.default->Belt.Option.map(p => Value.FloatPoint(p))
|
|
||||||
| FloatPoint(r) => r.default->Belt.Option.map(p => Value.FloatPoint(p))
|
|
||||||
| Probability(r) => r.default->Belt.Option.map(p => Value.Probability(p))
|
|
||||||
| DateTime(r) => r.default->Belt.Option.map(p => Value.DateTime(p))
|
|
||||||
| SelectSingle(r) =>
|
|
||||||
r.default->Belt.Option.map(p => Value.SelectSingle(p))
|
|
||||||
| FloatCdf => None
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module ValueMap = {
|
|
||||||
module MS = Belt.Map.String;
|
|
||||||
type t = MS.t(Value.t);
|
|
||||||
let get = (t: t, s) => MS.get(t, s);
|
|
||||||
let keys = MS.keysToArray;
|
|
||||||
let map = MS.map;
|
|
||||||
let fromArray = (r): t => MS.fromArray(r);
|
|
||||||
let values = (t: t) => t |> MS.valuesToArray;
|
|
||||||
let update = (t, k, v) => MS.update(t, k, _ => v);
|
|
||||||
let toArray = MS.toArray;
|
|
||||||
let fromOptionalMap = (t: MS.t(option(Value.t))): t =>
|
|
||||||
MS.keep(t, (_, d) => E.O.isSome(d))
|
|
||||||
->MS.map(d => E.O.toExn("This should not have happened", d));
|
|
||||||
let fromOptionalArray = (r): t => MS.fromArray(r) |> fromOptionalMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
module ValueClusterMap = {
|
|
||||||
module MS = Belt.Map.String;
|
|
||||||
type t = MS.t(ValueCluster.t);
|
|
||||||
let get = (t: t, s) => MS.get(t, s);
|
|
||||||
let keys = MS.keysToArray;
|
|
||||||
let map = MS.map;
|
|
||||||
let fromArray = (r): t => MS.fromArray(r);
|
|
||||||
let values = (t: t) => t |> MS.valuesToArray;
|
|
||||||
let update = (t, k, v) => MS.update(t, k, _ => v);
|
|
||||||
let toArray = MS.toArray;
|
|
||||||
let fromOptionalMap = (t: MS.t(option(ValueCluster.t))): t =>
|
|
||||||
MS.keep(t, (_, d) => E.O.isSome(d))
|
|
||||||
->MS.map(d => E.O.toExn("This should not have happened", d));
|
|
||||||
let fromOptionalArray = (r): t => MS.fromArray(r) |> fromOptionalMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
module TypeWithMetadata = {
|
|
||||||
// TODO: Figure out a better name for assumptionType
|
|
||||||
type assumptionType =
|
|
||||||
| PRIMARY_INPUT
|
|
||||||
| ASSUMPTION;
|
|
||||||
|
|
||||||
type t = {
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
description: option(string),
|
|
||||||
type_: Type.t,
|
|
||||||
assumptionType,
|
|
||||||
};
|
|
||||||
|
|
||||||
type ts = array(t);
|
|
||||||
|
|
||||||
let make =
|
|
||||||
(
|
|
||||||
~name,
|
|
||||||
~type_,
|
|
||||||
~id=name,
|
|
||||||
~description=None,
|
|
||||||
~assumptionType=PRIMARY_INPUT,
|
|
||||||
(),
|
|
||||||
) => {
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
type_,
|
|
||||||
description,
|
|
||||||
assumptionType,
|
|
||||||
};
|
|
||||||
|
|
||||||
let currentYear =
|
|
||||||
make(
|
|
||||||
~id="currentYear",
|
|
||||||
~name="Current Day",
|
|
||||||
~description=None,
|
|
||||||
~type_=
|
|
||||||
DateTime({
|
|
||||||
default: Some(MomentRe.momentNow()),
|
|
||||||
min: Some(MomentRe.momentNow()),
|
|
||||||
max: Some(MomentRe.momentNow()),
|
|
||||||
}),
|
|
||||||
~assumptionType=ASSUMPTION,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let age =
|
|
||||||
make(
|
|
||||||
~id="age",
|
|
||||||
~name="Current Age",
|
|
||||||
~description=None,
|
|
||||||
~type_=
|
|
||||||
FloatPoint({
|
|
||||||
default: Some(40.0),
|
|
||||||
min: Some(0.0),
|
|
||||||
max: Some(100.0),
|
|
||||||
}),
|
|
||||||
~assumptionType=PRIMARY_INPUT,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let sex =
|
|
||||||
make(
|
|
||||||
~id="sex",
|
|
||||||
~name="Sex",
|
|
||||||
~description=None,
|
|
||||||
~type_=
|
|
||||||
SelectSingle({
|
|
||||||
options: [
|
|
||||||
{id: "male", name: "Male"},
|
|
||||||
{id: "female", name: "Female"},
|
|
||||||
],
|
|
||||||
default: Some("female"),
|
|
||||||
}),
|
|
||||||
~assumptionType=PRIMARY_INPUT,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Model = {
|
|
||||||
type t = {
|
|
||||||
name: string,
|
|
||||||
id: string,
|
|
||||||
fileName: string,
|
|
||||||
description: string,
|
|
||||||
author: string,
|
|
||||||
version: string,
|
|
||||||
inputTypes: array(TypeWithMetadata.t),
|
|
||||||
outputTypes: array(TypeWithMetadata.t),
|
|
||||||
run: array(option(Value.t)) => option(Value.t),
|
|
||||||
}
|
|
||||||
and combo = {
|
|
||||||
model: t,
|
|
||||||
inputValues: ValueMap.t,
|
|
||||||
outputValues: ValueMap.t,
|
|
||||||
};
|
|
||||||
|
|
||||||
module InputTypes = {
|
|
||||||
let keys = (t: t) =>
|
|
||||||
t.inputTypes |> E.A.fmap((r: TypeWithMetadata.t) => r.id);
|
|
||||||
|
|
||||||
let getBy = (t: t, fn) => t.inputTypes |> E.A.getBy(_, fn);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Combo = {
|
|
||||||
type t = Model.combo;
|
|
||||||
type valueArray = array(option(Value.t));
|
|
||||||
|
|
||||||
module InputValues = {
|
|
||||||
let defaults = (t: Model.t) =>
|
|
||||||
t.inputTypes
|
|
||||||
|> E.A.fmap((o: TypeWithMetadata.t) => (o.id, Type.default(o.type_)))
|
|
||||||
|> ValueMap.fromOptionalArray;
|
|
||||||
|
|
||||||
let isValid = (t: t) =>
|
|
||||||
t.model
|
|
||||||
|> Model.InputTypes.keys
|
|
||||||
|> E.A.fmap(ValueMap.get(t.inputValues))
|
|
||||||
|> Belt.Array.some(_, E.O.isNone);
|
|
||||||
|
|
||||||
let update = (t: t, key: string, onUpdate: option(Value.t)) =>
|
|
||||||
ValueMap.update(t.inputValues, key, onUpdate);
|
|
||||||
|
|
||||||
let toValueArray = (t: t): valueArray => {
|
|
||||||
t.model.inputTypes
|
|
||||||
|> E.A.fmap((r: TypeWithMetadata.t) =>
|
|
||||||
t.inputValues->ValueMap.get(r.id)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let updateInputValue = (t: t, k, u) => {
|
|
||||||
...t,
|
|
||||||
inputValues: InputValues.update(t, k, u),
|
|
||||||
};
|
|
||||||
|
|
||||||
let inputTypeValuePairs = (t: t) =>
|
|
||||||
t.model.inputTypes
|
|
||||||
|> E.A.fmap((i: TypeWithMetadata.t) =>
|
|
||||||
(i, ValueMap.get(t.inputValues, i.id))
|
|
||||||
);
|
|
||||||
|
|
||||||
let fromModel = (t: Model.t): t => {
|
|
||||||
model: t,
|
|
||||||
inputValues: InputValues.defaults(t),
|
|
||||||
outputValues: InputValues.defaults(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
let run = (t: t, f): ValueMap.t => f(t.inputValues);
|
|
||||||
};
|
|
|
@ -1,157 +0,0 @@
|
||||||
open Prop;
|
|
||||||
let handleChange = (handleChange, event) =>
|
|
||||||
handleChange(ReactEvent.Form.target(event)##value);
|
|
||||||
type onChange = option(Value.t) => unit;
|
|
||||||
|
|
||||||
module ConditionalReducer = {
|
|
||||||
type action =
|
|
||||||
| ADD_OR_UPDATE_CONDITIONAL(Value.conditional)
|
|
||||||
| REMOVE_CONDITIONAL(Value.conditional);
|
|
||||||
|
|
||||||
let reducer = (items: array(Value.conditional), action: action) =>
|
|
||||||
switch (action) {
|
|
||||||
| ADD_OR_UPDATE_CONDITIONAL(conditional) =>
|
|
||||||
items->E.A.hasBy(c => c.name == conditional.name)
|
|
||||||
? items
|
|
||||||
|> E.A.fmap((r: Value.conditional) =>
|
|
||||||
r.name == conditional.name ? conditional : r
|
|
||||||
)
|
|
||||||
: E.A.append(items, [|conditional|])
|
|
||||||
| REMOVE_CONDITIONAL(conditional) =>
|
|
||||||
items
|
|
||||||
|> E.A.filter((c: Value.conditional) => c.name != conditional.name)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
[@react.component]
|
|
||||||
let make =
|
|
||||||
(
|
|
||||||
~type_: TypeWithMetadata.t,
|
|
||||||
~value: option(Value.t),
|
|
||||||
~onChange: onChange,
|
|
||||||
) => {
|
|
||||||
switch (type_.type_, value) {
|
|
||||||
| (Conditionals(l), Some(ConditionalArray(n))) =>
|
|
||||||
<div>
|
|
||||||
{n
|
|
||||||
|> E.A.fmap((r: Value.conditional) =>
|
|
||||||
<div
|
|
||||||
onClick={_ =>
|
|
||||||
onChange(
|
|
||||||
Some(
|
|
||||||
Value.ConditionalArray(
|
|
||||||
ConditionalReducer.reducer(
|
|
||||||
n,
|
|
||||||
REMOVE_CONDITIONAL({name: r.name, truthValue: true}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}>
|
|
||||||
{r.name |> ReasonReact.string}
|
|
||||||
{(r.truthValue ? " = True" : " = False") |> ReasonReact.string}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|> ReasonReact.array}
|
|
||||||
{l.options
|
|
||||||
|> E.A.fmap(r =>
|
|
||||||
<div
|
|
||||||
className="max-w-sm rounded overflow-hidden shadow-sm py-1 px-2 rounded mb-3 bg-gray-200">
|
|
||||||
{r |> ReasonReact.string}
|
|
||||||
<button
|
|
||||||
className="bg-blue-500 hover:bg-blue-700 text-white py-0 px-1 rounded"
|
|
||||||
onClick={e => {
|
|
||||||
ReactEvent.Synthetic.preventDefault(e);
|
|
||||||
onChange(
|
|
||||||
Some(
|
|
||||||
Value.ConditionalArray(
|
|
||||||
ConditionalReducer.reducer(
|
|
||||||
n,
|
|
||||||
ADD_OR_UPDATE_CONDITIONAL({
|
|
||||||
name: r,
|
|
||||||
truthValue: true,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
();
|
|
||||||
}}>
|
|
||||||
{"=True" |> ReasonReact.string}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="hover:bg-red-700 text-white py-0 px-1 rounded bg-red-500"
|
|
||||||
onClick={e => {
|
|
||||||
ReactEvent.Synthetic.preventDefault(e);
|
|
||||||
onChange(
|
|
||||||
Some(
|
|
||||||
Value.ConditionalArray(
|
|
||||||
ConditionalReducer.reducer(
|
|
||||||
n,
|
|
||||||
ADD_OR_UPDATE_CONDITIONAL({
|
|
||||||
name: r,
|
|
||||||
truthValue: false,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}}>
|
|
||||||
{"=False" |> ReasonReact.string}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|> ReasonReact.array}
|
|
||||||
</div>
|
|
||||||
| (Conditionals(l), _) =>
|
|
||||||
l.options |> E.A.fmap(r => r |> ReasonReact.string) |> ReasonReact.array
|
|
||||||
| (Year(_), Some(FloatPoint(r))) =>
|
|
||||||
<input
|
|
||||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
|
||||||
type_="number"
|
|
||||||
value={r |> Js.Float.toString}
|
|
||||||
onChange={handleChange(r =>
|
|
||||||
switch (Js.Float.fromString(r)) {
|
|
||||||
| r => onChange(Some(Value.FloatPoint(r)))
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
| (FloatPoint(_), Some(FloatPoint(r))) =>
|
|
||||||
<input
|
|
||||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
|
||||||
type_="number"
|
|
||||||
value={r |> Js.Float.toString}
|
|
||||||
onChange={handleChange(r =>
|
|
||||||
switch (Js.Float.fromString(r)) {
|
|
||||||
| r => onChange(Some(Value.FloatPoint(r)))
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
| (Year(_), _)
|
|
||||||
| (FloatPoint(_), _) => <input type_="number" value="" />
|
|
||||||
| (SelectSingle(t), Some(SelectSingle(r))) =>
|
|
||||||
<select
|
|
||||||
defaultValue=r
|
|
||||||
className="block appearance-none w-full bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline"
|
|
||||||
onChange={handleChange(l => onChange(Some(Value.SelectSingle(l))))}>
|
|
||||||
{t.options
|
|
||||||
|> E.A.of_list
|
|
||||||
|> E.A.fmap((l: Type.selectOption) =>
|
|
||||||
<option value={l.id} key={l.id}>
|
|
||||||
{l.name |> ReasonReact.string}
|
|
||||||
</option>
|
|
||||||
)
|
|
||||||
|> ReasonReact.array}
|
|
||||||
</select>
|
|
||||||
| (DateTime(_), Some(DateTime((d: MomentRe.Moment.t)))) =>
|
|
||||||
<input
|
|
||||||
type_="date"
|
|
||||||
value={MomentRe.Moment.format("YYYY-MM-DD", d)}
|
|
||||||
onChange={handleChange(r =>
|
|
||||||
onChange(
|
|
||||||
Some(Value.DateTime(MomentRe.momentWithFormat(r, "YYYY-MM-DD"))),
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,306 +0,0 @@
|
||||||
module Data = {
|
|
||||||
type fund =
|
|
||||||
| ANIMAL_WELFARE
|
|
||||||
| GLOBAL_HEALTH
|
|
||||||
| LONG_TERM_FUTURE
|
|
||||||
| META;
|
|
||||||
|
|
||||||
type group =
|
|
||||||
| Fund(fund)
|
|
||||||
| All;
|
|
||||||
|
|
||||||
type output =
|
|
||||||
| DONATIONS
|
|
||||||
| CHANCE_OF_EXISTENCE
|
|
||||||
| PAYOUTS;
|
|
||||||
|
|
||||||
type conditionals =
|
|
||||||
| WORLD_CATASTROPHE;
|
|
||||||
|
|
||||||
type fundWithInfo = {
|
|
||||||
group,
|
|
||||||
name: string,
|
|
||||||
existingDonations: option(float),
|
|
||||||
existingPayouts: option(float),
|
|
||||||
};
|
|
||||||
|
|
||||||
let makeFundWithInfo = (name, group, existingDonations, existingPayouts) => {
|
|
||||||
group,
|
|
||||||
name,
|
|
||||||
existingDonations,
|
|
||||||
existingPayouts,
|
|
||||||
};
|
|
||||||
|
|
||||||
let funds = [|
|
|
||||||
makeFundWithInfo(
|
|
||||||
"Animal Welfare Fund",
|
|
||||||
Fund(ANIMAL_WELFARE),
|
|
||||||
Some(400000.0),
|
|
||||||
Some(100000.0),
|
|
||||||
),
|
|
||||||
makeFundWithInfo(
|
|
||||||
"Global Health Fund",
|
|
||||||
Fund(GLOBAL_HEALTH),
|
|
||||||
Some(400000.0),
|
|
||||||
Some(100000.0),
|
|
||||||
),
|
|
||||||
makeFundWithInfo(
|
|
||||||
"Long Term Future Fund",
|
|
||||||
Fund(LONG_TERM_FUTURE),
|
|
||||||
Some(400000.0),
|
|
||||||
Some(100000.0),
|
|
||||||
),
|
|
||||||
makeFundWithInfo(
|
|
||||||
"Meta Fund",
|
|
||||||
Fund(ANIMAL_WELFARE),
|
|
||||||
Some(400000.0),
|
|
||||||
Some(100000.0),
|
|
||||||
),
|
|
||||||
makeFundWithInfo("All", All, None, None),
|
|
||||||
|];
|
|
||||||
};
|
|
||||||
|
|
||||||
module Model = {
|
|
||||||
open Data;
|
|
||||||
let currentYear = 2020.;
|
|
||||||
let firstYearStdDev = 400000.;
|
|
||||||
type yearlyNumericDiff = {
|
|
||||||
meanDiff: float,
|
|
||||||
stdDiff: float,
|
|
||||||
};
|
|
||||||
|
|
||||||
let yearlyMeanGrowthRateIfNotClosed = (group: group): yearlyNumericDiff => {
|
|
||||||
{meanDiff: 1.1, stdDiff: 1.2};
|
|
||||||
};
|
|
||||||
|
|
||||||
let calculateDifference =
|
|
||||||
(currentValue, dateTime, currentDateTime, y: yearlyNumericDiff) => {
|
|
||||||
let yearDiff = MomentRe.diff(dateTime, currentDateTime, `days) /. 365.;
|
|
||||||
let meanDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff);
|
|
||||||
let stdDevDiff = Js.Math.pow_float(~base=y.stdDiff, ~exp=yearDiff);
|
|
||||||
GuesstimatorDist.logNormal(
|
|
||||||
currentValue *. meanDiff,
|
|
||||||
firstYearStdDev *. stdDevDiff,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let rec currentValue = (group: group, output) => {
|
|
||||||
let sum = (): float =>
|
|
||||||
currentValue(Fund(ANIMAL_WELFARE), output)
|
|
||||||
+. currentValue(Fund(GLOBAL_HEALTH), output)
|
|
||||||
+. currentValue(Fund(LONG_TERM_FUTURE), output)
|
|
||||||
+. currentValue(Fund(META), output);
|
|
||||||
switch (group, output) {
|
|
||||||
| (Fund(ANIMAL_WELFARE), DONATIONS) => 300000.0
|
|
||||||
| (Fund(ANIMAL_WELFARE), PAYOUTS) => 2300000.0
|
|
||||||
| (Fund(GLOBAL_HEALTH), DONATIONS) => 1000000.0
|
|
||||||
| (Fund(GLOBAL_HEALTH), PAYOUTS) => 500000.0
|
|
||||||
| (Fund(LONG_TERM_FUTURE), DONATIONS) => 600000.0
|
|
||||||
| (Fund(LONG_TERM_FUTURE), PAYOUTS) => 120000.0
|
|
||||||
| (Fund(META), DONATIONS) => 9300000.0
|
|
||||||
| (Fund(META), PAYOUTS) => 830000.0
|
|
||||||
| (All, _) => sum()
|
|
||||||
| (_, CHANCE_OF_EXISTENCE) => 0.0
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let xRisk = conditionals =>
|
|
||||||
Prop.Value.ConditionalArray.get(conditionals, "Global Existential Event");
|
|
||||||
|
|
||||||
// TODO: Fixe number that integral is calculated for
|
|
||||||
let getGlobalCatastropheChance = dateTime => {
|
|
||||||
GlobalCatastrophe.makeI(MomentRe.momentNow())
|
|
||||||
|> DistPlusRenderer.Inputs.make(~distPlusIngredients=_, ())
|
|
||||||
|> DistPlusRenderer.run
|
|
||||||
|> E.R.bind(_, r =>
|
|
||||||
r
|
|
||||||
|> DistPlusTime.Integral.xToY(Time(dateTime))
|
|
||||||
|> E.O.toResult("error")
|
|
||||||
)
|
|
||||||
|> E.R.toOption;
|
|
||||||
};
|
|
||||||
|
|
||||||
let make =
|
|
||||||
(
|
|
||||||
group: group,
|
|
||||||
dateTime: MomentRe.Moment.t,
|
|
||||||
currentDateTime: MomentRe.Moment.t,
|
|
||||||
output: output,
|
|
||||||
conditionals: array(Prop.Value.conditional),
|
|
||||||
) => {
|
|
||||||
let xRisk = xRisk(conditionals);
|
|
||||||
switch (output) {
|
|
||||||
| DONATIONS
|
|
||||||
| PAYOUTS =>
|
|
||||||
let difference =
|
|
||||||
calculateDifference(
|
|
||||||
currentValue(group, output),
|
|
||||||
dateTime,
|
|
||||||
currentDateTime,
|
|
||||||
yearlyMeanGrowthRateIfNotClosed(group),
|
|
||||||
);
|
|
||||||
|
|
||||||
let str =
|
|
||||||
switch (xRisk) {
|
|
||||||
| Some({truthValue: true}) => "0"
|
|
||||||
| Some({truthValue: false}) => difference
|
|
||||||
| None =>
|
|
||||||
let foo =
|
|
||||||
getGlobalCatastropheChance(dateTime)
|
|
||||||
|> E.O.fmap(r => {
|
|
||||||
let chance = r;
|
|
||||||
let opposite = 1.0 -. r;
|
|
||||||
let reg = difference;
|
|
||||||
{j|mm(0, $reg, [$chance, $opposite])|j};
|
|
||||||
});
|
|
||||||
foo |> E.O.default("");
|
|
||||||
};
|
|
||||||
|
|
||||||
let distPlusIngredients =
|
|
||||||
DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
~guesstimatorString=str,
|
|
||||||
~domain=Complete,
|
|
||||||
~unit=UnspecifiedDistribution,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
Prop.Value.DistPlusIngredients(distPlusIngredients);
|
|
||||||
|
|
||||||
| CHANCE_OF_EXISTENCE =>
|
|
||||||
Prop.Value.DistPlusIngredients(
|
|
||||||
DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
~guesstimatorString=
|
|
||||||
GuesstimatorDist.min(
|
|
||||||
GlobalCatastrophe.guesstimatorString,
|
|
||||||
GuesstimatorDist.logNormal(20., 2.),
|
|
||||||
),
|
|
||||||
~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
|
|
||||||
~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Interface = {
|
|
||||||
open Data;
|
|
||||||
|
|
||||||
let fundKey = "Fund";
|
|
||||||
let dayKey = "Day";
|
|
||||||
let outputKey = "Output";
|
|
||||||
|
|
||||||
let choiceFromString = (s: string) =>
|
|
||||||
funds |> E.A.getBy(_, r => r.name == s);
|
|
||||||
|
|
||||||
let outputFromString = (s: string) =>
|
|
||||||
switch (s) {
|
|
||||||
| "donations" => DONATIONS
|
|
||||||
| "exists" => CHANCE_OF_EXISTENCE
|
|
||||||
| _ => PAYOUTS
|
|
||||||
};
|
|
||||||
|
|
||||||
let run = (p: array(option(Prop.Value.t))) => {
|
|
||||||
switch (p) {
|
|
||||||
| [|
|
|
||||||
Some(SelectSingle(fund)),
|
|
||||||
Some(DateTime(intendedYear)),
|
|
||||||
Some(DateTime(currentYear)),
|
|
||||||
Some(SelectSingle(output)),
|
|
||||||
Some(ConditionalArray(conditionals)),
|
|
||||||
|] =>
|
|
||||||
choiceFromString(fund)
|
|
||||||
|> E.O.fmap(fund =>
|
|
||||||
Model.make(
|
|
||||||
fund.group,
|
|
||||||
intendedYear,
|
|
||||||
currentYear,
|
|
||||||
outputFromString(output),
|
|
||||||
conditionals,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| _ => None
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let model: Prop.Model.t =
|
|
||||||
Prop.{
|
|
||||||
id: "ea-funds",
|
|
||||||
name: "EA Funds: Donations & Payouts",
|
|
||||||
description: "Calculate the payments and payouts of CEA Funds based on existing data.",
|
|
||||||
version: "1.0.0",
|
|
||||||
fileName: "EAFunds.re",
|
|
||||||
author: "Ozzie Gooen",
|
|
||||||
inputTypes: [|
|
|
||||||
TypeWithMetadata.make(
|
|
||||||
~name=fundKey,
|
|
||||||
~type_=
|
|
||||||
SelectSingle({
|
|
||||||
default: Some(Array.unsafe_get(Data.funds, 0).name),
|
|
||||||
options:
|
|
||||||
Data.funds
|
|
||||||
|> E.A.fmap((r) =>
|
|
||||||
({name: r.name, id: r.name}: Prop.Type.selectOption)
|
|
||||||
)
|
|
||||||
|> Array.to_list,
|
|
||||||
}),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
TypeWithMetadata.make(
|
|
||||||
~name=dayKey,
|
|
||||||
~type_=
|
|
||||||
DateTime({
|
|
||||||
default:
|
|
||||||
Some(
|
|
||||||
MomentRe.Moment.add(
|
|
||||||
~duration=MomentRe.duration(5., `years),
|
|
||||||
MomentRe.momentNow(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
min:
|
|
||||||
Some(
|
|
||||||
MomentRe.Moment.subtract(
|
|
||||||
~duration=MomentRe.duration(20., `years),
|
|
||||||
MomentRe.momentNow(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
max:
|
|
||||||
Some(
|
|
||||||
MomentRe.Moment.add(
|
|
||||||
~duration=MomentRe.duration(20., `years),
|
|
||||||
MomentRe.momentNow(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
TypeWithMetadata.currentYear,
|
|
||||||
TypeWithMetadata.make(
|
|
||||||
~name=outputKey,
|
|
||||||
~type_=
|
|
||||||
SelectSingle({
|
|
||||||
default: Some("Output"),
|
|
||||||
options: [
|
|
||||||
{name: "Donations", id: "donations"},
|
|
||||||
{name: "Funding", id: "funding"},
|
|
||||||
{name: "Closing", id: "exists"},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
TypeWithMetadata.make(
|
|
||||||
~name="Conditionals",
|
|
||||||
~id="conditionals",
|
|
||||||
~type_=
|
|
||||||
Conditionals(
|
|
||||||
Prop.Type.makeConditionals(
|
|
||||||
[||],
|
|
||||||
[|"Global Existential Event"|],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
|],
|
|
||||||
outputTypes: [||],
|
|
||||||
run,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,39 +0,0 @@
|
||||||
let guesstimatorString = "uniform(1, 100)";
|
|
||||||
|
|
||||||
let makeI = (currentDateTime: MomentRe.Moment.t) => {
|
|
||||||
DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
~guesstimatorString,
|
|
||||||
~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
|
|
||||||
~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
module Model = {
|
|
||||||
let make = (currentDateTime: MomentRe.Moment.t) => {
|
|
||||||
Prop.Value.DistPlusIngredients(makeI(currentDateTime));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Interface = {
|
|
||||||
let dayKey = "Day";
|
|
||||||
|
|
||||||
let run = (p: array(option(Prop.Value.t))) => {
|
|
||||||
switch (p) {
|
|
||||||
| [|Some(DateTime(currentYear))|] => Some(Model.make(currentYear))
|
|
||||||
| _ => None
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let model: Prop.Model.t =
|
|
||||||
Prop.{
|
|
||||||
name: "Global Catastrophe",
|
|
||||||
id: "global-catastrophe",
|
|
||||||
fileName: "GlobalCatastrophe.re",
|
|
||||||
description: "The chances of having at least one catastrophe per year in the future, assuming no other catastrophe until then.",
|
|
||||||
version: "1.0.0",
|
|
||||||
author: "Ozzie Gooen",
|
|
||||||
inputTypes: [|TypeWithMetadata.currentYear|],
|
|
||||||
outputTypes: [||],
|
|
||||||
run,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,42 +0,0 @@
|
||||||
let guesstimatorString = age =>
|
|
||||||
GuesstimatorDist.normal(72.0 -. age, 5.0 -. age *. 0.01);
|
|
||||||
|
|
||||||
let makeI = (age: float) => {
|
|
||||||
DistPlusRenderer.Inputs.Ingredients.make(
|
|
||||||
~guesstimatorString=guesstimatorString(age),
|
|
||||||
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
|
|
||||||
~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Model = {
|
|
||||||
let make = (age: float) => {
|
|
||||||
Prop.Value.DistPlusIngredients(makeI(age));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Interface = {
|
|
||||||
let ageKey = "age";
|
|
||||||
|
|
||||||
let run = (p: array(option(Prop.Value.t))) => {
|
|
||||||
switch (p) {
|
|
||||||
| [|Some(FloatPoint(age)), Some(SelectSingle(sex))|] =>
|
|
||||||
Some(Model.make(age))
|
|
||||||
| _ => None
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let model: Prop.Model.t =
|
|
||||||
Prop.{
|
|
||||||
name: "Death Time",
|
|
||||||
id: "human-lifespan",
|
|
||||||
fileName: "Human.re",
|
|
||||||
description: "When will you die?",
|
|
||||||
version: "1.0.0",
|
|
||||||
author: "Ozzie Gooen",
|
|
||||||
inputTypes: [|TypeWithMetadata.age, TypeWithMetadata.sex|],
|
|
||||||
outputTypes: [||],
|
|
||||||
run,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,20 +1,3 @@
|
||||||
type route =
|
|
||||||
| Model(string);
|
|
||||||
|
|
||||||
let routeToPath = route =>
|
|
||||||
switch (route) {
|
|
||||||
| Model(modelId) => "/m/" ++ modelId
|
|
||||||
};
|
|
||||||
|
|
||||||
module Models = {
|
|
||||||
let all = [|
|
|
||||||
EAFunds.Interface.model,
|
|
||||||
GlobalCatastrophe.Interface.model,
|
|
||||||
Human.Interface.model,
|
|
||||||
|];
|
|
||||||
let getById = id => E.A.getBy(all, r => r.id == id);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Styles = {
|
module Styles = {
|
||||||
open Css;
|
open Css;
|
||||||
let h3 = style([fontSize(`em(1.5)), marginBottom(`em(1.5))]);
|
let h3 = style([fontSize(`em(1.5)), marginBottom(`em(1.5))]);
|
||||||
|
@ -30,51 +13,9 @@ module Table = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module Item = {
|
|
||||||
[@react.component]
|
|
||||||
let make = (~model: Prop.Model.t, ~children) => {
|
|
||||||
<div className=TableStyles.row>
|
|
||||||
<div className={TableStyles.col()}>
|
|
||||||
<a
|
|
||||||
href={routeToPath(Model(model.id))}
|
|
||||||
onClick={e => {
|
|
||||||
e->ReactEvent.Synthetic.preventDefault;
|
|
||||||
ReasonReactRouter.push(routeToPath(Model(model.id)));
|
|
||||||
}}>
|
|
||||||
children
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className={TableStyles.col(~f=3.0, ())}>
|
|
||||||
{model.description |> R.ste}
|
|
||||||
</div>
|
|
||||||
<div className={TableStyles.col()}> {model.author |> R.ste} </div>
|
|
||||||
</div>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module ColumnsTitles = {
|
|
||||||
[@react.component]
|
|
||||||
let make = () => {
|
|
||||||
<div className=TableStyles.row>
|
|
||||||
<div className={TableStyles.col()}> {"Name" |> R.ste} </div>
|
|
||||||
<div className={TableStyles.col(~f=3.0, ())}>
|
|
||||||
{"Description" |> R.ste}
|
|
||||||
</div>
|
|
||||||
<div className={TableStyles.col()}> {"Author" |> R.ste} </div>
|
|
||||||
</div>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = () => {
|
let make = () => {
|
||||||
<>
|
<>
|
||||||
<h3 className=Styles.h3> {"Probability Models" |> R.ste} </h3>
|
|
||||||
<ColumnsTitles />
|
|
||||||
{Models.all
|
|
||||||
|> E.A.fmap((model: Prop.Model.t) => {
|
|
||||||
<Item model key={model.id}> {model.name |> R.ste} </Item>
|
|
||||||
})
|
|
||||||
|> ReasonReact.array}
|
|
||||||
</>;
|
</>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user