feat: get 'convolutions' working for sum of distributions
This commit is contained in:
parent
8b042db2b8
commit
36b318dede
|
@ -0,0 +1,114 @@
|
||||||
|
let emptyXYShape: PointSetTypes.xyShape = {xs: [], ys: []}
|
||||||
|
exception LogicallyInconsistent(string)
|
||||||
|
|
||||||
|
let getApproximatePdfOfContinuousDistributionAtPoint = (
|
||||||
|
dist: PointSetTypes.xyShape,
|
||||||
|
point: float,
|
||||||
|
): float => {
|
||||||
|
let closestFromBelowIndex = E.A.reducei(dist.xs, None, (accumulator, item, index) =>
|
||||||
|
item < point ? Some(index) : accumulator
|
||||||
|
)
|
||||||
|
let closestFromAboveIndexOption = Belt.Array.getIndexBy(dist.xs, item => item > point)
|
||||||
|
|
||||||
|
let weightedMean = (
|
||||||
|
point: float,
|
||||||
|
closestFromBelow: float,
|
||||||
|
closestFromAbove: float,
|
||||||
|
valueclosestFromBelow,
|
||||||
|
valueclosestFromAbove,
|
||||||
|
): float => {
|
||||||
|
let distance = closestFromAbove -. closestFromBelow
|
||||||
|
let w1 = (point -. closestFromBelow) /. distance
|
||||||
|
let w2 = (closestFromAbove -. point) /. distance
|
||||||
|
let result = w1 *. valueclosestFromAbove +. w2 *. valueclosestFromBelow
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = switch (closestFromBelowIndex, closestFromAboveIndexOption) {
|
||||||
|
| (None, None) =>
|
||||||
|
raise(
|
||||||
|
LogicallyInconsistent(
|
||||||
|
"Logically inconsistent option in NumericShapeCombination2.res. Possibly caused by empty distribution",
|
||||||
|
),
|
||||||
|
) // all are smaller, and all are larger
|
||||||
|
| (None, Some(i)) => 0.0 // none are smaller, all are larger
|
||||||
|
| (Some(i), None) => 0.0 // all are smaller, none are larger
|
||||||
|
| (Some(i), Some(j)) => weightedMean(point, dist.xs[i], dist.xs[j], dist.ys[i], dist.ys[j]) // there is a lowerBound and an upperBound.
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
let addContinuousContinuous = (
|
||||||
|
s1: PointSetTypes.xyShape,
|
||||||
|
s2: PointSetTypes.xyShape,
|
||||||
|
): PointSetTypes.xyShape => {
|
||||||
|
// Assumption: xyShapes are ordered on the x coordinate.
|
||||||
|
|
||||||
|
// Get some needed variables
|
||||||
|
let len1 = XYShape.T.length(s1)
|
||||||
|
let mins1xs = s1.xs[0] // Belt.Array.reduce(s1.xs, s1.xs[0], (a, b) => a < b ? a : b)
|
||||||
|
let maxs1xs = s1.xs[len1 - 1] // Belt.Array.reduce(s1.xs, s1.xs[0], (a, b) => a > b ? a : b)
|
||||||
|
|
||||||
|
let len2 = XYShape.T.length(s2)
|
||||||
|
let mins2xs = s2.xs[0] // Belt.Array.reduce(s1.xs, s1.xs[0], (a, b) => a < b ? a : b)
|
||||||
|
let maxs2xs = s2.xs[len1 - 1] // Belt.Array.reduce(s1.xs, s1.xs[0], (a, b) => a > b ? a : b)
|
||||||
|
|
||||||
|
let lowerBound = mins1xs +. mins2xs
|
||||||
|
let upperBound = maxs1xs +. maxs2xs
|
||||||
|
let numIntervals = 2 * Js.Math.max_int(len1, len2)
|
||||||
|
let epsilon = (upperBound -. lowerBound) /. Belt.Int.toFloat(numIntervals) // Js.Math.pow_float(~base=2.0, ~exp=-16.0)
|
||||||
|
|
||||||
|
let newXs: array<float> = Belt.Array.makeUninitializedUnsafe(numIntervals)
|
||||||
|
let newYs: array<float> = Belt.Array.makeUninitializedUnsafe(numIntervals)
|
||||||
|
|
||||||
|
let getApproximatePdfOfS1AtPoint = x => getApproximatePdfOfContinuousDistributionAtPoint(s1, x)
|
||||||
|
let getApproximatePdfOfS2AtPoint = x => getApproximatePdfOfContinuousDistributionAtPoint(s2, x)
|
||||||
|
let float = x => Belt.Int.toFloat(x)
|
||||||
|
// Compute the integral numerically.
|
||||||
|
for i in 0 to numIntervals - 1 {
|
||||||
|
newXs[i] = lowerBound +. float(i) *. epsilon
|
||||||
|
newYs[i] = 0.0
|
||||||
|
for j in 0 to numIntervals - 1 {
|
||||||
|
let deltaYi =
|
||||||
|
getApproximatePdfOfS1AtPoint(lowerBound +. float(j) *. epsilon) *.
|
||||||
|
getApproximatePdfOfS2AtPoint(float(i) *. epsilon -. float(j) *. epsilon)
|
||||||
|
// lowerBound +. float(i) *. epsilon - (lowerBound +. float(j) *. epsilon)
|
||||||
|
newYs[i] = newYs[i] +. deltaYi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This could be improved by, for instance, choosing the location of the xs strategically
|
||||||
|
// for example, such that each of them is "equidistant" in a cdf, that is, such that the
|
||||||
|
// cdf increases by constant amounts from one point to another.
|
||||||
|
{xs: newXs, ys: newYs}
|
||||||
|
}
|
||||||
|
|
||||||
|
let combineShapesContinuousContinuous = (
|
||||||
|
op: Operation.algebraicOperation,
|
||||||
|
s1: PointSetTypes.xyShape,
|
||||||
|
s2: PointSetTypes.xyShape,
|
||||||
|
): PointSetTypes.xyShape => {
|
||||||
|
let result = switch op {
|
||||||
|
| #Add => addContinuousContinuous(s1, s2)
|
||||||
|
| #Subtract => emptyXYShape
|
||||||
|
| #Multiply => emptyXYShape
|
||||||
|
| #Power => emptyXYShape
|
||||||
|
| #Logarithm => emptyXYShape
|
||||||
|
| #Divide => emptyXYShape
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not sure I understand how to combine continuous and discrete distribution
|
||||||
|
|
||||||
|
let combineShapesContinuousDiscrete = (
|
||||||
|
op: Operation.algebraicOperation,
|
||||||
|
continuousShape: PointSetTypes.xyShape,
|
||||||
|
discreteShape: PointSetTypes.xyShape,
|
||||||
|
): PointSetTypes.xyShape => emptyXYShape
|
||||||
|
|
||||||
|
let combineShapesDiscreteContinuous = (
|
||||||
|
op: Operation.algebraicOperation,
|
||||||
|
discreteShape: PointSetTypes.xyShape,
|
||||||
|
continuousShape: PointSetTypes.xyShape,
|
||||||
|
): PointSetTypes.xyShape => emptyXYShape
|
Loading…
Reference in New Issue
Block a user