diff --git a/packages/squiggle-lang/__tests__/Distributions/AlgebraicShapeCombination_test.res b/packages/squiggle-lang/__tests__/Distributions/AlgebraicShapeCombination_test.res new file mode 100644 index 00000000..7b84ee99 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/AlgebraicShapeCombination_test.res @@ -0,0 +1,16 @@ +open Jest +open TestHelpers + +describe("Combining Continuous and Discrete Distributions", () => { + makeTest( + "keep order of xs when multiplying by negative number", + AlgebraicShapeCombination.isOrdered( + AlgebraicShapeCombination.combineShapesContinuousDiscrete( + #Multiply, + {xs: [0., 1.], ys: [1., 1.]}, + {xs: [-1.], ys: [1.]}, + ), + ), // Multiply distribution by -1 + true, + ) +}) diff --git a/packages/squiggle-lang/jest.config.js b/packages/squiggle-lang/jest.config.js index 520f4693..71babb3c 100644 --- a/packages/squiggle-lang/jest.config.js +++ b/packages/squiggle-lang/jest.config.js @@ -2,7 +2,6 @@ module.exports = { preset: "ts-jest", testEnvironment: "node", - bail: true, setupFilesAfterEnv: [ "/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js", ], diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index d6ff1d31..b544fb33 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -215,7 +215,6 @@ let combineShapesContinuousDiscrete = ( continuousShape.ys[i] *. discreteShape.ys[j], ), ) |> ignore - () } Belt.Array.set(outXYShapes, j, dxyShape) |> ignore () @@ -225,9 +224,13 @@ let combineShapesContinuousDiscrete = ( // creates a new continuous shape for each one of the discrete points, and collects them in outXYShapes. let dxyShape: array<(float, float)> = Belt.Array.makeUninitializedUnsafe(t1n) for i in 0 to t1n - 1 { + // If this operation would flip the x axis (such as -1 * normal(5, 2)), + // then we want to fill the shape in backwards to ensure all the points + // are still in the right order + let index = discreteShape.xs[j] > 0.0 ? i : t1n - 1 - i Belt.Array.set( dxyShape, - i, + index, ( fn(continuousShape.xs[i], discreteShape.xs[j]), continuousShape.ys[i] *. discreteShape.ys[j] /. Js.Math.abs_float(discreteShape.xs[j]), @@ -251,3 +254,5 @@ let combineShapesContinuousDiscrete = ( XYShape.T.empty, ) } + +let isOrdered = (a: XYShape.T.t): bool => E.A.Sorted.Floats.isSorted(a.xs) diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 78c872ff..c3ba48a2 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -363,6 +363,9 @@ module A = { |> Rationale.Result.return } + let tail = Belt.Array.sliceToEnd(_, 1) + + let zip = Belt.Array.zip // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { let maxLength = Int.max(length(array1), length(array2)) @@ -506,6 +509,9 @@ module A = { } module Floats = { + let isSorted = (ar: array): bool => + reduce(zip(ar, tail(ar)), true, (acc, (first, second)) => acc && first < second) + let makeIncrementalUp = (a, b) => Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)