feat: calculate multiplication using convolution
This commit is contained in:
parent
cfc1fd2239
commit
468ecc05e3
|
@ -100,6 +100,59 @@ let addContinuousContinuous = (
|
|||
{xs: newXs, ys: newYs}
|
||||
}
|
||||
|
||||
let multiplyContinuousContinuous = (
|
||||
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) // 5000
|
||||
let epsilon = (upperBound -. lowerBound) /. Belt.Int.toFloat(numIntervals) // Js.Math.pow_float(~base=2.0, ~exp=-16.0)
|
||||
let epsilonForIgnoreInIntegral = 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.
|
||||
// I wouldn't worry too much about the O(n^3). At 5000 samples, this takes on the order of 25 million operations
|
||||
// The AMD Ryzen 7 processor in my computer can do around 300K million operations per second.
|
||||
// src: https://wikiless.org/wiki/Instructions_per_second?lang=en#Thousand_instructions_per_second_(TIPS/kIPS)
|
||||
for i in 0 to numIntervals - 1 {
|
||||
// where are the x points in the resulting distribution
|
||||
let z = lowerBound +. float(i) *. epsilon
|
||||
newXs[i] = z
|
||||
newYs[i] = 0.0
|
||||
for j in 0 to numIntervals - 1 {
|
||||
// how fine-grained do we want our approximation of the integral to be.
|
||||
let x = lowerBound +. float(j) *. epsilon
|
||||
let absX = Js.Math.abs_float(x)
|
||||
if absX > epsilonForIgnoreInIntegral {
|
||||
let deltaYi =
|
||||
getApproximatePdfOfS1AtPoint(x) *. getApproximatePdfOfS2AtPoint(z /. x) *. (1 /. x)
|
||||
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}
|
||||
}
|
||||
|
||||
// Main function
|
||||
|
||||
let combineShapesContinuousContinuous = (
|
||||
|
|
Loading…
Reference in New Issue
Block a user