diff --git a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs index 4cf4179a..36a85587 100644 --- a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs @@ -795,6 +795,36 @@ static int4 clamp(int4 x, int4 a, int4 b) { if (a.x > b.x || a.y > b.y || a.z > new Family("vec4 cultmath_snoise_grad(vec3)", "ulp-bounded, coordinate bands 1e2 to 4e6", r => new object[] { BandPoint3(r, 1.0e2, 4.0e6) }, SpanAllowanceRead, Verify: cases => AssertSpanAllowance(cases, hessian: false, small: false)), new Family("mat3 cultmath_snoise_hessian(vec3)", "ulp-bounded, coordinate bands 1e-4 to 1e2", r => new object[] { BandPoint3(r, 1.0e-4, 1.0e2) }, SpanAllowanceRead, Verify: cases => AssertSpanAllowance(cases, hessian: true, small: true)), new Family("mat3 cultmath_snoise_hessian(vec3)", "ulp-bounded, coordinate bands 1e2 to 4e6", r => new object[] { BandPoint3(r, 1.0e2, 4.0e6) }, SpanAllowanceRead, Verify: cases => AssertSpanAllowance(cases, hessian: true, small: false)), + // Segment distance in 2D and 3D (one segment in eight degenerate), then the site cells: scores, fold step + // over states built by inserting 0-3 random scores (one in four with an exactly tied score), border, margin. + new Family("float cultmath_distance_to_segment(vec2, vec2, vec2)", "ulp-bounded", r => + { + var start = Point2(r); + return new object[] { Point2(r), start, r.Next(8) == 0 ? start : Point2(r) }; + }), + new Family("float cultmath_distance_to_segment(vec3, vec3, vec3)", "ulp-bounded", r => + { + var start = Point3(r); + return new object[] { Point3(r), start, r.Next(8) == 0 ? start : Point3(r) }; + }), + new Family("vec4 cultmath_power_score(vec3, vec4)", "ulp-bounded", r => new object[] { Point3(r), Site(r, 0.1f, 20.0f) }), + new Family("vec4 cultmath_multiplicative_score(vec3, vec4)", "ulp-bounded", r => new object[] { Point3(r), Site(r, 0.1f, 100.0f, logWeight: true) }), + new Family("CultSiteCells cultmath_site_cells_insert(CultSiteCells, vec4, int)", "ulp-bounded", r => + { + var (cells, scores) = CellsState(r); + var score = r.Next(4) == 0 && scores.Count > 0 ? scores[r.Next(scores.Count)] : PowerOrMultiplicative(r); + return new object[] { cells, score, scores.Count }; + }), + new Family("vec4 cultmath_site_cells_border(CultSiteCells)", "ulp-bounded", r => + { + var (cells, _) = CellsState(r, minimum: r.Next(8) == 0 ? 0 : 2); + return new object[] { cells }; + }), + new Family("float cultmath_gabriel_margin(vec3, vec3, vec3)", "ulp-bounded", r => + { + var a = Point3(r); + return new object[] { a, r.Next(8) == 0 ? a : Point3(r), Point3(r) }; + }), }).ToArray(); // A point of magnitude m, m log-uniform in [lo, hi]: one component at +-m, the other two uniform in [-m, m], @@ -807,6 +837,33 @@ static int4 clamp(int4 x, int4 a, int4 b) { if (a.x > b.x || a.y > b.y || a.z > return new float3((float)v[0], (float)v[1], (float)v[2]); } + private static float2 Point2(System.Random r) => new(Uniform(r, -50.0f, 50.0f), Uniform(r, -50.0f, 50.0f)); + + // A site float4(position.xyz, weight): the weight uniform in [lo, hi], or log-uniform when logWeight. + private static float4 Site(System.Random r, float lo, float hi, bool logWeight = false) + { + var p = Point3(r); + return new float4(p.x, p.y, p.z, logWeight ? lo * MathF.Pow(hi / lo, r.NextSingle()) : Uniform(r, lo, hi)); + } + + private static float4 PowerOrMultiplicative(System.Random r) => + r.Next(2) == 0 ? math.power_score(Point3(r), Site(r, 0.1f, 20.0f)) : math.multiplicative_score(Point3(r), Site(r, 0.1f, 100.0f, logWeight: true)); + + // A fold state made by the production path: site_cells_insert over a few random scores (at least minimum). + private static (CultSiteCells Cells, List Scores) CellsState(System.Random r, int minimum = 0) + { + var scores = new List(); + var cells = math.site_cells_empty(); + for (var i = minimum + r.Next(4 - minimum); i > 0; i--) + { + var score = r.Next(4) == 0 && scores.Count > 0 ? scores[^1] : PowerOrMultiplicative(r); + cells = math.site_cells_insert(cells, score, scores.Count); + scores.Add(score); + } + + return (cells, scores); + } + private static object[] SpanArguments(System.Random r) { var stage = SpanStageTests.Stage.Draw(r); @@ -876,6 +933,7 @@ static int4 clamp(int4 x, int4 a, int4 b) { if (a.x > b.x || a.y > b.y || a.z > ["float"] = typeof(float), ["int"] = typeof(int), ["vec2"] = typeof(float2), ["vec3"] = typeof(float3), ["vec4"] = typeof(float4), ["ivec3"] = typeof(int3), ["ivec4"] = typeof(int4), ["SpanPath"] = typeof(SpanPath), ["SpanStage"] = typeof(SpanStage), + ["CultSiteCells"] = typeof(CultSiteCells), }; // The C# math method a GLSL signature names: cultmath_ dropped, parameter types mapped.