feat: calculate multiplication using convolution
This commit is contained in:
		
							parent
							
								
									cfc1fd2239
								
							
						
					
					
						commit
						468ecc05e3
					
				|  | @ -100,6 +100,59 @@ let addContinuousContinuous = ( | ||||||
|   {xs: newXs, ys: newYs} |   {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 | // Main function | ||||||
| 
 | 
 | ||||||
| let combineShapesContinuousContinuous = ( | let combineShapesContinuousContinuous = ( | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user