Added infinity error; fixed infinities in logs

Value: [1e-3 to 3e-2]
This commit is contained in:
Quinn Dougherty 2022-05-02 17:15:23 -04:00
parent db3acbf96c
commit 2d84805f88
8 changed files with 57 additions and 9 deletions

View File

@ -0,0 +1,19 @@
/*
This test case comes via Nuño https://github.com/quantified-uncertainty/squiggle/issues/433
*/
open Jest
open Expect
open TestHelpers
describe("", () => {
test("", () => {
let scalelog = DistributionOperation.Constructors.scaleLogarithm(~env, mkExponential(10.0), 2.0)
E.R2.bind(DistributionOperation.Constructors.mean(~env), scalelog)
->expect
->toEqual(Ok(-2.348336572091017))
})
})

View File

@ -1,3 +0,0 @@
open Jest
open Expect
open TestHelpers

View File

@ -60,3 +60,19 @@ let cauchyMake = SymbolicDist.Cauchy.make
let lognormalMake = SymbolicDist.Lognormal.make let lognormalMake = SymbolicDist.Lognormal.make
let triangularMake = SymbolicDist.Triangular.make let triangularMake = SymbolicDist.Triangular.make
let floatMake = SymbolicDist.Float.make let floatMake = SymbolicDist.Float.make
let normalMakeR = (mean, stdev) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Normal.make(mean, stdev))
let betaMakeR = (alpha, beta) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Beta.make(alpha, beta))
let exponentialMakeR = rate =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Exponential.make(rate))
let uniformMakeR = (low, high) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Uniform.make(low, high))
let cauchyMakeR = (local, rate) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Cauchy.make(local, rate))
let lognormalMakeR = (mu, sigma) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Lognormal.make(mu, sigma))
let triangularMakeR = (low, mode, high) =>
E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Triangular.make(low, mode, high))
// let floatMakeR = x =>E.R.fmap(s => DistributionTypes.Symbolic(s), SymbolicDist.Float.make(x))

View File

@ -266,6 +266,8 @@ module Constructors = {
let algebraicLogarithm = (~env, dist1, dist2) => let algebraicLogarithm = (~env, dist1, dist2) =>
C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR
let algebraicPower = (~env, dist1, dist2) => C.algebraicPower(dist1, dist2)->run(~env)->toDistR let algebraicPower = (~env, dist1, dist2) => C.algebraicPower(dist1, dist2)->run(~env)->toDistR
let scalePower = (~env, dist, n) => C.scalePower(dist, n)->run(~env)->toDistR
let scaleLogarithm = (~env, dist, n) => C.scaleLogarithm(dist, n)->run(~env)->toDistR
let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR
let pointwiseMultiply = (~env, dist1, dist2) => let pointwiseMultiply = (~env, dist1, dist2) =>
C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR

View File

@ -85,6 +85,10 @@ module Constructors: {
@genType @genType
let algebraicPower: (~env: env, genericDist, genericDist) => result<genericDist, error> let algebraicPower: (~env: env, genericDist, genericDist) => result<genericDist, error>
@genType @genType
let scaleLogarithm: (~env: env, genericDist, float) => result<genericDist, error>
@genType
let scalePower: (~env: env, genericDist, float) => result<genericDist, error>
@genType
let pointwiseAdd: (~env: env, genericDist, genericDist) => result<genericDist, error> let pointwiseAdd: (~env: env, genericDist, genericDist) => result<genericDist, error>
@genType @genType
let pointwiseMultiply: (~env: env, genericDist, genericDist) => result<genericDist, error> let pointwiseMultiply: (~env: env, genericDist, genericDist) => result<genericDist, error>

View File

@ -117,6 +117,7 @@ module DistributionOperation = {
| ToFloat(#Mean) => `mean` | ToFloat(#Mean) => `mean`
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})` | ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
| ToFloat(#Sample) => `sample` | ToFloat(#Sample) => `sample`
| ToFloat(#IntegralSum) => `integralSum`
| ToScore(LogScore(_)) => `logScore` | ToScore(LogScore(_)) => `logScore`
| ToDist(Normalize) => `normalize` | ToDist(Normalize) => `normalize`
| ToDist(ToPointSet) => `toPointSet` | ToDist(ToPointSet) => `toPointSet`

View File

@ -38,11 +38,11 @@ let combinePointwise = (
t1: PointSetTypes.discreteShape, t1: PointSetTypes.discreteShape,
t2: PointSetTypes.discreteShape, t2: PointSetTypes.discreteShape,
): result<PointSetTypes.discreteShape, 'e> => { ): result<PointSetTypes.discreteShape, 'e> => {
let combinedIntegralSum = Common.combineIntegralSums( // let combinedIntegralSum = Common.combineIntegralSums(
integralSumCachesFn, // integralSumCachesFn,
t1.integralSumCache, // t1.integralSumCache,
t2.integralSumCache, // t2.integralSumCache,
) // )
// TODO: does it ever make sense to pointwise combine the integrals here? // TODO: does it ever make sense to pointwise combine the integrals here?
// It could be done for pointwise additions, but is that ever needed? // It could be done for pointwise additions, but is that ever needed?

View File

@ -52,6 +52,7 @@ module Convolution = {
type operationError = type operationError =
| DivisionByZeroError | DivisionByZeroError
| ComplexNumberError | ComplexNumberError
| InfinityError
@genType @genType
module Error = { module Error = {
@ -62,6 +63,7 @@ module Error = {
switch err { switch err {
| DivisionByZeroError => "Cannot divide by zero" | DivisionByZeroError => "Cannot divide by zero"
| ComplexNumberError => "Operation returned complex result" | ComplexNumberError => "Operation returned complex result"
| InfinityError => "Operation returned + or - infinity"
} }
} }
@ -86,6 +88,8 @@ let logarithm = (a: float, b: float): result<float, Error.t> =>
Ok(0.) Ok(0.)
} else if a > 0.0 && b > 0.0 { } else if a > 0.0 && b > 0.0 {
Ok(log(a) /. log(b)) Ok(log(a) /. log(b))
} else if a == 0.0 {
Error(InfinityError)
} else { } else {
Error(ComplexNumberError) Error(ComplexNumberError)
} }
@ -150,7 +154,12 @@ module Scale = {
| #Multiply => Ok(a *. b) | #Multiply => Ok(a *. b)
| #Divide => divide(a, b) | #Divide => divide(a, b)
| #Power => power(a, b) | #Power => power(a, b)
| #Logarithm => logarithm(a, b) | #Logarithm =>
if a < MagicNumbers.Epsilon.seven {
Ok(0.0)
} else {
logarithm(a, b)
}
} }
let format = (operation: t, value, scaleBy) => let format = (operation: t, value, scaleBy) =>