2022-02-16 19:57:46 +00:00
|
|
|
// This file has no dependencies. It's used outside of the interpreter, but the interpreter depends on it.
|
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
@genType
|
2022-02-16 19:57:46 +00:00
|
|
|
type algebraicOperation = [
|
|
|
|
| #Add
|
|
|
|
| #Multiply
|
|
|
|
| #Subtract
|
|
|
|
| #Divide
|
2022-04-09 16:37:26 +00:00
|
|
|
| #Power
|
2022-04-01 19:41:11 +00:00
|
|
|
| #Logarithm
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(float)
|
2022-02-16 19:57:46 +00:00
|
|
|
]
|
2022-04-22 16:43:18 +00:00
|
|
|
|
|
|
|
type convolutionOperation = [
|
|
|
|
| #Add
|
|
|
|
| #Multiply
|
|
|
|
| #Subtract
|
|
|
|
]
|
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
@genType
|
2022-04-09 16:37:26 +00:00
|
|
|
type pointwiseOperation = [#Add | #Multiply | #Power]
|
2022-05-04 17:02:58 +00:00
|
|
|
type scaleOperation = [#Multiply | #Power | #Logarithm | #LogarithmWithThreshold(float) | #Divide]
|
2022-02-16 19:57:46 +00:00
|
|
|
type distToFloatOperation = [
|
|
|
|
| #Pdf(float)
|
|
|
|
| #Cdf(float)
|
|
|
|
| #Inv(float)
|
|
|
|
| #Mean
|
|
|
|
| #Sample
|
|
|
|
]
|
2022-02-06 23:10:39 +00:00
|
|
|
|
2022-04-22 16:43:18 +00:00
|
|
|
module Convolution = {
|
|
|
|
type t = convolutionOperation
|
2022-04-27 16:48:46 +00:00
|
|
|
//Only a selection of operations are supported by convolution.
|
|
|
|
let fromAlgebraicOperation = (op: algebraicOperation): option<convolutionOperation> =>
|
|
|
|
switch op {
|
|
|
|
| #Add => Some(#Add)
|
|
|
|
| #Subtract => Some(#Subtract)
|
|
|
|
| #Multiply => Some(#Multiply)
|
2022-05-04 17:02:58 +00:00
|
|
|
| #Divide | #Power | #Logarithm | #LogarithmWithThreshold(_) => None
|
2022-04-27 16:48:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let canDoAlgebraicOperation = (op: algebraicOperation): bool =>
|
|
|
|
fromAlgebraicOperation(op)->E.O.isSome
|
|
|
|
|
2022-04-22 16:43:18 +00:00
|
|
|
let toFn: (t, float, float) => float = x =>
|
|
|
|
switch x {
|
|
|
|
| #Add => \"+."
|
|
|
|
| #Subtract => \"-."
|
|
|
|
| #Multiply => \"*."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-23 18:35:49 +00:00
|
|
|
type operationError =
|
|
|
|
| DivisionByZeroError
|
|
|
|
| ComplexNumberError
|
2022-05-02 21:15:23 +00:00
|
|
|
| InfinityError
|
2022-05-03 14:15:48 +00:00
|
|
|
| NegativeInfinityError
|
2022-05-06 14:49:04 +00:00
|
|
|
| LogicallyInconsistentPathwayError
|
2022-04-23 18:35:49 +00:00
|
|
|
|
2022-04-22 20:27:17 +00:00
|
|
|
@genType
|
2022-04-23 13:56:47 +00:00
|
|
|
module Error = {
|
|
|
|
@genType
|
2022-04-23 18:35:49 +00:00
|
|
|
type t = operationError
|
2022-04-22 20:27:17 +00:00
|
|
|
|
2022-04-23 18:35:49 +00:00
|
|
|
let toString = (err: t): string =>
|
2022-04-23 13:56:47 +00:00
|
|
|
switch err {
|
|
|
|
| DivisionByZeroError => "Cannot divide by zero"
|
|
|
|
| ComplexNumberError => "Operation returned complex result"
|
2022-05-03 14:15:48 +00:00
|
|
|
| InfinityError => "Operation returned positive infinity"
|
|
|
|
| NegativeInfinityError => "Operation returned negative infinity"
|
2022-05-06 14:49:04 +00:00
|
|
|
| LogicallyInconsistentPathwayError => "This pathway should have been logically unreachable"
|
2022-04-23 13:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-22 20:27:17 +00:00
|
|
|
|
2022-04-23 18:35:49 +00:00
|
|
|
let power = (a: float, b: float): result<float, Error.t> =>
|
2022-04-23 18:09:06 +00:00
|
|
|
if a >= 0.0 {
|
|
|
|
Ok(a ** b)
|
|
|
|
} else {
|
|
|
|
Error(ComplexNumberError)
|
|
|
|
}
|
|
|
|
|
2022-04-23 18:35:49 +00:00
|
|
|
let divide = (a: float, b: float): result<float, Error.t> =>
|
2022-04-23 18:09:06 +00:00
|
|
|
if b != 0.0 {
|
|
|
|
Ok(a /. b)
|
|
|
|
} else {
|
|
|
|
Error(DivisionByZeroError)
|
|
|
|
}
|
|
|
|
|
2022-04-23 18:35:49 +00:00
|
|
|
let logarithm = (a: float, b: float): result<float, Error.t> =>
|
2022-04-23 18:09:06 +00:00
|
|
|
if b == 1. {
|
|
|
|
Error(DivisionByZeroError)
|
|
|
|
} else if b == 0. {
|
|
|
|
Ok(0.)
|
|
|
|
} else if a > 0.0 && b > 0.0 {
|
|
|
|
Ok(log(a) /. log(b))
|
2022-05-02 21:15:23 +00:00
|
|
|
} else if a == 0.0 {
|
2022-05-03 14:15:48 +00:00
|
|
|
Error(NegativeInfinityError)
|
2022-04-23 18:09:06 +00:00
|
|
|
} else {
|
|
|
|
Error(ComplexNumberError)
|
|
|
|
}
|
|
|
|
|
2022-04-23 18:16:11 +00:00
|
|
|
@genType
|
2022-02-06 23:10:39 +00:00
|
|
|
module Algebraic = {
|
2022-04-23 18:16:11 +00:00
|
|
|
@genType
|
2022-02-06 23:10:39 +00:00
|
|
|
type t = algebraicOperation
|
2022-04-23 18:35:49 +00:00
|
|
|
let toFn: (t, float, float) => result<float, Error.t> = (x, a, b) =>
|
2022-02-06 23:10:39 +00:00
|
|
|
switch x {
|
2022-04-22 20:27:17 +00:00
|
|
|
| #Add => Ok(a +. b)
|
|
|
|
| #Subtract => Ok(a -. b)
|
|
|
|
| #Multiply => Ok(a *. b)
|
2022-04-23 18:09:06 +00:00
|
|
|
| #Power => power(a, b)
|
|
|
|
| #Divide => divide(a, b)
|
|
|
|
| #Logarithm => logarithm(a, b)
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(eps) =>
|
|
|
|
if a < eps {
|
|
|
|
Ok(0.0)
|
|
|
|
} else {
|
|
|
|
logarithm(a, b)
|
|
|
|
}
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let toString = x =>
|
|
|
|
switch x {
|
|
|
|
| #Add => "+"
|
|
|
|
| #Subtract => "-"
|
|
|
|
| #Multiply => "*"
|
2022-04-09 16:37:26 +00:00
|
|
|
| #Power => "**"
|
2022-02-06 23:10:39 +00:00
|
|
|
| #Divide => "/"
|
2022-04-01 19:41:11 +00:00
|
|
|
| #Logarithm => "log"
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(_) => "log"
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let format = (a, b, c) => b ++ (" " ++ (toString(a) ++ (" " ++ c)))
|
|
|
|
}
|
|
|
|
|
|
|
|
module Pointwise = {
|
|
|
|
type t = pointwiseOperation
|
|
|
|
let toString = x =>
|
|
|
|
switch x {
|
|
|
|
| #Add => "+"
|
2022-04-10 00:36:33 +00:00
|
|
|
| #Power => "**"
|
2022-02-06 23:10:39 +00:00
|
|
|
| #Multiply => "*"
|
|
|
|
}
|
|
|
|
|
|
|
|
let format = (a, b, c) => b ++ (" " ++ (toString(a) ++ (" " ++ c)))
|
|
|
|
}
|
|
|
|
|
|
|
|
module DistToFloat = {
|
|
|
|
type t = distToFloatOperation
|
|
|
|
|
|
|
|
let format = (operation, value) =>
|
|
|
|
switch operation {
|
|
|
|
| #Cdf(f) => j`cdf(x=$f,$value)`
|
|
|
|
| #Pdf(f) => j`pdf(x=$f,$value)`
|
|
|
|
| #Inv(f) => j`inv(x=$f,$value)`
|
|
|
|
| #Sample => "sample($value)"
|
|
|
|
| #Mean => "mean($value)"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note that different logarithms don't really do anything.
|
|
|
|
module Scale = {
|
|
|
|
type t = scaleOperation
|
2022-04-23 18:35:49 +00:00
|
|
|
let toFn = (x: t, a: float, b: float): result<float, Error.t> =>
|
2022-02-06 23:10:39 +00:00
|
|
|
switch x {
|
2022-04-22 20:27:17 +00:00
|
|
|
| #Multiply => Ok(a *. b)
|
2022-04-23 18:09:06 +00:00
|
|
|
| #Divide => divide(a, b)
|
|
|
|
| #Power => power(a, b)
|
2022-05-04 18:55:49 +00:00
|
|
|
| #Logarithm => logarithm(a, b)
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(eps) =>
|
|
|
|
if a < eps {
|
|
|
|
Ok(0.0)
|
|
|
|
} else {
|
|
|
|
logarithm(a, b)
|
|
|
|
}
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let format = (operation: t, value, scaleBy) =>
|
|
|
|
switch operation {
|
|
|
|
| #Multiply => j`verticalMultiply($value, $scaleBy) `
|
2022-03-26 17:25:47 +00:00
|
|
|
| #Divide => j`verticalDivide($value, $scaleBy) `
|
2022-04-09 16:37:26 +00:00
|
|
|
| #Power => j`verticalPower($value, $scaleBy) `
|
2022-04-01 19:41:11 +00:00
|
|
|
| #Logarithm => j`verticalLog($value, $scaleBy) `
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(eps) => j`verticalLog($value, $scaleBy, epsilon=$eps) `
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let toIntegralSumCacheFn = x =>
|
|
|
|
switch x {
|
|
|
|
| #Multiply => (a, b) => Some(a *. b)
|
2022-03-26 17:25:47 +00:00
|
|
|
| #Divide => (a, b) => Some(a /. b)
|
2022-05-04 17:02:58 +00:00
|
|
|
| #Power | #Logarithm | #LogarithmWithThreshold(_) => (_, _) => None
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let toIntegralCacheFn = x =>
|
|
|
|
switch x {
|
2022-02-17 14:50:43 +00:00
|
|
|
| #Multiply => (_, _) => None // TODO: this could probably just be multiplied out (using Continuous.scaleBy)
|
2022-03-26 17:25:47 +00:00
|
|
|
| #Divide => (_, _) => None
|
2022-04-09 16:37:26 +00:00
|
|
|
| #Power => (_, _) => None
|
2022-04-01 19:41:11 +00:00
|
|
|
| #Logarithm => (_, _) => None
|
2022-05-04 17:02:58 +00:00
|
|
|
| #LogarithmWithThreshold(_) => (_, _) => None
|
2022-02-06 23:10:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 19:57:46 +00:00
|
|
|
module Truncate = {
|
|
|
|
let toString = (left: option<float>, right: option<float>, nodeToString) => {
|
2022-02-06 23:10:39 +00:00
|
|
|
let left = left |> E.O.dimap(Js.Float.toString, () => "-inf")
|
|
|
|
let right = right |> E.O.dimap(Js.Float.toString, () => "inf")
|
|
|
|
j`truncate($nodeToString, $left, $right)`
|
|
|
|
}
|
2022-03-22 02:33:28 +00:00
|
|
|
}
|