diff --git a/packages/cultmath/README.md b/packages/cultmath/README.md
index 0b12819e..e5df5f1e 100644
--- a/packages/cultmath/README.md
+++ b/packages/cultmath/README.md
@@ -34,7 +34,8 @@ shader semantics.
parity. HLSL already owns `float2`, `float3`, and `float4`; the include
exposes `cultmath_*` functions for shared semantics HLSL does not provide.
It includes `shaders/CultMath.Phacelle.hlsl` (MPL-2.0) and
- `shaders/CultMath.Interval.hlsl` from the same directory, so ship all three.
+ `shaders/CultMath.Interval.hlsl` and `shaders/CultMath.Affine.hlsl` from the same
+ directory, so ship all four.
- interval arithmetic for culling empty space with a proof: `iv_*` functions
over `float2(lo, hi)` (`iv_add`, `iv_mul`, `iv_exp`, `iv_smoothstep`, ...)
and `iv_snoise_ball`/`iv_fbm_ball`, which bound `snoise` and `fbm_grad` over a
diff --git a/packages/cultmath/docs/design.md b/packages/cultmath/docs/design.md
index 24e94c2c..cf40ed12 100644
--- a/packages/cultmath/docs/design.md
+++ b/packages/cultmath/docs/design.md
@@ -222,6 +222,18 @@ lowering that inflates the ball fails too. Only those two bounds fail the
check; the largest ulp distance is reported as for any ulp-bounded family.
`GoldenFixtureMatchesCSharp` applies the same check to C#'s own results.
+Every `af_*` function is an ulp-bounded family, and `af_snoise`, `af_fbm` and `af_frustum_ball` also carry a two-sided `check`
+of their own, applied the same way: the device's own `snoise` or fBm at 75 sampled points of the case's set must lie in the device's
+form with no tolerance (a device whose gradient error exceeds the allowance fails), its width must not pass the Lipschitz form's
+allowance, and the device's `af_frustum_ball` radius must enclose the sampled ray points and stay within its rounding widening.
+The reference is the device's own noise, which is right for culling soundness but would pass a device whose noise is wrong
+everywhere, so two appended families (`af_snoise` and `af_fbm`, 256 cases each) add the centre leg: the fixture's own `x0`
+(C#'s value at the centre) must lie in the device form's `[x0 - e, x0 + e]`, for every `af_snoise` and `af_fbm` family. They
+also draw reach `|axis| + radius` from 1e-6 to 1e-3, the short slices near a camera, where the float32 allowance is most of `e`:
+the main families' reach is at least about 1e-3, where the second-order remainder is far larger and a device that drops the
+allowance still passes. `GoldenFixtureMatchesCSharp` requires each of the two to hold cases that fail on C#'s own results once
+the allowance is removed.
+
`GoldenFixtureMatchesCSharp` evaluates C# on the committed fixture's own
arguments. Arguments are drawn only when the fixture is regenerated
(`CULTMATH_WRITE_GLSL=1`), because the draw itself calls `MathF.Pow`, whose
@@ -586,9 +598,9 @@ over 2,000 balls x 64 points are the defence. A change to the `snoise` kernel
must re-run `MeasureLipschitz` and re-pin `L` and the witness.
What the ball bounds guarantee: enclosure of `snoise` and `fbm_grad(...).w` over
-the ball, in float32. What they do not: anything about tapes, pruning, choice
-tracking or affine forms; those are later steps of
-`docs/cultmath-tape-target.md` (CultLib root). How loose they are is a number:
+the ball, in float32. What they do not: anything about tapes, pruning or choice tracking. Correlation
+between the operands of one expression is what "Affine forms" below adds.
+How loose the ball bounds are is a number:
`NoiseBoundTests.TightnessReport` prints the mean interval width over the
sampled range: 5.08 for `iv_snoise_ball` at `r = 0.05`, 1.96 at 0.25 and 1.28
at 1.0; 6.64 and 2.82 for 4-octave `iv_fbm_ball` at 0.05 and 0.25.
@@ -616,30 +628,43 @@ printed. The flow is not counted. At `N = 8`, in Aetheria's units on its
- (a) Height fog, camera above the safety band, rays level and up: the whole
grid is one envelope probe per tile, against 256 envelope evaluations per ray,
16384x. Every cell is oracle-empty and the pre-pass proves them all.
-- (b) Inside the fog: 1.15x, and 0.99x with the warp. Most cells are fog, and
+- (b) Inside the fog: 1.16x, and 1.11x with the warp. Most cells are fog, and
the pre-pass probes each one.
-- (c) The zone bowl and four wells, the camera gazing across. With no warp:
- 2.74x, oracle ceiling 7.26x, efficiency 0.378, cull fraction 0.952, probe
- overhead 0.961. With the warp `D = 60`: 1.39x, oracle ceiling 7.17x,
- efficiency 0.194, cull fraction 0.842, probe overhead 0.993. With the warp the
- pre-pass cuts envelope evaluations from 177.46 to 33.49 per ray, but the
- oracle march costs 0.194 of the tile march, so about four fifths of the tile
- march's cost goes to cells no ray samples nonzero: the warp bound swamps the
- noise ball, so the ball cannot prove those cells empty. That gap belongs to
- the tape target's affine forms, not to a better pre-pass.
-- (d) r1's uniform slab, which has no envelope: 1.23x, and 1.48x with no warp.
+- (c) The deep well (ruling `wells-scale-order-of-magnitude`): the zone bowl
+ plus one well at its centre, `PowerPulse` exponent 2, scale 2220, depth 600.
+ The band `G = 60` is where only the noise decides density (`s` within
+ `F -+ 1.5 A` with the fade at 1); depth and half-depth radius are each
+ `10 G`. The camera's `xz` is uniform within 300 of the centre, at
+ `y = F - h(xz) / 2`, so it looks across the bowl from inside it. Both rows run
+ on the same seeds. With no warp, the centred interval takes 3.20x (oracle
+ ceiling 5.24x, efficiency 0.611, cull fraction 0.988, probe overhead 0.940)
+ and the affine bound 3.57x (efficiency 0.682, cull 0.993, overhead 0.905). With
+ the warp `D = 60`: 3.12x (ceiling 5.31x, efficiency 0.588, cull 0.987, overhead
+ 0.929) against 3.46x (efficiency 0.651, cull 0.993, overhead 0.880), so affine
+ is 1.12x and 1.11x cheaper. The range mask (the oracle cells plus every cell
+ where any of 5 x 5 slopes x 9 depths has density above zero) gives a range
+ ceiling of 0.859 (0.848 with the warp), the cost a bound that proves exactly
+ the range-empty cells would reach against the oracle's; the efficiencies
+ against it are 0.794 and 0.712 (warp 0), 0.768 and 0.694 (warp `D`).
+- (c-band) The shallow wells, four mass-derived wells in the zone bowl with
+ the camera gazing across, whose geometry is band-dominated, printed only.
+ Centred interval 3.01x (efficiency 0.414, cull 0.960, overhead 0.958), affine
+ 3.95x (0.544, 0.980, 0.901); with the warp 2.75x (0.383, 0.954, 0.944) against
+ 3.54x (0.494, 0.976, 0.865).
+- (d) r1's uniform slab, which has no envelope: 1.38x with the warp 0.05, and
+ 1.67x with no warp.
- (e) The void at the shipped point (ruling `operator-shipped-void`): `Rh = 198`,
`S = 50`, `Rc = Rh + S = 248`, `e = -ln 1.5 / ln(1 - (Rh / Rc)^2)`, the
shipped camera, 200 tiles. The fixed-step reference takes 36.34 steps per
- pixel. The same cells masked by the pre-pass take 20.13, with identical
- transmittance. The footprint-aware march takes 13.54: 2.68x fewer. `snoise`
- per pixel goes from 32.98 to 26.69, and combined cost from 40.25 to 29.52 with
+ pixel. The same cells masked by the pre-pass take 20.08, with identical
+ transmittance. The footprint-aware march takes 13.50: 2.69x fewer. `snoise`
+ per pixel goes from 32.98 to 26.70, and combined cost from 40.25 to 29.54 with
the probes, 1.36x. Every one of the 200 tiles proves a body. Before the body
both marches are measured against a converged one (midpoint quadrature at
`h = 0.5` over every cell, trusting no pre-pass): the relative optical-depth
error at the body start is at most 0.0608 for the fixed-step march and 0.08639
for the footprint march, 1.42x. Over the grid of hollow radius, camera offset
- and ramp width the steps ratio runs from 1.57x (`Rh = 100`, low, `S = 150`) to
+ and ramp width the steps ratio runs from 1.59x (`Rh = 100`, low, `S = 150`) to
27.45x (`Rh = 1000`, centred, `S = 10`), the cost ratio from 1.26x to 3.89x,
and the depth-error ratio from 0.85 to 4.72 (`Rh = 200`, centred, `S = 150`,
where the errors are 0.01504 and 0.003188). LOD-far takes 14.19x fewer steps;
@@ -669,24 +694,144 @@ interval argument, so the composed interval encloses both fields.
The contracts, at `N = 8`, the lower of warp 0 and `D`:
- (a) at least 2x combined cost;
-- (c) (ruling `wells-overhead-plus-floor`): probe overhead, the tile march over
- the tile march plus its probes, at least 0.90; and, hard, the pre-pass proves
- at least half of the oracle-empty cells empty, so a pre-pass that skips
- nothing fails. The oracle ceiling, the efficiency against it and the cull
- fraction are printed, not asserted;
+- (c) on the deep well (rulings `affine-wells-contract-cheaper-than-interval`
+ and `wells-overhead-plus-floor`): the affine bound's combined cost ratio is
+ above the centred interval's at warp 0 and at warp `D`; and, hard, the
+ pre-pass proves at least half of the oracle-empty cells empty under both
+ bounds, so a pre-pass that skips nothing fails. The probe overhead, the
+ efficiencies against the oracle and the range ceiling, the ceilings and the
+ cull fraction are printed, not asserted; (c-band) is printed only;
- (e) at the shipped void: the masked fixed-step march agrees with the reference
exactly; the footprint march's optical depth at the body start is off the
converged march's by at most twice the fixed-step march's error; and it takes
at most half the reference's steps per pixel.
-This run meets every contract: (a) 16384x, (c) probe overhead 0.961 and cull
-fraction 0.842, (e) 2.68x fewer steps and a depth error 1.42x the fixed-step
-march's. The fields, the grids and the 0.2 weight are not tuned toward the
-contracts.
+This run meets every contract: (a) 16384x, (c) affine 3.57x and 3.46x against
+the centred interval's 3.20x and 3.12x, with a cull fraction of 0.987 at the
+lowest, (e) 2.69x fewer steps and a depth error 1.42x the fixed-step march's.
+The fields, the grids, the 0.2 envelope weight and the 2.0 gradient weight are
+not tuned toward the contracts. An affine probe is one `snoise_grad`, counted at
+2.0 `snoise` evaluations (an estimate, printed beside the count).
Consumers: the gamecult.org ground shader (through the GLSL lowering) and
Aetheria's nebula raymarch at its CultMath pin bump.
+## Affine forms
+
+`math.Affine.cs` carries reduced affine forms with one shared symbol: a
+`float3(x0, a, e)` is the set `x0 + a eps + e delta` with `eps` and `delta` in
+`[-1, 1]` and `e >= 0` (Messine's AF1, as Gamito and Maddock use it for gradient
+noise, in one register as an interval is a `float2`). `eps` is shared by every
+form over one region (for a screen-tile slice, the depth parameter, `z = z_m +
+h eps`), so `af_sub(x, x)` has `a = 0`; `delta` is private to the form, and
+every term that cannot be tracked is condensed into `e`. A slice is a
+`float4(centre, radius)` with a `float3` axis. No op takes a compound type, a
+reference parameter or a swizzle write, so each mirrors into the HLSL common
+subset.
+
+The ops: `af_point`, `af_symbol`, `af_from_iv`, `af_range` (the bridge back to
+`iv_*`), `af_add`, `af_sub`, `af_neg`, `af_scale`, `af_add_iv`, `af_mul` (the
+product `|a_x a_y|` and the cross-error terms condensed into `e`, so there is
+no `af_sqr`), `af_snoise` and `af_fbm`, and the slice pair `af_frustum_axis` and
+`af_frustum_ball`.
+
+Rounding. Every op returns a form whose set at each `eps` contains the float32
+value of its function at every point of its operands' sets at that `eps`. Each
+op folds its own float32 rounding into `e` as `S 2^-20`, `S` the sum of the
+magnitudes its roundings are relative to (named in the op's comment): at most
+`8u S` is needed with `u = 2^-24`, and the factor of two over that is the
+allowance for a device whose `+` and `*` are faithful rather than correctly
+rounded. `AffineTests.EveryOpEnclosesItsPoints` evaluates the form's set in
+double and the function in float32 with no tolerance. Products and `af_from_iv` also
+add `2^-126`, the most an underflow to a subnormal can lose (`TinyOperandsEncloseTheirPoints`).
+`af_from_iv` halves its endpoints before it sums and differences them, and `af_range`
+scales its terms before it sums them, so endpoints near the float maximum do not overflow
+in the middle of the op; a form that overflows anyway gives `af_range` infinite endpoints,
+never NaN (`FromIntervalAndRangeHoldAtTheExtremes`). `af_range` finds a NaN endpoint by its bit pattern, because
+`lo == lo` is a compare dxc marks `fast` and deletes under its default flags. `AbsorptionsArePinned` and
+`SnoiseFormCarriesItsDocumentedWidth` pin each absorption and `af_snoise`'s float32 allowance both
+ways: the enclosure tests alone cannot see them on a CPU, where float32 is exact.
+
+`af_snoise(centre, axis, radius)` encloses `snoise` over `centre + axis eps + w`,
+`|w| <= radius`, from one `snoise_grad`. It returns the narrower of the
+Lipschitz form `(n, 0, L R)` and the centred form `(n, g . axis, |g| radius +
+M R^2 / 2)` (`R = |axis| + radius`, `L = SNOISE_LIPSCHITZ`, `M =
+SNOISE_HESSIAN`), so its total width is never more than the Lipschitz form's.
+The centred form is Taylor's theorem, which is why it beats the ball when the
+radius is small and the axis carries the variation. `af_fbm` compounds octaves
+as `iv_fbm_ball` does. The float32 evaluation allowance is derived in
+`af_snoise`'s comment.
+
+`SNOISE_HESSIAN = 56.050385` is 1.10 times the refined maximum of the spectral
+norm of the Hessian of `snoise(float3)`, measured by
+`NoiseBoundTests.MeasureHessian` over 1e6 seeded points (central differences of
+`snoise_grad`) and refined by ascent from the 1e4 largest: sampled 50.1366,
+refined 50.9549, witness (-245.19885, -53.01323, -91.47363).
+`HessianConstantPinsSampledCurvature` fails on a 1% move.
+`SNOISE2_LIPSCHITZ = 8.117002` is the same for the gradient of `snoise(float2)`
+(`MeasureLipschitz2`: sampled 7.2575, refined 7.3791, witness (-67.12454,
+-129.53296), `|snoise2|` at most 0.99964), and it backs `iv_snoise_ball(float2,
+float)`. Both are empirical with a margin, not proofs. A random ball cannot see a
+curvature constant 20% low, so `SNOISE_HESSIAN` is defended by
+`HessianConstantPinsSampledCurvature` and `SnoiseFormEnclosesTheCurvatureWitness`
+(`af_snoise` at the point where the curvature is realised, along 4,000 directions: a
+constant of 40 misses there). The margin over the function itself: a scan of the whole
+289^3 hash period found a realised maximum of 50.58, and bounding each corner's gradient
+independently over every hash configuration gives 52.22, so 56.05 sits 7% above the
+configuration bound. A change to the kernels must re-run the measurements.
+
+The slice. `af_frustum_ball(centreSlope, z0, z1, footprintPerDepth,
+warpVariation)` returns the centre `(m_c z_m, z_m)` and a radius `z1
+footprintPerDepth + warpVariation`, with `af_frustum_axis` the axis `(m_c, 1) h`:
+every ray point at depth `z` is `centre + axis eps(z) + w`. Its derivation
+and the clamp residual are in the comment. The caller rotates, translates and
+scales the slice into the noise's frame, and owns the rounding of that.
+
+The centred warp. A flow-warped sample reads `snoise` at `p + flow(p) shift`. The
+caller does not enlarge the ball by the whole displacement `|flow| shift`; it
+moves the centre by the flow at the centre, `c + flow(c) shift`, and widens the
+radius by the flow's variation across the ball, `r + |shift| rho` with `rho =
+FlowAmplitude (SNOISE2_LIPSCHITZ FlowFrequency r + a) sqrt 2` (the clamp to the unit
+disc is nonexpansive), where `a = 2^-14 + L2 2^-20 (|q|_1 + r FlowFrequency)` is the
+float32 allowance of the flow's two `snoise(float2)` reads (the point `q` plus its offset rounds at the
+magnitude of `q`, and a float32 flow at two points of a ball differs by more than the exact
+function can). CultMath owns neither the flow nor the envelope: the warp's
+centre and variation are the caller's, and a consumer adds them to the slice's
+`warpVariation` or to the form's radius. With two phases that cross-fade, each
+phase takes its own centre; one ball serves when the phases' centres coincide
+(warp 0). `NoiseBoundTests.CentredWarpStaysEnclosed` checks 2,000 balls, radius 1e-3 to
+500, and fails when `rho` is dropped or halved; `AffineWarpStaysEnclosed` checks
+3,000 tile slices of `FogField.Slice`, which returns the final `af_snoise` arguments
+(each phase's moved centre and grown radius, the detail's unwarped set, the shared axis),
+so the affine bound wires nothing itself: the reach over which the flow is varied is
+`|axis| + radius`, each phase carries its own growth, and the gate reads each argument's
+reach. It fails when the reach is the ball's radius or the larger of the two, a phase's
+growth is dropped or taken from the other phase, the axis or the detail radius is scaled,
+or `rho` is halved. `AffineCompositionTightensItsRanges` sees the shared-symbol
+composition itself: the bound is exactly the intersection of the affine arithmetic's piece
+and the interval composition over the forms' ranges, and the affine piece is the narrower
+of the two in at least 35% of the open slices (the piece alone is wider in total).
+
+The deep well is the representative Aetheria case: the camera inside a sun's
+bowl, looking across. `DeepWellIsTenBandsDeepAndWide` computes the band `G` from
+`FogField`'s own floor offset, amplitude and noise range (60) and requires the
+depth (633 at the centre against the rim) and the half-depth radius to be at
+least `10 G`, every drawn camera sitting inside the well below the rim; a well of
+depth 150 fails. The shallow wells stay as the printed shallow-well, band-dominated row (c-band).
+
+The test field's affine bound takes depth as `af_symbol(z_m, h)`, builds `s`
+affine in it with the height interval, the footprint and the slope-depth
+product in `e` through `af_add_iv`, takes the noise through `af_frustum_*` and
+`af_snoise` per phase and for the detail octave, fades by `af_from_iv` and
+`af_mul`, reads the range with `af_range`, and intersects with the centred
+interval's bound (both sound). `FogField.Bound` makes no direct `snoise` call.
+The cull-map render (`DeepWellCullMap`, explicit) writes a PNG when
+`CULTMATH_WRITE_CULLMAP` names a directory: one deep-well camera at warp `D`,
+960 x 540 in 8 x 8 tiles, with panels for dense cells per ray under the centred
+interval, under the affine bound and under the oracle mask (one logarithmic
+scale) and the transmittance. Its run: 4.23, 3.60 and 2.02 cells per ray on
+average, 44 the most, mean transmittance 0.278.
+
## Rules
- Keep type names HLSL-shaped: `float2`, `float3`, `float4`, `float3x3`, and `math`.
diff --git a/packages/cultmath/scripts/build-unity-package.ps1 b/packages/cultmath/scripts/build-unity-package.ps1
index 7fb6f7a6..f232d6eb 100644
--- a/packages/cultmath/scripts/build-unity-package.ps1
+++ b/packages/cultmath/scripts/build-unity-package.ps1
@@ -84,7 +84,9 @@ $requiredTemplateFiles = @(
"Shaders\CultMath.Phacelle.hlsl",
"Shaders\CultMath.Phacelle.hlsl.meta",
"Shaders\CultMath.Interval.hlsl",
- "Shaders\CultMath.Interval.hlsl.meta"
+ "Shaders\CultMath.Interval.hlsl.meta",
+ "Shaders\CultMath.Affine.hlsl",
+ "Shaders\CultMath.Affine.hlsl.meta"
)
foreach ($relativePath in $requiredTemplateFiles) {
if (-not (Test-Path -LiteralPath (Join-Path $templateRoot $relativePath) -PathType Leaf)) {
diff --git a/packages/cultmath/shaders/CultMath.Affine.hlsl b/packages/cultmath/shaders/CultMath.Affine.hlsl
new file mode 100644
index 00000000..f165148b
--- /dev/null
+++ b/packages/cultmath/shaders/CultMath.Affine.hlsl
@@ -0,0 +1,132 @@
+#ifndef CULTMATH_AFFINE_HLSL
+#define CULTMATH_AFFINE_HLSL
+
+// Reduced affine forms with one shared symbol over float3(x0, a, e): the set { x0 + a eps + e delta :
+// delta in [-1, 1] } at the region's shared eps in [-1, 1], e >= 0. Every cultmath_af_* function mirrors
+// math.Affine.cs bit for bit; see that file and docs/design.md ("Affine forms") for each op's enclosure
+// and the float32 rounding allowance it folds into e. Included by CultMath.hlsl after
+// CultMath.Interval.hlsl, whose CULTMATH_SNOISE_LIPSCHITZ it shares, and after its own
+// definition of cultmath_snoise_grad.
+
+// An upper bound on the spectral norm of the Hessian of cultmath_snoise(float3); provenance in
+// math.Affine.cs (SNOISE_HESSIAN).
+static const float CULTMATH_SNOISE_HESSIAN = 56.050385;
+
+float3 cultmath_af_point(float value) { return float3(value, 0.0, 0.0); }
+float3 cultmath_af_symbol(float x0, float a) { return float3(x0, a, 0.0); }
+
+float3 cultmath_af_from_iv(float2 interval)
+{
+ float x0 = interval.x * 0.5 + interval.y * 0.5;
+ float e = interval.y * 0.5 - interval.x * 0.5;
+ return float3(x0, 0.0, e + (abs(x0) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// An endpoint that would be NaN is the infinity on its side. NaN is found by its bit pattern: dxc marks
+// compares fast, so a test that needs NaN to make `lo == lo` false is deleted under its default flags.
+float2 cultmath_af_range(float3 x)
+{
+ float r = abs(x.y) + x.z;
+ float w = abs(x.x) * 9.5367431640625e-7 + r * 9.5367431640625e-7;
+ float lo = x.x - r - w;
+ float hi = x.x + r + w;
+ return float2((asuint(lo) & 0x7fffffffu) > 0x7f800000u ? asfloat(0xff800000u) : lo,
+ (asuint(hi) & 0x7fffffffu) > 0x7f800000u ? asfloat(0x7f800000u) : hi);
+}
+
+float3 cultmath_af_add(float3 x, float3 y)
+{
+ float x0 = x.x + y.x;
+ float a = x.y + y.y;
+ float e = x.z + y.z;
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+float3 cultmath_af_sub(float3 x, float3 y)
+{
+ float x0 = x.x - y.x;
+ float a = x.y - y.y;
+ float e = x.z + y.z;
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+float3 cultmath_af_neg(float3 x) { return float3(-x.x, -x.y, x.z); }
+
+float3 cultmath_af_scale(float3 x, float s)
+{
+ float x0 = x.x * s;
+ float a = x.y * s;
+ float e = x.z * abs(s);
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+float3 cultmath_af_add_iv(float3 x, float2 interval) { return cultmath_af_add(x, cultmath_af_from_iv(interval)); }
+
+float3 cultmath_af_mul(float3 x, float3 y)
+{
+ float x0 = x.x * y.x;
+ float p = x.x * y.y;
+ float q = y.x * x.y;
+ float a = p + q;
+ float e = abs(x.x) * y.z + abs(y.x) * x.z + (abs(x.y) + x.z) * (abs(y.y) + y.z);
+ return float3(x0, a, e + (abs(x0) + abs(p) + abs(q) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// The narrower of the Lipschitz form and the centred (Taylor) form over every p = centre + axis eps + w,
+// |w| <= radius, from one cultmath_snoise_grad at the centre; the allowance for the float32 evaluation is
+// in math.Affine.cs.
+float3 cultmath_af_snoise(float3 centre, float3 axis, float radius)
+{
+ float4 g = cultmath_snoise_grad(centre);
+ float3 gradient = float3(g.x, g.y, g.z);
+ float reach = length(axis) + radius;
+ float lipschitz = CULTMATH_SNOISE_LIPSCHITZ * reach;
+ float a = dot(gradient, axis);
+ float remainder = length(gradient) * radius + 0.5 * CULTMATH_SNOISE_HESSIAN * reach * reach;
+ float allowance = 6.103515625e-5 + 2.44140625e-4 * reach
+ + CULTMATH_SNOISE_LIPSCHITZ * 9.5367431640625e-7 * (abs(centre.x) + abs(centre.y) + abs(centre.z) + reach);
+ bool centred = abs(a) + remainder < lipschitz;
+ float slope = centred ? a : 0.0;
+ float e = (centred ? remainder : lipschitz) + allowance;
+ return float3(g.w, slope, e + (abs(g.w) + abs(slope) + e) * 9.5367431640625e-7);
+}
+
+// Octave sum of cultmath_af_snoise, compounding frequency and amplitude as the value-and-gradient fBm does.
+float3 cultmath_af_fbm(float3 centre, float3 axis, float radius, int octaves, float lacunarity, float gain)
+{
+ octaves = clamp(octaves, 0, 16);
+ float amplitude = 1.0;
+ float frequency = 1.0;
+ float3 sum = float3(0.0, 0.0, 0.0);
+ for (int i = 0; i < octaves; i++)
+ {
+ sum = cultmath_af_add(sum, cultmath_af_scale(cultmath_af_snoise(centre * frequency, axis * frequency, radius * abs(frequency)), amplitude));
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+
+ return sum;
+}
+
+// The axis of a screen tile's slice over the depth segment [z0, z1]; camera frame of
+// cultmath_iv_frustum_ball.
+float3 cultmath_af_frustum_axis(float2 centreSlope, float z0, float z1)
+{
+ float h = (z1 - z0) * 0.5;
+ return float3(centreSlope.x * h, centreSlope.y * h, h);
+}
+
+// The affine slice of a screen tile over [z0, z1]: centre xyz, radius w. Derivation in math.Affine.cs.
+float4 cultmath_af_frustum_ball(float2 centreSlope, float z0, float z1, float footprintPerDepth, float warpVariation)
+{
+ float zm = (z0 + z1) * 0.5;
+ float h = (z1 - z0) * 0.5;
+ float cx = centreSlope.x * zm;
+ float cy = centreSlope.y * zm;
+ float spread = (abs(centreSlope.x) + abs(centreSlope.y) + 1.0) * h;
+ float radius = z1 * footprintPerDepth + warpVariation;
+ radius += (abs(cx) + abs(cy) + abs(zm) + spread + radius) * 9.5367431640625e-7;
+ return float4(cx, cy, zm, radius);
+}
+
+#endif
diff --git a/packages/cultmath/shaders/CultMath.Affine.hlsl.meta b/packages/cultmath/shaders/CultMath.Affine.hlsl.meta
new file mode 100644
index 00000000..81cc7925
--- /dev/null
+++ b/packages/cultmath/shaders/CultMath.Affine.hlsl.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 26f28fce38e14eed8b9b5dbd758e4ffc
+ShaderIncludeImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/packages/cultmath/shaders/CultMath.Interval.hlsl b/packages/cultmath/shaders/CultMath.Interval.hlsl
index 22c19221..bc084ace 100644
--- a/packages/cultmath/shaders/CultMath.Interval.hlsl
+++ b/packages/cultmath/shaders/CultMath.Interval.hlsl
@@ -9,6 +9,9 @@
// Lipschitz constant of cultmath_snoise(float3); provenance in math.Interval.cs (SNOISE_LIPSCHITZ).
static const float CULTMATH_SNOISE_LIPSCHITZ = 7.9640074;
+// Lipschitz constant of cultmath_snoise(float2); provenance in math.Interval.cs (SNOISE2_LIPSCHITZ).
+static const float CULTMATH_SNOISE2_LIPSCHITZ = 8.117002;
+
float2 cultmath_iv_point(float value) { return float2(value, value); }
float2 cultmath_iv_add(float2 a, float2 b) { return float2(a.x + b.x, a.y + b.y); }
float2 cultmath_iv_sub(float2 a, float2 b) { return float2(a.x - b.y, a.y - b.x); }
@@ -87,6 +90,14 @@ float2 cultmath_iv_snoise_ball(float3 centre, float radius)
return float2(max(n - e, -1.0), min(n + e, 1.0));
}
+// The 2D overload: [n - L2 r, n + L2 r] intersected with [-1, 1], n = cultmath_snoise(centre). One snoise, value only.
+float2 cultmath_iv_snoise_ball(float2 centre, float radius)
+{
+ float n = cultmath_snoise(centre);
+ float e = CULTMATH_SNOISE2_LIPSCHITZ * radius;
+ return float2(max(n - e, -1.0), min(n + e, 1.0));
+}
+
// Octave sum of cultmath_iv_snoise_ball, compounding frequency and amplitude as the value-and-gradient fBm does.
float2 cultmath_iv_fbm_ball(float3 centre, float radius, int octaves, float lacunarity, float gain)
{
diff --git a/packages/cultmath/shaders/CultMath.glsl b/packages/cultmath/shaders/CultMath.glsl
index 50e8f340..d89ff8a3 100644
--- a/packages/cultmath/shaders/CultMath.glsl
+++ b/packages/cultmath/shaders/CultMath.glsl
@@ -1,4 +1,4 @@
-// Generated from shaders/CultMath.hlsl and CultMath.Interval.hlsl by GlslLowering (packages/cultmath/tests/CultMath.Tests/GlslLowering.cs). Do not edit; regenerate with CULTMATH_WRITE_GLSL=1 dotnet test --filter GlslMirrorTests. MIT. cultmath_phacelle is in CultMath.Phacelle.glsl, to be concatenated after this file by consumers that call it.
+// Generated from shaders/CultMath.hlsl and CultMath.Interval.hlsl and CultMath.Affine.hlsl by GlslLowering (packages/cultmath/tests/CultMath.Tests/GlslLowering.cs). Do not edit; regenerate with CULTMATH_WRITE_GLSL=1 dotnet test --filter GlslMirrorTests. MIT. cultmath_phacelle is in CultMath.Phacelle.glsl, to be concatenated after this file by consumers that call it.
#ifndef CULTMATH_GLSL
#define CULTMATH_GLSL
// CultMath HLSL mirror.
@@ -518,6 +518,9 @@ CultCellular cultmath_cellular(vec3 p)
// Lipschitz constant of cultmath_snoise(vec3); provenance in math.Interval.cs (SNOISE_LIPSCHITZ).
const float CULTMATH_SNOISE_LIPSCHITZ = 7.9640074;
+// Lipschitz constant of cultmath_snoise(vec2); provenance in math.Interval.cs (SNOISE2_LIPSCHITZ).
+const float CULTMATH_SNOISE2_LIPSCHITZ = 8.117002;
+
vec2 cultmath_iv_point(float value) { return vec2(value, value); }
vec2 cultmath_iv_add(vec2 a, vec2 b) { return vec2(a.x + b.x, a.y + b.y); }
vec2 cultmath_iv_sub(vec2 a, vec2 b) { return vec2(a.x - b.y, a.y - b.x); }
@@ -596,6 +599,14 @@ vec2 cultmath_iv_snoise_ball(vec3 centre, float radius)
return vec2(max(n - e, -1.0), min(n + e, 1.0));
}
+// The 2D overload: [n - L2 r, n + L2 r] intersected with [-1, 1], n = cultmath_snoise(centre). One snoise, value only.
+vec2 cultmath_iv_snoise_ball(vec2 centre, float radius)
+{
+ float n = cultmath_snoise(centre);
+ float e = CULTMATH_SNOISE2_LIPSCHITZ * radius;
+ return vec2(max(n - e, -1.0), min(n + e, 1.0));
+}
+
// Octave sum of cultmath_iv_snoise_ball, compounding frequency and amplitude as the value-and-gradient fBm does.
vec2 cultmath_iv_fbm_ball(vec3 centre, float radius, int octaves, float lacunarity, float gain)
{
@@ -631,6 +642,139 @@ vec4 cultmath_iv_frustum_ball(vec2 centreSlope, float z0, float z1, float footpr
+
+
+// Reduced affine forms with one shared symbol over vec3(x0, a, e): the set { x0 + a eps + e delta :
+// delta in [-1, 1] } at the region's shared eps in [-1, 1], e >= 0. Every cultmath_af_* function mirrors
+// math.Affine.cs bit for bit; see that file and docs/design.md ("Affine forms") for each op's enclosure
+// and the float32 rounding allowance it folds into e. Included by CultMath.hlsl after
+// CultMath.Interval.hlsl, whose CULTMATH_SNOISE_LIPSCHITZ it shares, and after its own
+// definition of cultmath_snoise_grad.
+
+// An upper bound on the spectral norm of the Hessian of cultmath_snoise(vec3); provenance in
+// math.Affine.cs (SNOISE_HESSIAN).
+const float CULTMATH_SNOISE_HESSIAN = 56.050385;
+
+vec3 cultmath_af_point(float value) { return vec3(value, 0.0, 0.0); }
+vec3 cultmath_af_symbol(float x0, float a) { return vec3(x0, a, 0.0); }
+
+vec3 cultmath_af_from_iv(vec2 interval)
+{
+ float x0 = interval.x * 0.5 + interval.y * 0.5;
+ float e = interval.y * 0.5 - interval.x * 0.5;
+ return vec3(x0, 0.0, e + (abs(x0) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// An endpoint that would be NaN is the infinity on its side. NaN is found by its bit pattern: dxc marks
+// compares fast, so a test that needs NaN to make `lo == lo` false is deleted under its default flags.
+vec2 cultmath_af_range(vec3 x)
+{
+ float r = abs(x.y) + x.z;
+ float w = abs(x.x) * 9.5367431640625e-7 + r * 9.5367431640625e-7;
+ float lo = x.x - r - w;
+ float hi = x.x + r + w;
+ return vec2((floatBitsToUint(lo) & 0x7fffffffu) > 0x7f800000u ? uintBitsToFloat(0xff800000u) : lo,
+ (floatBitsToUint(hi) & 0x7fffffffu) > 0x7f800000u ? uintBitsToFloat(0x7f800000u) : hi);
+}
+
+vec3 cultmath_af_add(vec3 x, vec3 y)
+{
+ float x0 = x.x + y.x;
+ float a = x.y + y.y;
+ float e = x.z + y.z;
+ return vec3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+vec3 cultmath_af_sub(vec3 x, vec3 y)
+{
+ float x0 = x.x - y.x;
+ float a = x.y - y.y;
+ float e = x.z + y.z;
+ return vec3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+vec3 cultmath_af_neg(vec3 x) { return vec3(-x.x, -x.y, x.z); }
+
+vec3 cultmath_af_scale(vec3 x, float s)
+{
+ float x0 = x.x * s;
+ float a = x.y * s;
+ float e = x.z * abs(s);
+ return vec3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+vec3 cultmath_af_add_iv(vec3 x, vec2 interval) { return cultmath_af_add(x, cultmath_af_from_iv(interval)); }
+
+vec3 cultmath_af_mul(vec3 x, vec3 y)
+{
+ float x0 = x.x * y.x;
+ float p = x.x * y.y;
+ float q = y.x * x.y;
+ float a = p + q;
+ float e = abs(x.x) * y.z + abs(y.x) * x.z + (abs(x.y) + x.z) * (abs(y.y) + y.z);
+ return vec3(x0, a, e + (abs(x0) + abs(p) + abs(q) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// The narrower of the Lipschitz form and the centred (Taylor) form over every p = centre + axis eps + w,
+// |w| <= radius, from one cultmath_snoise_grad at the centre; the allowance for the float32 evaluation is
+// in math.Affine.cs.
+vec3 cultmath_af_snoise(vec3 centre, vec3 axis, float radius)
+{
+ vec4 g = cultmath_snoise_grad(centre);
+ vec3 gradient = vec3(g.x, g.y, g.z);
+ float reach = length(axis) + radius;
+ float lipschitz = CULTMATH_SNOISE_LIPSCHITZ * reach;
+ float a = dot(gradient, axis);
+ float remainder = length(gradient) * radius + 0.5 * CULTMATH_SNOISE_HESSIAN * reach * reach;
+ float allowance = 6.103515625e-5 + 2.44140625e-4 * reach
+ + CULTMATH_SNOISE_LIPSCHITZ * 9.5367431640625e-7 * (abs(centre.x) + abs(centre.y) + abs(centre.z) + reach);
+ bool centred = abs(a) + remainder < lipschitz;
+ float slope = centred ? a : 0.0;
+ float e = (centred ? remainder : lipschitz) + allowance;
+ return vec3(g.w, slope, e + (abs(g.w) + abs(slope) + e) * 9.5367431640625e-7);
+}
+
+// Octave sum of cultmath_af_snoise, compounding frequency and amplitude as the value-and-gradient fBm does.
+vec3 cultmath_af_fbm(vec3 centre, vec3 axis, float radius, int octaves, float lacunarity, float gain)
+{
+ octaves = clamp(octaves, 0, 16);
+ float amplitude = 1.0;
+ float frequency = 1.0;
+ vec3 sum = vec3(0.0, 0.0, 0.0);
+ for (int i = 0; i < octaves; i++)
+ {
+ sum = cultmath_af_add(sum, cultmath_af_scale(cultmath_af_snoise(centre * frequency, axis * frequency, radius * abs(frequency)), amplitude));
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+
+ return sum;
+}
+
+// The axis of a screen tile's slice over the depth segment [z0, z1]; camera frame of
+// cultmath_iv_frustum_ball.
+vec3 cultmath_af_frustum_axis(vec2 centreSlope, float z0, float z1)
+{
+ float h = (z1 - z0) * 0.5;
+ return vec3(centreSlope.x * h, centreSlope.y * h, h);
+}
+
+// The affine slice of a screen tile over [z0, z1]: centre xyz, radius w. Derivation in math.Affine.cs.
+vec4 cultmath_af_frustum_ball(vec2 centreSlope, float z0, float z1, float footprintPerDepth, float warpVariation)
+{
+ float zm = (z0 + z1) * 0.5;
+ float h = (z1 - z0) * 0.5;
+ float cx = centreSlope.x * zm;
+ float cy = centreSlope.y * zm;
+ float spread = (abs(centreSlope.x) + abs(centreSlope.y) + 1.0) * h;
+ float radius = z1 * footprintPerDepth + warpVariation;
+ radius += (abs(cx) + abs(cy) + abs(zm) + spread + radius) * 9.5367431640625e-7;
+ return vec4(cx, cy, zm, radius);
+}
+
+
+
+
float cultmath_value_noise(vec2 position)
{
vec2 cell = floor(position);
diff --git a/packages/cultmath/shaders/CultMath.hlsl b/packages/cultmath/shaders/CultMath.hlsl
index e40cf0b6..6856a000 100644
--- a/packages/cultmath/shaders/CultMath.hlsl
+++ b/packages/cultmath/shaders/CultMath.hlsl
@@ -509,6 +509,7 @@ CultCellular cultmath_cellular(float3 p)
#include "CultMath.Phacelle.hlsl"
#include "CultMath.Interval.hlsl"
+#include "CultMath.Affine.hlsl"
float cultmath_value_noise(float2 position)
{
diff --git a/packages/cultmath/src/CultMath/math.Affine.cs b/packages/cultmath/src/CultMath/math.Affine.cs
new file mode 100644
index 00000000..3c00e397
--- /dev/null
+++ b/packages/cultmath/src/CultMath/math.Affine.cs
@@ -0,0 +1,241 @@
+namespace CultMath;
+
+public static partial class math
+{
+ // Reduced affine forms with one shared symbol (design.md, "Affine forms"): float3(x0, a, e) is the
+ // set { x0 + a eps + e delta : delta in [-1, 1] } at the region's shared eps in [-1, 1], with
+ // e >= 0. Every form over one region shares that eps (for a screen-tile slice, the depth
+ // parameter), and delta is private to the form. This is Messine's AF1 as Gamito and Maddock use it
+ // for gradient noise (t0 + t1 e1 + t2 e2), in one register, as an interval is a float2.
+ //
+ // Every af_* op returns a form whose set, at each eps, contains f evaluated pointwise in float32 at
+ // every point of its operands' sets at that same eps. Rounding rule: each op folds its own float32
+ // rounding into e as (S) 2^-20, where S is the sum of the magnitudes the op's roundings are
+ // relative to (named in each comment). With u = 2^-24, every op below needs at most 8u S (its
+ // component roundings, the pointwise result's own rounding, and the roundings of computing e), so
+ // 2^-20 = 16u covers it twice over; the factor of two is the allowance for a device whose + and *
+ // are faithful (within one ulp) rather than correctly rounded, and fma contraction only removes
+ // roundings. Products also add 2^-126, the most any underflow to a subnormal can lose. The
+ // enclosure tests evaluate the form's set in double and f in float32 with no tolerance
+ // (AffineTests.EveryOpEnclosesItsPoints). No op takes a compound type or a reference parameter: each is a
+ // plain function of float values, so it mirrors into the HLSL common subset.
+
+ // An upper bound on the spectral norm of the Hessian of snoise(float3). Provenance:
+ // NoiseBoundTests.MeasureHessian (slow, explicit) takes the largest Hessian norm (central
+ // differences of snoise_grad, largest absolute eigenvalue) over 1e6 seeded points, refines the 1e4
+ // largest by ascent, and multiplies the refined maximum by 1.10;
+ // NoiseBoundTests.HessianConstantPinsSampledCurvature pins this value against a fast re-measure and
+ // the ascent from MeasureHessian's witness. Empirical with a margin, not a proof. Random balls
+ // cannot see a constant 20% low, so the defence is those two curvature tests plus
+ // NoiseBoundTests.SnoiseFormEnclosesTheCurvatureWitness, where af_snoise misses at the point the
+ // curvature is realised if the constant is under it. The margin over the function: a scan of the
+ // whole 289^3 hash period found a realised maximum of 50.58, and bounding each corner's gradient
+ // independently over every hash configuration gives 52.22 (Soul pass s1). A change to the snoise
+ // kernel must re-run MeasureHessian and re-pin it.
+ public const float SNOISE_HESSIAN = 56.050385f;
+
+ /// The point form (x, 0, 0): the value x at every eps. Exact.
+ public static float3 af_point(float value) => new(value, 0.0f, 0.0f);
+
+ ///
+ /// The shared symbol itself, (x0, a, 0): the value x0 + a eps. It is how a region's parameter enters
+ /// (for a tile slice, depth z = z_m + h eps), so it is exact by definition: eps is defined through it.
+ ///
+ public static float3 af_symbol(float x0, float a) => new(x0, a, 0.0f);
+
+ ///
+ /// Every value of the interval [lo, hi], uncorrelated with eps: (lo / 2 + hi / 2, 0, hi / 2 - lo / 2),
+ /// the halves taken before the sum and the difference so that endpoints near the float maximum do not
+ /// overflow in them. Rounding: x0 and e each round once, and a value of the interval is within e of x0
+ /// only up to those; S = |x0| + e. Halving a subnormal endpoint loses at most 2^-150, and the sum and
+ /// difference of subnormals are exact, so 2^-126 covers the underflow (the e of an interval spanning
+ /// one subnormal step would otherwise round to 0). |x0| + e is at most the larger endpoint
+ /// in magnitude, so it does not overflow. If e + its absorption exceeds the float maximum it is
+ /// infinity, which still encloses.
+ ///
+ public static float3 af_from_iv(float2 interval)
+ {
+ var x0 = interval.x * 0.5f + interval.y * 0.5f;
+ var e = interval.y * 0.5f - interval.x * 0.5f;
+ return new float3(x0, 0.0f, e + (abs(x0) + e) * 9.5367431640625e-7f + 1.17549435e-38f);
+ }
+
+ ///
+ /// The interval of every value of the form over every eps: x0 -+ (|a| + e), the bridge to iv_*. The
+ /// endpoints round inward by at most u (|x0| + |a| + e) each, so each is moved outward by
+ /// (|x0| + |a| + e) 2^-20, formed term by term so that the sum never passes the float maximum before it
+ /// is scaled. A form with an infinite component (an overflowed op) gives infinite
+ /// endpoints, and an endpoint that would be NaN (infinity minus infinity, or a NaN component) is
+ /// the infinity on its side, so the result is never NaN and still encloses. NaN is found by its bit
+ /// pattern, not by lo == lo, which a compiler that assumes no NaNs (dxc's default) deletes.
+ ///
+ public static float2 af_range(float3 x)
+ {
+ var r = abs(x.y) + x.z;
+ var w = abs(x.x) * 9.5367431640625e-7f + r * 9.5367431640625e-7f;
+ var lo = x.x - r - w;
+ var hi = x.x + r + w;
+ return new float2((asuint(lo) & 0x7fffffffu) > 0x7f800000u ? float.NegativeInfinity : lo,
+ (asuint(hi) & 0x7fffffffu) > 0x7f800000u ? float.PositiveInfinity : hi);
+ }
+
+ ///
+ /// Encloses x + y: (x0 + y0, a_x + a_y, e_x + e_y). The shared symbol keeps the two forms
+ /// correlated, so af_sub(x, x) has a = 0. Rounding: S = |x0| + |a| + e of the result.
+ ///
+ public static float3 af_add(float3 x, float3 y)
+ {
+ var x0 = x.x + y.x;
+ var a = x.y + y.y;
+ var e = x.z + y.z;
+ return new float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7f);
+ }
+
+ /// Encloses x - y: (x0 - y0, a_x - a_y, e_x + e_y). Rounding as af_add.
+ public static float3 af_sub(float3 x, float3 y)
+ {
+ var x0 = x.x - y.x;
+ var a = x.y - y.y;
+ var e = x.z + y.z;
+ return new float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7f);
+ }
+
+ /// Encloses -x: (-x0, -a, e). Exact.
+ public static float3 af_neg(float3 x) => new(-x.x, -x.y, x.z);
+
+ ///
+ /// Encloses x * s: (x0 s, a s, e |s|). Rounding: S = |x0| + |a| + e of the result, plus 2^-126
+ /// for underflow.
+ ///
+ public static float3 af_scale(float3 x, float s)
+ {
+ var x0 = x.x * s;
+ var a = x.y * s;
+ var e = x.z * abs(s);
+ return new float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7f + 1.17549435e-38f);
+ }
+
+ /// Encloses x + v for v in the interval, uncorrelated with eps: af_add(x, af_from_iv(interval)).
+ public static float3 af_add_iv(float3 x, float2 interval) => af_add(x, af_from_iv(interval));
+
+ ///
+ /// Encloses x * y, AF1's product: (x0 y0, x0 a_y + y0 a_x, |x0| e_y + |y0| e_x + (|a_x| + e_x)(|a_y| + e_y)).
+ /// The last term condenses the eps^2 term a_x a_y and every cross term with an error symbol into e,
+ /// so a form multiplied by itself is wider than its square: there is no af_sqr until a consumer
+ /// names one. Rounding: a can cancel, so S = |x0| + |x0 a_y| + |y0 a_x| + e, plus 2^-126 for
+ /// underflow.
+ ///
+ public static float3 af_mul(float3 x, float3 y)
+ {
+ var x0 = x.x * y.x;
+ var p = x.x * y.y;
+ var q = y.x * x.y;
+ var a = p + q;
+ var e = abs(x.x) * y.z + abs(y.x) * x.z + (abs(x.y) + x.z) * (abs(y.y) + y.z);
+ return new float3(x0, a, e + (abs(x0) + abs(p) + abs(q) + e) * 9.5367431640625e-7f + 1.17549435e-38f);
+ }
+
+ ///
+ /// Encloses snoise(p) for every p = centre + axis eps + w with |w| <= radius, from one snoise_grad at
+ /// the centre (value n, gradient g). With R = |axis| + radius it returns the narrower of two sound
+ /// forms: the Lipschitz form (n, 0, L R), L = SNOISE_LIPSCHITZ, and the centred form
+ /// (n, g . axis, |g| radius + M R^2 / 2), M = SNOISE_HESSIAN. The centred form is Taylor's theorem:
+ /// snoise(c + d) = n + g . d + r with |r| <= M |d|^2 / 2, d = axis eps + w, g . w <= |g| radius.
+ /// radius must be at least 0.
+ ///
+ /// Both forms carry an allowance for the float32 evaluation of snoise, which is not the exact
+ /// function: 2^-14 + 2^-12 R + L 2^-20 (|centre|_1 + R). The skew and the corner offsets round the
+ /// input point by at most about 2u |p|_1 before any kernel term is formed (the hashing is exact on
+ /// integers below 2^24), so a float32 snoise of p is the exact one at a point within 2u |p|_1, which
+ /// moves the value by at most L 2u |p|_1; for both p and the centre, with the caller's scaling of the
+ /// point by a frequency (one rounding) and a factor of two for a GPU, 16u = 2^-20. The kernel's
+ /// absolute rounding is at most 105 x four corners x terms of magnitude below 0.5^4 x 1.8 over about
+ /// 30 operations, under 2^-15, doubled to 2^-14; the gradient's error times |d| <= R is under 2^-13 R,
+ /// doubled to 2^-12 R. AffineTests.SnoiseFormEnclosesBall checks the result with no tolerance on the
+ /// CPU, and the fixture's enclosure check measures it on a GPU. Rounding of the form itself: S =
+ /// |n| + |a| + e. The Lipschitz form is chosen when its half-width L R is at most the centred form's
+ /// |a| + |g| radius + M R^2 / 2, so the total width is never more than the Lipschitz form's.
+ ///
+ public static float3 af_snoise(float3 centre, float3 axis, float radius)
+ {
+ var g = snoise_grad(centre);
+ var gradient = new float3(g.x, g.y, g.z);
+ var reach = length(axis) + radius;
+ var lipschitz = SNOISE_LIPSCHITZ * reach;
+ var a = dot(gradient, axis);
+ var remainder = length(gradient) * radius + 0.5f * SNOISE_HESSIAN * reach * reach;
+ var allowance = 6.103515625e-5f + 2.44140625e-4f * reach
+ + SNOISE_LIPSCHITZ * 9.5367431640625e-7f * (abs(centre.x) + abs(centre.y) + abs(centre.z) + reach);
+ var centred = abs(a) + remainder < lipschitz;
+ var slope = centred ? a : 0.0f;
+ var e = (centred ? remainder : lipschitz) + allowance;
+ return new float3(g.w, slope, e + (abs(g.w) + abs(slope) + e) * 9.5367431640625e-7f);
+ }
+
+ ///
+ /// Encloses the fBm value, sum of a_i snoise(p f_i) over the octaves, for every p = centre + axis eps
+ /// + w with |w| <= radius: the octave sum of af_snoise(centre f_i, axis f_i, radius |f_i|) scaled by
+ /// a_i, with frequency f_i and amplitude a_i compounded exactly as fbm_grad compounds them (its .w is
+ /// what AffineTests.SnoiseFormEnclosesBall encloses). The rounding of p f_i, inside fbm_grad, and of
+ /// the scaled centre and axis here, moves each point by at most 3u (|centre f_i|_1 + R f_i), inside
+ /// af_snoise's allowance for its input point. octaves is clamped to [0, 16] as there.
+ ///
+ public static float3 af_fbm(float3 centre, float3 axis, float radius, int octaves, float lacunarity, float gain)
+ {
+ octaves = clamp(octaves, 0, 16);
+ var amplitude = 1.0f;
+ var frequency = 1.0f;
+ var sum = new float3(0.0f, 0.0f, 0.0f);
+ for (var i = 0; i < octaves; i++)
+ {
+ sum = af_add(sum, af_scale(af_snoise(centre * frequency, axis * frequency, radius * abs(frequency)), amplitude));
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+
+ return sum;
+ }
+
+ ///
+ /// The axis of a screen tile's slice over the depth segment [z0, z1], for af_frustum_ball's centre:
+ /// (m_c, 1) h with h = (z1 - z0) / 2, in the camera frame of iv_frustum_ball (a pinhole at the
+ /// origin looking down +z, the ray of slope m the points (m z, z)). Its z component is h itself, the
+ /// symbol's coefficient for depth: z = z_m + h eps. Its rounding is af_frustum_ball's.
+ ///
+ public static float3 af_frustum_axis(float2 centreSlope, float z0, float z1)
+ {
+ var h = (z1 - z0) * 0.5f;
+ return new float3(centreSlope.x * h, centreSlope.y * h, h);
+ }
+
+ ///
+ /// The affine slice of a screen tile over [z0, z1]: a centre (xyz) and radius (w) such that every point
+ /// of every ray of the tile at depth z in [z0, z1] is centre + axis eps(z) + w', |w'| <= radius, with
+ /// axis = af_frustum_axis(centreSlope, z0, z1), z_m = (z0 + z1) / 2, h = (z1 - z0) / 2 (both float32,
+ /// as computed here) and eps(z) = clamp((z - z_m) / h, -1, 1) (0 where h is 0). The centre is
+ /// (m_c z_m, z_m) and the radius z1 footprintPerDepth + warpVariation, where footprintPerDepth is
+ /// iv_frustum_ball's and warpVariation is what the caller's warp can add once its value at the centre
+ /// is applied to the centre (design.md, "Affine forms", the centred warp). Derivation: a point of
+ /// slope m_c + e (|e| <= footprintPerDepth) at depth z is (m_c z_m, z_m) + (m_c, 1)(z - z_m) +
+ /// (e z, 0), and (m_c, 1)(z - z_m) = axis eps(z) + (m_c, 1) r(z), where the clamp residual
+ /// |r(z)| = |z - z_m - h eps(z)| is at most u (|z_m| + h), one rounding each of z_m and h. A caller
+ /// taking depth as af_symbol(z_m, h) adds the same residual, 2^-23 (|z_m| + h) covers it, to that
+ /// form's e. Rounding: the centre's products and the axis's products round once each (u |c|_1 and
+ /// u |axis|_1 against |eps| <= 1), the residual is at most u (|c|_1 + |axis|_1) since
+ /// |(m_c, 1)| <= |m_c|_1 + 1, and the radius rounds at most four times; 2^-20 (|c|_1 + |axis|_1 +
+ /// radius) covers it twice over (AffineTests.FrustumSliceEnclosesEveryRayPoint, extreme families
+ /// included). The caller rotates and translates the centre into world space, rotates the axis, and
+ /// scales all three by its noise frequency; the rounding of that transform is the caller's.
+ ///
+ public static float4 af_frustum_ball(float2 centreSlope, float z0, float z1, float footprintPerDepth, float warpVariation)
+ {
+ var zm = (z0 + z1) * 0.5f;
+ var h = (z1 - z0) * 0.5f;
+ var cx = centreSlope.x * zm;
+ var cy = centreSlope.y * zm;
+ var spread = (abs(centreSlope.x) + abs(centreSlope.y) + 1.0f) * h;
+ var radius = z1 * footprintPerDepth + warpVariation;
+ radius += (abs(cx) + abs(cy) + abs(zm) + spread + radius) * 9.5367431640625e-7f;
+ return new float4(cx, cy, zm, radius);
+ }
+}
diff --git a/packages/cultmath/src/CultMath/math.Affine.cs.meta b/packages/cultmath/src/CultMath/math.Affine.cs.meta
new file mode 100644
index 00000000..34ba0047
--- /dev/null
+++ b/packages/cultmath/src/CultMath/math.Affine.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 86b87ffb6c8a4d72b067a64f9f8a06ce
diff --git a/packages/cultmath/src/CultMath/math.Interval.cs b/packages/cultmath/src/CultMath/math.Interval.cs
index ec6c1ea6..5d0a6da4 100644
--- a/packages/cultmath/src/CultMath/math.Interval.cs
+++ b/packages/cultmath/src/CultMath/math.Interval.cs
@@ -20,6 +20,14 @@ public static partial class math
// snoise kernel must re-run MeasureLipschitz and re-pin this constant.
public const float SNOISE_LIPSCHITZ = 7.9640074f;
+ // Lipschitz constant of snoise(float2) in its input, with SNOISE_LIPSCHITZ's provenance rule:
+ // NoiseBoundTests.MeasureLipschitz2 (slow, explicit) takes the largest gradient length (central
+ // differences over exact float steps) over 1e6 seeded points, refines the 1e4 largest by ascent and
+ // multiplies by 1.10; NoiseBoundTests.Lipschitz2ConstantPins pins it against a fast re-measure and
+ // the ascent from MeasureLipschitz2's witness. A change to the 2D snoise kernel must re-run
+ // MeasureLipschitz2 and re-pin this constant.
+ public const float SNOISE2_LIPSCHITZ = 8.117002f;
+
/// The point interval [x, x].
public static float2 iv_point(float value) => new(value, value);
@@ -142,6 +150,22 @@ public static partial class math
return new(max(n - e, -1.0f), min(n + e, 1.0f));
}
+ ///
+ /// Encloses snoise(x) for every 2D x within distance radius of centre: [n - L2 r, n + L2 r] intersected
+ /// with [-1, 1], n = snoise(centre), L2 = SNOISE2_LIPSCHITZ. radius must be at least 0. One snoise
+ /// evaluation, value only. Like iv_snoise_ball(float3) it is exact for the point it is handed and
+ /// carries no allowance for the float32 evaluation: a consumer whose 2D flow is evaluated at points
+ /// it rounds itself (a shifted, scaled or projected point) adds 2^-14 + L2 2^-20 (|centre|_1 + radius)
+ /// to the width, the convention af_snoise carries for the 3D point
+ /// (NoiseBoundTests.FlowVariationCarriesItsAllowance, CentredWarpStaysEnclosed).
+ ///
+ public static float2 iv_snoise_ball(float2 centre, float radius)
+ {
+ var n = snoise(centre);
+ var e = SNOISE2_LIPSCHITZ * radius;
+ return new(max(n - e, -1.0f), min(n + e, 1.0f));
+ }
+
///
/// Encloses the fBm value, sum of a_i * snoise(x * f_i) over the octaves, for every x within distance
/// radius of centre: the octave sum of iv_snoise_ball(centre * f_i, radius * |f_i|) scaled by a_i,
diff --git a/packages/cultmath/tests/CultMath.Tests/AffineTests.cs b/packages/cultmath/tests/CultMath.Tests/AffineTests.cs
new file mode 100644
index 00000000..51bcacc5
--- /dev/null
+++ b/packages/cultmath/tests/CultMath.Tests/AffineTests.cs
@@ -0,0 +1,699 @@
+using CultMath;
+using Xunit;
+using static CultMath.math;
+
+namespace CultMath.Tests;
+
+///
+/// The affine forms of math.Affine.cs (design.md, "Affine forms"). A form (x0, a, e) is the set
+/// x0 + a eps + e delta at the region's shared eps; every check evaluates that set in double and the
+/// pointwise function in float32, with no tolerance. Operand values are float32 values drawn inside
+/// their operands' sets at one shared eps, endpoints (eps and delta at -1 and 1) included.
+///
+public sealed class AffineTests
+{
+ private readonly ITestOutputHelper output;
+
+ public AffineTests(ITestOutputHelper output) => this.output = output;
+
+ private static float Uniform(System.Random random, float lo, float hi) => lo + (hi - lo) * random.NextSingle();
+
+ private static float LogUniform(System.Random random, float lo, float hi) =>
+ MathF.Exp(Uniform(random, MathF.Log(lo), MathF.Log(hi)));
+
+ private static float Signed(System.Random random, float magnitude) => random.Next(2) == 0 ? -magnitude : magnitude;
+
+ // Whether value lies in the form's set at eps, in double.
+ private static bool InForm(float3 form, float eps, double value) =>
+ Math.Abs(value - (form.x + (double)form.y * eps)) <= form.z;
+
+ // A form with its centre in [-20, 20] and |a| and e log-uniform over [1e-5, 20]; one in eight has
+ // a = 0 and one in eight e = 0.
+ private static float3 DrawForm(System.Random random)
+ {
+ var x0 = Uniform(random, -20.0f, 20.0f);
+ var a = random.Next(8) == 0 ? 0.0f : Signed(random, LogUniform(random, 1.0e-5f, 20.0f));
+ var e = random.Next(8) == 0 ? 0.0f : LogUniform(random, 1.0e-5f, 20.0f);
+ return new float3(x0, a, e);
+ }
+
+ private static float2 DrawInterval(System.Random random)
+ {
+ var lo = Uniform(random, -20.0f, 20.0f);
+ return new float2(lo, lo + (random.Next(8) == 0 ? 0.0f : LogUniform(random, 1.0e-5f, 40.0f)));
+ }
+
+ // The tiny family: magnitudes from 1e-21 to 1e-17, products near and under 2^-126 = 1.2e-38, where a
+ // float32 result rounds to a subnormal and the absorption S 2^-20 is smaller than that loss.
+ private static float3 DrawTiny(System.Random random) =>
+ new(random.Next(8) == 0 ? 0.0f : Signed(random, LogUniform(random, 1.0e-21f, 1.0e-17f)),
+ random.Next(4) == 0 ? 0.0f : Signed(random, LogUniform(random, 1.0e-21f, 1.0e-17f)),
+ random.Next(4) == 0 ? 0.0f : LogUniform(random, 1.0e-21f, 1.0e-17f));
+
+ private static float2 DrawTinyInterval(System.Random random)
+ {
+ var lo = Signed(random, LogUniform(random, 1.0e-21f, 1.0e-17f));
+ return new float2(lo, lo + (random.Next(8) == 0 ? 0.0f : LogUniform(random, 1.0e-21f, 1.0e-17f)));
+ }
+
+ // A float32 value in the form's set at eps, delta at an endpoint when asked; NaN when rounding leaves
+ // no float of the set near the drawn point (a set narrower than an ulp).
+ private static float Member(System.Random random, float3 form, float eps, bool endpoint)
+ {
+ var centre = form.x + (double)form.y * eps;
+ var delta = endpoint ? (random.Next(2) == 0 ? -1.0 : 1.0) : Uniform(random, -1.0f, 1.0f);
+ var value = (float)(centre + form.z * delta);
+ for (var k = 0; k < 4 && !InForm(form, eps, value); k++)
+ value = value > centre ? MathF.BitDecrement(value) : MathF.BitIncrement(value);
+ return InForm(form, eps, value) ? value : float.NaN;
+ }
+
+ private static float MemberOf(System.Random random, float2 interval, bool endpoint) =>
+ endpoint ? (random.Next(2) == 0 ? interval.x : interval.y) : Math.Clamp(Uniform(random, interval.x, interval.y), interval.x, interval.y);
+
+ private readonly record struct Operands(float3 X, float3 Y, float2 Iv, float S);
+
+ private readonly record struct Values(float X, float Y, float V, float S);
+
+ // One op under the harness: Build gives the result's membership test (eps, value) from the operand
+ // forms, F the pointwise float32 function of operand values.
+ private sealed record Op(string Name, Func> Build, Func F);
+
+ private static Func Form(float3 form) => (eps, value) => InForm(form, eps, value);
+
+ private static Func Range(float2 range) => (_, value) => value >= range.x && value <= range.y;
+
+ private static readonly Op[] Ops =
+ {
+ new("af_point", o => Form(af_point(o.X.x)), v => v.S),
+ new("af_symbol", o => Form(af_symbol(o.X.x, o.X.y)), v => v.S),
+ new("af_from_iv", o => Form(af_from_iv(o.Iv)), v => v.V),
+ new("af_range", o => Range(af_range(o.X)), v => v.X),
+ new("af_add", o => Form(af_add(o.X, o.Y)), v => v.X + v.Y),
+ new("af_sub", o => Form(af_sub(o.X, o.Y)), v => v.X - v.Y),
+ new("af_neg", o => Form(af_neg(o.X)), v => -v.X),
+ new("af_scale", o => Form(af_scale(o.X, o.S)), v => v.X * v.S),
+ new("af_add_iv", o => Form(af_add_iv(o.X, o.Iv)), v => v.X + v.V),
+ new("af_mul", o => Form(af_mul(o.X, o.Y)), v => v.X * v.Y),
+ };
+
+ // Runs one op over `forms` seeded operand draws x 16 (eps, delta) draws; returns the misses and up to
+ // four witnesses. The first four draws per form put eps at an endpoint, the first eight delta.
+ // af_point and af_symbol are checked on their defining value: the point x0 itself, and x0 + a eps in
+ // double (the symbol defines eps, so it has no float32 evaluation to enclose).
+ private static (int Misses, List Witness) Harness(Op op, int seed, int forms = 10_000, Func? draw = null, bool tiny = false)
+ {
+ draw ??= tiny ? DrawTiny : DrawForm;
+ var random = new System.Random(seed);
+ var misses = 0;
+ var witness = new List();
+ for (var t = 0; t < forms; t++)
+ {
+ var operands = new Operands(draw(random), draw(random), tiny ? DrawTinyInterval(random) : DrawInterval(random),
+ random.Next(8) == 0 ? 0.0f : tiny ? Signed(random, LogUniform(random, 1.0e-32f, 1.0e-19f)) : Uniform(random, -4.0f, 4.0f));
+ var contains = op.Build(operands);
+ for (var d = 0; d < 16; d++)
+ {
+ var eps = d < 4 ? (d % 2 == 0 ? -1.0f : 1.0f) : Uniform(random, -1.0f, 1.0f);
+ var endpoint = d < 8;
+ var x = Member(random, operands.X, eps, endpoint);
+ var y = Member(random, operands.Y, eps, endpoint);
+ if (float.IsNaN(x) || float.IsNaN(y))
+ continue;
+ var v = MemberOf(random, operands.Iv, endpoint);
+ double f = op.Name switch
+ {
+ "af_point" => operands.X.x,
+ "af_symbol" => operands.X.x + (double)operands.X.y * eps,
+ _ => op.F(new Values(x, y, v, operands.S)),
+ };
+ if (!contains(eps, f))
+ {
+ misses++;
+ if (witness.Count < 4)
+ witness.Add($"{op.Name}: X {operands.X}, Y {operands.Y}, iv {operands.Iv}, s {operands.S:R}; eps {eps:R}, values ({x:R}, {y:R}, {v:R}) give {f:R}");
+ }
+ }
+ }
+
+ return (misses, witness);
+ }
+
+ [Fact]
+ public void EveryOpEnclosesItsPoints()
+ {
+ var failures = new List();
+ foreach (var op in Ops)
+ {
+ var (misses, witness) = Harness(op, 0xAF00);
+ if (misses > 0)
+ failures.Add($"{op.Name}: {misses} misses" + Environment.NewLine + string.Join(Environment.NewLine, witness));
+ }
+
+ Assert.True(failures.Count == 0, string.Join(Environment.NewLine, failures));
+ }
+
+ private static float3 Shrink(float3 form) => new(form.x, form.y, form.z > 0.0f ? MathF.BitDecrement(form.z) : 0.0f);
+
+ // Each op with its rounding absorption removed: the propagated error alone, computed in float32.
+ private static readonly Op[] Unabsorbed =
+ {
+ new("af_from_iv", o => Form(new float3((o.Iv.x + o.Iv.y) * 0.5f, 0.0f, (o.Iv.y - o.Iv.x) * 0.5f)), v => v.V),
+ new("af_range", o => Range(new float2(o.X.x - (MathF.Abs(o.X.y) + o.X.z), o.X.x + (MathF.Abs(o.X.y) + o.X.z))), v => v.X),
+ new("af_add", o => Form(new float3(o.X.x + o.Y.x, o.X.y + o.Y.y, o.X.z + o.Y.z)), v => v.X + v.Y),
+ new("af_sub", o => Form(new float3(o.X.x - o.Y.x, o.X.y - o.Y.y, o.X.z + o.Y.z)), v => v.X - v.Y),
+ new("af_scale", o => Form(new float3(o.X.x * o.S, o.X.y * o.S, o.X.z * MathF.Abs(o.S))), v => v.X * v.S),
+ new("af_add_iv", o => Form(new float3(o.X.x + (o.Iv.x + o.Iv.y) * 0.5f, o.X.y, o.X.z + (o.Iv.y - o.Iv.x) * 0.5f)), v => v.X + v.V),
+ new("af_mul", o => Form(new float3(o.X.x * o.Y.x, o.X.x * o.Y.y + o.Y.x * o.X.y,
+ MathF.Abs(o.X.x) * o.Y.z + MathF.Abs(o.Y.x) * o.X.z + (MathF.Abs(o.X.y) + o.X.z) * (MathF.Abs(o.Y.y) + o.Y.z))), v => v.X * v.Y),
+ };
+
+ // One-ulp mutants that survive, each with the reason. A rounding absorption bounds the worst case
+ // over every operand value, and 2^-20 S is 16u S, at least eight ulps of the larger of |x0|, |a| and
+ // e; one ulp less of e leaves the rest of that margin, which no sampled rounding can cross.
+ private static readonly Dictionary OneUlpSurvivors = new()
+ {
+ ["af_from_iv"] = "the absorption (|x0| + e) 2^-20 is at least eight ulps of e over the one rounding of x0 and e it covers",
+ ["af_range"] = "each endpoint moves outward by (|x0| + |a| + e) 2^-20, eight ulps past the one rounding it covers",
+ ["af_add"] = "the absorption 2^-20 S is eight ulps of S's largest term past the three roundings it covers",
+ ["af_sub"] = "as af_add",
+ ["af_scale"] = "as af_add",
+ ["af_add_iv"] = "two absorptions, af_from_iv's and af_add's",
+ ["af_mul"] = "the absorption 2^-20 (|x0| + |x0 a_y| + |y0 a_x| + e) is eight ulps past the products it covers",
+ };
+
+ ///
+ /// The rounding absorptions are load-bearing: with each op's absorption removed (Unabsorbed), the
+ /// harness finds a miss for every op. Each op's e shrunk by one ulp is run too; it survives for every
+ /// op, because the absorption is a worst-case bound many ulps wide, and each survivor is named with
+ /// its reason in OneUlpSurvivors. A one-ulp mutant that starts failing, or one that is not named,
+ /// fails this test, so the list cannot go stale.
+ ///
+ [Fact]
+ public void EveryRoundingTermIsCaught()
+ {
+ var problems = new List();
+ foreach (var mutant in Unabsorbed)
+ {
+ var (misses, _) = Harness(mutant, 0xAF01);
+ output.WriteLine($"AF-REPORT {mutant.Name} without absorption: {misses} misses");
+ if (misses == 0)
+ problems.Add($"{mutant.Name}: removing the rounding absorption is not caught");
+ }
+
+ foreach (var op in Ops.Where(o => o.Name is not ("af_point" or "af_symbol" or "af_neg")))
+ {
+ var shrunk = op.Name == "af_range"
+ ? op with { Build = o => { var r = af_range(o.X); return Range(new float2(MathF.BitIncrement(r.x), MathF.BitDecrement(r.y))); } }
+ : op with { Build = o => Form(Shrink(BuildForm(op.Name, o))) };
+ var (misses, _) = Harness(shrunk, 0xAF02);
+ output.WriteLine($"AF-REPORT {op.Name} with e one ulp short: {misses} misses");
+ var named = OneUlpSurvivors.ContainsKey(op.Name);
+ if (misses == 0 && !named)
+ problems.Add($"{op.Name}: e one ulp short survives and is not named");
+ if (misses > 0 && named)
+ problems.Add($"{op.Name}: e one ulp short is now caught; remove it from OneUlpSurvivors");
+ }
+
+ Assert.True(problems.Count == 0, string.Join(Environment.NewLine, problems));
+ }
+
+ private static float3 BuildForm(string name, Operands o) => name switch
+ {
+ "af_from_iv" => af_from_iv(o.Iv),
+ "af_add" => af_add(o.X, o.Y),
+ "af_sub" => af_sub(o.X, o.Y),
+ "af_scale" => af_scale(o.X, o.S),
+ "af_add_iv" => af_add_iv(o.X, o.Iv),
+ "af_mul" => af_mul(o.X, o.Y),
+ _ => throw new ArgumentException(name),
+ };
+
+ ///
+ /// The shared symbol correlates: for x = af_symbol(x0, a), af_sub(x, x) and af_add(x, af_neg(x)) have
+ /// a = 0 and e at most their own rounding, and af_sub(af_scale(x, 2), af_add(x, x)) has a = 0. A
+ /// mutant of af_add, af_sub or af_scale that condensed a into e would leave e of order |a|.
+ ///
+ [Fact]
+ public void SharedSymbolCorrelates()
+ {
+ var random = new System.Random(0xAF03);
+ for (var t = 0; t < 10_000; t++)
+ {
+ var x = af_symbol(Uniform(random, -20.0f, 20.0f), Signed(random, LogUniform(random, 1.0e-5f, 20.0f)));
+ foreach (var (name, form) in new[]
+ {
+ ("af_sub(x, x)", af_sub(x, x)),
+ ("af_add(x, af_neg(x))", af_add(x, af_neg(x))),
+ ("af_sub(af_scale(x, 2), af_add(x, x))", af_sub(af_scale(x, 2.0f), af_add(x, x))),
+ })
+ {
+ var rounding = (MathF.Abs(x.x) + MathF.Abs(x.y)) * 1.0e-5f;
+ Assert.True(form.y == 0.0f && form.z <= rounding, $"{name} for x = {x} is {form}: a must be 0 and e at most {rounding:R}");
+ }
+ }
+ }
+
+ // Forms whose range straddles zero (|x0| below |a| + e) or is one-signed (|x0| above it).
+ private static float3 DrawSigned(System.Random random, bool straddle)
+ {
+ var a = Signed(random, LogUniform(random, 1.0e-3f, 10.0f));
+ var e = LogUniform(random, 1.0e-3f, 10.0f);
+ var reach = MathF.Abs(a) + e;
+ return new float3(Signed(random, straddle ? Uniform(random, 0.0f, 0.9f * reach) : reach * Uniform(random, 1.1f, 4.0f)), a, e);
+ }
+
+ ///
+ /// af_mul encloses the product over forms that straddle zero and forms that are one-signed, every
+ /// sign combination. The eps^2 term a_x a_y is what the condensed e carries for eps at +-1: a mutant
+ /// dropping |a_x a_y| from e misses there.
+ ///
+ [Fact]
+ public void MulEnclosesEverySignCase()
+ {
+ var mul = Ops.Single(o => o.Name == "af_mul");
+ var dropped = mul with
+ {
+ Build = o =>
+ {
+ var r = af_mul(o.X, o.Y);
+ return Form(new float3(r.x, r.y, r.z - MathF.Abs(o.X.y * o.Y.y)));
+ },
+ };
+ foreach (var (sx, sy) in new[] { (true, true), (true, false), (false, true), (false, false) })
+ {
+ var seed = 0xAF04 + (sx ? 1 : 0) + (sy ? 2 : 0);
+ var flip = 0;
+ float3 Draw(System.Random r) => DrawSigned(r, (flip++ % 2 == 0) ? sx : sy);
+ var (misses, witness) = Harness(mul, seed, 5_000, Draw);
+ Assert.True(misses == 0, $"af_mul, straddling ({sx}, {sy}): {misses} misses" + Environment.NewLine + string.Join(Environment.NewLine, witness));
+ flip = 0;
+ var (caught, _) = Harness(dropped, seed, 5_000, Draw);
+ Assert.True(caught > 0, $"af_mul without |a_x a_y|, straddling ({sx}, {sy}), is not caught");
+ }
+ }
+
+ // af_snoise's float32 allowance, as its doc comment states it, for the width comparison below.
+ private static double Allowance(float3 centre, double reach) =>
+ Math.ScaleB(1.0, -14) + Math.ScaleB(reach, -12)
+ + SNOISE_LIPSCHITZ * Math.ScaleB(Math.Abs(centre.x) + Math.Abs(centre.y) + Math.Abs(centre.z) + reach, -20);
+
+ private static float3 UnitVector(System.Random random)
+ {
+ float3 v;
+ do
+ {
+ v = new float3(Uniform(random, -1.0f, 1.0f), Uniform(random, -1.0f, 1.0f), Uniform(random, -1.0f, 1.0f));
+ }
+ while (dot(v, v) > 1.0f || dot(v, v) < 1.0e-4f);
+
+ return normalize(v);
+ }
+
+ // A float32 point of the set centre + axis eps + w, |w| <= radius, checked in double; the first eight
+ // w are on the surface. Where the float32 sum rounds a point out of the set, w is pulled in by the
+ // overshoot and 2^-21 (|centre|_1 + |axis|_1) and the sum retried; a point that still rounds out is
+ // reported as null and skipped.
+ private static float3? PointOf(System.Random random, float3 centre, float3 axis, float radius, float eps, int index)
+ {
+ var w = UnitVector(random) * (index < 8 ? radius : radius * MathF.Cbrt(random.NextSingle()));
+ for (var k = 0; k < 6; k++)
+ {
+ var p = centre + axis * eps + w;
+ var (dx, dy, dz) = (p.x - (centre.x + (double)axis.x * eps), p.y - (centre.y + (double)axis.y * eps), p.z - (centre.z + (double)axis.z * eps));
+ var distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
+ if (distance <= radius)
+ return p;
+ w *= (float)(Math.Max(0.0, 2.0 * radius - distance - Math.ScaleB(Math.Abs(centre.x) + Math.Abs(centre.y) + Math.Abs(centre.z) + Math.Abs(axis.x) + Math.Abs(axis.y) + Math.Abs(axis.z), -21)) / radius);
+ }
+
+ return null;
+ }
+
+ ///
+ /// af_snoise and af_fbm over 2,000 (centre, axis, radius) each: centres in [-20, 20]^3, radius
+ /// log-uniform in [1e-4, 2], |axis| uniform in [0, 2] (an eighth exactly 0). 64 points
+ /// centre + axis eps + w per case, eps at -1 and 1 for the first eight; snoise (fbm_grad(...).w) in
+ /// float32 lies in the form at eps, no tolerance. Dropping the M R^2 / 2 remainder from a centred
+ /// form misses. af_snoise's total width is never more than the Lipschitz form's, L R plus the
+ /// allowance.
+ ///
+ [Fact]
+ public void SnoiseFormEnclosesBall()
+ {
+ var random = new System.Random(0xAF10);
+ var (misses, remainderMisses, skipped, centredCases) = (0, 0, 0, 0);
+ var witness = new List();
+ for (var b = 0; b < 4000; b++)
+ {
+ var fbm = b >= 2000;
+ var centre = new float3(Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f));
+ var axis = random.Next(8) == 0 ? new float3(0.0f, 0.0f, 0.0f) : UnitVector(random) * Uniform(random, 0.0f, 2.0f);
+ var radius = LogUniform(random, 1.0e-4f, 2.0f);
+ var (octaves, lacunarity, gain) = (random.Next(0, 7), Uniform(random, 1.5f, 2.5f), Uniform(random, 0.3f, 0.7f));
+ var form = fbm ? af_fbm(centre, axis, radius, octaves, lacunarity, gain) : af_snoise(centre, axis, radius);
+ var reach = (double)length(axis) + radius;
+ var remainder = 0.5 * SNOISE_HESSIAN * reach * reach;
+ var mutant = new float3(form.x, form.y, (float)(form.z - remainder));
+ if (!fbm)
+ {
+ var lipschitz = (SNOISE_LIPSCHITZ * reach + Allowance(centre, reach) + Math.ScaleB(Math.Abs(form.x), -20)) * (1.0 + Math.ScaleB(1.0, -18));
+ Assert.True(Math.Abs(form.y) + form.z <= lipschitz, $"af_snoise({centre}, {axis}, {radius:R}) = {form} is wider than the Lipschitz form's half-width {lipschitz:R}");
+ centredCases += form.y != 0.0f ? 1 : 0;
+ }
+
+ for (var i = 0; i < 64; i++)
+ {
+ var eps = i < 8 ? (i % 2 == 0 ? -1.0f : 1.0f) : Uniform(random, -1.0f, 1.0f);
+ var p = PointOf(random, centre, axis, radius, eps, i);
+ if (p is not { } point)
+ {
+ skipped++;
+ continue;
+ }
+
+ var value = fbm ? fbm_grad(point, octaves, lacunarity, gain).w : snoise(point);
+ if (!InForm(form, eps, value))
+ {
+ misses++;
+ if (witness.Count < 4)
+ witness.Add($"{(fbm ? $"af_fbm(..., {octaves}, {lacunarity:R}, {gain:R})" : "af_snoise")}({centre}, {axis}, {radius:R}) = {form} misses {value:R} at eps {eps:R}, {point}");
+ }
+
+ if (!fbm && form.y != 0.0f && !InForm(mutant, eps, value))
+ remainderMisses++;
+ }
+ }
+
+ output.WriteLine($"AF-REPORT af_snoise/af_fbm enclosure: {misses} misses, {skipped} points skipped (rounded out of the set), {centredCases} of 2000 af_snoise cases centred, {remainderMisses} misses with the remainder dropped");
+ Assert.True(misses == 0, string.Join(Environment.NewLine, witness));
+ Assert.True(skipped < 64 * 4000 / 100, $"{skipped} points rounded out of their sets");
+ Assert.True(remainderMisses > 0, "dropping M R^2 / 2 from the centred form is not caught");
+ }
+
+ ///
+ /// At radius 1e-3 and |axis| = 1e-3, af_snoise takes the centred form in every one of 2,000 seeded
+ /// cases (a is nonzero), and its mean total width is under half of the Lipschitz form's 2 L R. A
+ /// mutant that always returns the Lipschitz form has a = 0.
+ ///
+ [Fact]
+ public void SnoiseChoosesTheCentredFormWhereNarrower()
+ {
+ var random = new System.Random(0xAF11);
+ var sum = 0.0;
+ for (var b = 0; b < 2000; b++)
+ {
+ var centre = new float3(Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f));
+ var axis = UnitVector(random) * 1.0e-3f;
+ var form = af_snoise(centre, axis, 1.0e-3f);
+ var lipschitz = 2.0 * SNOISE_LIPSCHITZ * 2.0e-3;
+ var width = 2.0 * (Math.Abs(form.y) + form.z);
+ Assert.True(form.y != 0.0f && width < lipschitz, $"af_snoise({centre}, {axis}, 1e-3) = {form}: not the centred form, or no narrower than 2 L R = {lipschitz:R}");
+ sum += width / lipschitz;
+ }
+
+ output.WriteLine($"AF-REPORT af_snoise at radius 1e-3: mean width over 2 L R {sum / 2000:F3}");
+ Assert.True(sum / 2000 < 0.5, $"mean width over 2 L R is {sum / 2000:F3}, not under half");
+ }
+
+ ///
+ /// af_frustum_ball and af_frustum_axis over iv_frustum_ball's families (NoiseBoundTests.DrawBallCase:
+ /// the r2 domain and the degenerate, thin, wide-slope, far, from-the-camera, tiny-focal and huge-warp
+ /// extremes), 2,000 tiles each, warp passed as the warp variation: every exact ray point (m z, z),
+ /// formed in double from the float32 slope and depth at the footprint's corners at both depth ends
+ /// (and 56 more for the r2 domain), moved by a full-length outward flow of length warp, is within
+ /// radius of centre + axis eps(z), eps(z) = clamp((z - z_m) / h, -1, 1) with z_m and h the centre's z
+ /// and the axis's z (0 when h is 0). The radius is pinned to the derivation both ways:
+ /// r <= w <= r + 2^-19 (r + |c|_1 + |axis|_1), r = z1 footprintPerDepth + warp in double.
+ ///
+ [Fact]
+ public void FrustumSliceEnclosesEveryRayPoint()
+ {
+ var random = new System.Random(0xAF12);
+ string[] families = { "r2 domain", "degenerate", "thin", "wide slope", "far", "from the camera", "tiny focal", "huge warp" };
+ var failures = new Dictionary();
+ var witness = new List();
+ foreach (var family in families)
+ {
+ failures[family] = 0;
+ for (var t = 0; t < 2000; t++)
+ {
+ var (n, focal, slope, z0, z1, warp) = NoiseBoundTests.DrawBallCase(random, family);
+ var half = n / (2.0f * focal);
+ var footprint = n / (MathF.Sqrt(2.0f) * focal);
+ var axis = af_frustum_axis(slope, z0, z1);
+ var ball = af_frustum_ball(slope, z0, z1, footprint, warp);
+ var (cx, cy, cz, w) = ((double)ball.x, (double)ball.y, (double)ball.z, (double)ball.w);
+ var r = z1 * (double)footprint + warp;
+ var c1 = Math.Abs(cx) + Math.Abs(cy) + Math.Abs(cz);
+ var a1 = Math.Abs((double)axis.x) + Math.Abs((double)axis.y) + Math.Abs((double)axis.z);
+ if (!(r <= w && w <= r + Math.ScaleB(r + c1 + a1, -19)))
+ {
+ failures[family]++;
+ if (witness.Count < 8)
+ witness.Add($"{family} pin: af_frustum_ball({slope}, {z0:R}, {z1:R}, {footprint:R}, {warp:R}) = {ball}, derivation {r:R}");
+ }
+
+ // The axis is (m_c, 1) h exactly, and the radius carries the documented widening, the
+ // rounding of the centre, the axis (spread) and the radius at 2^-20 each, to 15% (the
+ // radius rounds too).
+ var h = (z1 - z0) * 0.5f;
+ var spread = ((double)Math.Abs(slope.x) + Math.Abs(slope.y) + 1.0) * h;
+ var widening = Math.ScaleB(c1 + spread + r, -20);
+ if (!(axis.z == h && axis.x == slope.x * h && axis.y == slope.y * h && Math.Abs(w - r - widening) <= 0.15 * widening + Math.ScaleB(w, -22)))
+ {
+ failures[family]++;
+ if (witness.Count < 8)
+ witness.Add($"{family} axis or widening: af_frustum_ball({slope}, {z0:R}, {z1:R}, {footprint:R}, {warp:R}) = {ball}, axis {axis}, widening {w - r:R} against {widening:R}");
+ }
+
+ for (var i = 0; i < (family == "r2 domain" ? 64 : 8); i++)
+ {
+ var offset = i < 8
+ ? new float2((i & 1) == 0 ? -half : half, (i & 2) == 0 ? -half : half)
+ : new float2(Uniform(random, -half, half), Uniform(random, -half, half));
+ var z = i < 8 ? ((i & 4) == 0 ? z0 : z1) : Uniform(random, z0, z1);
+ var m = slope + offset;
+ var eps = axis.z == 0.0f ? 0.0 : Math.Clamp((z - cz) / axis.z, -1.0, 1.0);
+ var (qx, qy, qz) = (cx + axis.x * eps, cy + axis.y * eps, cz + axis.z * eps);
+ var (dx, dy, dz) = (m.x * (double)z - qx, m.y * (double)z - qy, z - qz);
+ var away = Math.Sqrt(dx * dx + dy * dy + dz * dz);
+ var distance = away + warp;
+ if (!(distance <= w))
+ {
+ failures[family]++;
+ if (witness.Count < 8)
+ witness.Add($"{family}: af_frustum_ball({slope}, {z0:R}, {z1:R}, {footprint:R}, {warp:R}) = {ball}, axis {axis} misses slope {m}, depth {z:R} by {(distance - w) / w:R} r");
+ }
+ }
+ }
+ }
+
+ Assert.True(failures.Values.Sum() == 0, string.Join(", ", families.Select(f => $"{f} {failures[f]}")) + Environment.NewLine + string.Join(Environment.NewLine, witness));
+ }
+
+ ///
+ /// Underflow. Operands of magnitude 1e-21 to 1e-17 put products near and under 2^-126, where float32
+ /// rounds to a subnormal and the relative absorption S 2^-20 is smaller than the loss: every op
+ /// still encloses, no tolerance. af_mul and af_scale carry the 2^-126 term; a mutant that subtracts
+ /// it misses here.
+ ///
+ [Fact]
+ public void TinyOperandsEncloseTheirPoints()
+ {
+ var failures = new List();
+ foreach (var op in Ops)
+ {
+ var (misses, witness) = Harness(op, 0xAF05, 10_000, tiny: true);
+ if (misses > 0)
+ failures.Add($"{op.Name}: {misses} misses" + Environment.NewLine + string.Join(Environment.NewLine, witness));
+ }
+
+ Assert.True(failures.Count == 0, string.Join(Environment.NewLine, failures));
+ }
+
+ private const float MinNormal = 1.17549435e-38f;
+
+ private static bool Near(double observed, double expected, double relative = 1.0e-5) =>
+ Math.Abs(observed - expected) <= relative * Math.Abs(expected);
+
+ ///
+ /// The rounding absorption of each op, pinned both ways. With no propagated error in e, af_add,
+ /// af_sub, af_scale, af_mul and af_from_iv return an e equal to their documented absorption (and
+ /// 2^-126 where documented) to a part in 1e5 of its double value, and af_range moves each endpoint
+ /// outward by (|x0| + |a| + e) 2^-20 to 30% (the endpoints round once). A factor, a sign or an
+ /// operator changed in any of them fails here; the one-ulp changes of the worst-case absorption are
+ /// the OneUlpSurvivors set EveryRoundingTermIsCaught names.
+ ///
+ [Fact]
+ public void AbsorptionsArePinned()
+ {
+ var u20 = Math.ScaleB(1.0, -20);
+ var random = new System.Random(0xAF06);
+ for (var t = 0; t < 2_000; t++)
+ {
+ var (x0, y0) = (Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f));
+ var (ax, ay) = (Signed(random, LogUniform(random, 1.0e-3f, 20.0f)), Signed(random, LogUniform(random, 1.0e-3f, 20.0f)));
+ var scale = Signed(random, LogUniform(random, 1.0e-2f, 4.0f));
+ var x = new float3(x0, ax, 0.0f);
+ var y = new float3(y0, ay, 0.0f);
+
+ var sum = af_add(x, y);
+ Assert.True(Near(sum.z, (Math.Abs((double)sum.x) + Math.Abs((double)sum.y)) * u20), $"af_add({x}, {y}) = {sum}: e is not (|x0| + |a|) 2^-20");
+ var difference = af_sub(x, y);
+ Assert.True(Near(difference.z, (Math.Abs((double)difference.x) + Math.Abs((double)difference.y)) * u20), $"af_sub({x}, {y}) = {difference}: e is not (|x0| + |a|) 2^-20");
+ var scaled = af_scale(x, scale);
+ Assert.True(Near(scaled.z, (Math.Abs((double)scaled.x) + Math.Abs((double)scaled.y)) * u20 + MinNormal), $"af_scale({x}, {scale:R}) = {scaled}: e is not (|x0| + |a|) 2^-20 + 2^-126");
+
+ // a_x = 0 leaves the product's propagated error 0 and its a = x0 a_y.
+ var px = new float3(x0, 0.0f, 0.0f);
+ var product = af_mul(px, y);
+ var terms = Math.Abs((double)product.x) + Math.Abs((double)x0 * ay);
+ Assert.True(Near(product.z, terms * u20 + MinNormal), $"af_mul({px}, {y}) = {product}: e is not (|x0 y0| + |x0 a_y|) 2^-20 + 2^-126");
+
+ var iv = DrawInterval(random);
+ var form = af_from_iv(iv);
+ var (mid, half) = (((double)iv.x + iv.y) / 2.0, ((double)iv.y - iv.x) / 2.0);
+ var expected = half + (Math.Abs(mid) + half) * u20 + MinNormal;
+ Assert.True(Math.Abs(form.z - expected) <= 1.0e-5 * (Math.Abs(mid) + half) * u20 + 1.0e-6 * half + 1.0e-12 * expected,
+ $"af_from_iv({iv}) = {form}: e is not half-width + (|mid| + half-width) 2^-20 + 2^-126 = {expected:R}");
+
+ var wide = new float3(Uniform(random, -20.0f, 20.0f), Signed(random, LogUniform(random, 1.0e-3f, 20.0f)), LogUniform(random, 1.0e-3f, 20.0f));
+ var range = af_range(wide);
+ var reach = Math.Abs((double)wide.y) + wide.z;
+ var absorption = (Math.Abs((double)wide.x) + reach) * u20;
+ var outward = ((double)range.y - range.x) / 2.0 - reach;
+ Assert.True(Math.Abs(outward - absorption) <= 0.3 * absorption, $"af_range({wide}) = {range}: endpoints are {outward:R} past x0 -+ (|a| + e), not (|x0| + |a| + e) 2^-20 = {absorption:R}");
+ }
+ }
+
+ ///
+ /// af_from_iv and af_range at the float32 extremes. Subnormal endpoints (including [0, the least
+ /// subnormal], whose halved width underflows to 0) and endpoints near the float maximum (where lo +
+ /// hi, hi - lo or the absorption would overflow) give a form whose set holds both endpoints and the
+ /// midpoint, and an af_range that holds them with no NaN endpoint. A form with an infinite or NaN
+ /// component, as an overflowed op returns, gives an af_range with no NaN endpoint.
+ ///
+ [Fact]
+ public void FromIntervalAndRangeHoldAtTheExtremes()
+ {
+ var least = BitConverter.Int32BitsToSingle(1);
+ var max = float.MaxValue;
+ var random = new System.Random(0xAF07);
+ var specials = new[] { 0.0f, least, 2 * least, 100 * least, MinNormal - least, MinNormal, 3.0f * MinNormal, 1.0e-30f, 1.0f, 1.0e20f, 1.0e30f, max / 4, max / 2, max * 0.75f, max };
+ var misses = new List();
+ void Check(float lo, float hi)
+ {
+ var form = af_from_iv(new float2(lo, hi));
+ var range = af_range(form);
+ if (float.IsNaN(form.x) || float.IsNaN(form.z) || float.IsNaN(range.x) || float.IsNaN(range.y))
+ misses.Add($"af_from_iv([{lo:R}, {hi:R}]) = {form}, af_range = {range}: NaN");
+ foreach (var value in new[] { lo, hi, (float)(((double)lo + hi) / 2.0) })
+ {
+ if (!InForm(form, 0.0f, value))
+ misses.Add($"af_from_iv([{lo:R}, {hi:R}]) = {form} misses {value:R}");
+ if (!(range.x <= value && value <= range.y))
+ misses.Add($"af_range(af_from_iv([{lo:R}, {hi:R}])) = {range} misses {value:R}");
+ }
+
+ // Tight where the answer is representable: an endpoint is no farther than 2^-18 (|lo| + |hi|)
+ // from the interval's, unless that bound passes the float maximum, where infinity is the answer.
+ var slack = Math.ScaleB(Math.Abs((double)lo) + Math.Abs((double)hi), -18) + 1.0e-37;
+ if ((double)lo - slack > -(double)max && range.x < (double)lo - slack)
+ misses.Add($"af_range(af_from_iv([{lo:R}, {hi:R}])).x = {range.x:R}, more than 2^-18 (|lo| + |hi|) under lo");
+ if ((double)hi + slack < (double)max && range.y > (double)hi + slack)
+ misses.Add($"af_range(af_from_iv([{lo:R}, {hi:R}])).y = {range.y:R}, more than 2^-18 (|lo| + |hi|) over hi");
+ }
+
+ foreach (var a in specials)
+ foreach (var b in specials)
+ {
+ Check(-a, b);
+ Check(-Math.Max(a, b), -Math.Min(a, b));
+ Check(Math.Min(a, b), Math.Max(a, b));
+ }
+
+ for (var t = 0; t < 200_000; t++)
+ {
+ var sign = random.Next(2) == 0 ? 1 : -1;
+ var lo = sign * BitConverter.Int32BitsToSingle(random.Next(0, random.Next(2) == 0 ? 1 << 20 : 0x00800000));
+ var width = BitConverter.Int32BitsToSingle(random.Next(0, random.Next(2) == 0 ? 1 << 12 : 1 << 22));
+ Check(lo, lo + width);
+ }
+
+ var odd = new[] { float.PositiveInfinity, float.NegativeInfinity, float.NaN, 0.0f, 1.0f, max };
+ foreach (var x0 in odd)
+ foreach (var a in odd)
+ foreach (var e in odd)
+ {
+ var range = af_range(new float3(x0, a, e));
+ // The range encloses x0 -+ (|a| + e) wherever that is a number, and is the whole line on the
+ // side where it is not (infinity minus infinity, a NaN component): the infinity on that side.
+ var spread = Math.Abs((double)a) + e;
+ var enclosesLow = double.IsNaN(x0 - spread) ? range.x == float.NegativeInfinity : range.x <= x0 - spread;
+ var enclosesHigh = double.IsNaN(x0 + spread) ? range.y == float.PositiveInfinity : range.y >= x0 + spread;
+ if (!enclosesLow || !enclosesHigh)
+ misses.Add($"af_range(({x0}, {a}, {e})) = {range}");
+ }
+
+ Assert.True(misses.Count == 0, $"{misses.Count} misses:" + Environment.NewLine + string.Join(Environment.NewLine, misses.Take(8)));
+ }
+
+ ///
+ /// af_snoise's width, pinned both ways. Over 6,000 seeded (centre, axis, radius) with reach R from 1e-3
+ /// to 3 (centres in [-20, 20]^3, a third out to [-1000, 1000]^3, a third of the axes and a third of the
+ /// radii 0), the form is the documented rule evaluated in double from snoise_grad: x0 = n; the centred
+ /// form when |g . axis| + |g| radius + M R^2 / 2 is under L R (checked away from that boundary), else
+ /// the Lipschitz form; e = that half-width + the float32 allowance (2^-14 + 2^-12 R + L 2^-20 (|centre|_1 + R))
+ /// plus the form's own rounding absorption (|n| + |a| + e) 2^-20; each of x0, a and e within a part in
+ /// 1e6 of it. The enclosure tests pass on an allowance or an absorption of any size on the CPU, where
+ /// float32 is exact; this is the test that sees them.
+ ///
+ [Fact]
+ public void SnoiseFormCarriesItsDocumentedWidth()
+ {
+ var u20 = Math.ScaleB(1.0, -20);
+ double lipschitz = SNOISE_LIPSCHITZ, hessian = SNOISE_HESSIAN;
+ var random = new System.Random(0xAF13);
+ var (centred, wide) = (0, 0);
+ for (var t = 0; t < 6_000; t++)
+ {
+ var spread = t % 3 == 2 ? 1000.0f : 20.0f;
+ var centre = new float3(Uniform(random, -spread, spread), Uniform(random, -spread, spread), Uniform(random, -spread, spread));
+ var axis = random.Next(3) == 0 ? new float3(0.0f, 0.0f, 0.0f) : UnitVector(random) * LogUniform(random, 1.0e-3f, 3.0f);
+ var radius = random.Next(3) == 0 ? 0.0f : LogUniform(random, 1.0e-3f, 3.0f);
+ var g = snoise_grad(centre);
+ var reach = (double)length(axis) + radius;
+ var lip = lipschitz * reach;
+ var a = (double)g.x * axis.x + (double)g.y * axis.y + (double)g.z * axis.z;
+ var remainder = Math.Sqrt((double)g.x * g.x + (double)g.y * g.y + (double)g.z * g.z) * radius + 0.5 * hessian * reach * reach;
+ var allowance = Math.ScaleB(1.0, -14) + Math.ScaleB(reach, -12)
+ + lipschitz * u20 * (Math.Abs((double)centre.x) + Math.Abs((double)centre.y) + Math.Abs((double)centre.z) + reach);
+
+ double Width(bool useCentred, out double slope)
+ {
+ slope = useCentred ? a : 0.0;
+ var e = (useCentred ? remainder : lip) + allowance;
+ return e + (Math.Abs((double)g.w) + Math.Abs(slope) + e) * u20;
+ }
+
+ var zCentred = Width(true, out var slopeCentred);
+ var zLipschitz = Width(false, out _);
+ var form = af_snoise(centre, axis, radius);
+ var observedCentred = Math.Abs(form.z - zCentred) <= Math.Abs(form.z - zLipschitz);
+ var expectedCentred = Math.Abs(a) + remainder < lip;
+ if (Math.Abs(Math.Abs(a) + remainder - lip) > 1.0e-3 * lip)
+ Assert.True(observedCentred == expectedCentred || zCentred == zLipschitz, $"af_snoise({centre}, {axis}, {radius:R}) = {form} took the {(observedCentred ? "centred" : "Lipschitz")} form; the rule takes the {(expectedCentred ? "centred" : "Lipschitz")} one (|a| + remainder = {Math.Abs(a) + remainder:R}, L R = {lip:R})");
+ var z = observedCentred ? zCentred : zLipschitz;
+ var slope = observedCentred ? slopeCentred : 0.0;
+ Assert.True(form.x == g.w, $"af_snoise({centre}, {axis}, {radius:R}).x0 = {form.x:R}, snoise = {g.w:R}");
+ Assert.True(Math.Abs(form.y - slope) <= 1.0e-5 * Math.Abs((double)length(new float3(g.x, g.y, g.z)) * length(axis)) + 1.0e-12, $"af_snoise({centre}, {axis}, {radius:R}).a = {form.y:R}, g . axis = {slope:R}");
+ Assert.True(Math.Abs(form.z - z) <= 1.0e-6 * z, $"af_snoise({centre}, {axis}, {radius:R}) = {form}: e is {form.z:R}, the documented rule gives {z:R}");
+ centred += observedCentred ? 1 : 0;
+ wide += !observedCentred ? 1 : 0;
+ }
+
+ output.WriteLine($"AF-REPORT af_snoise width: {centred} centred cases, {wide} Lipschitz cases");
+ Assert.True(centred > 1000 && wide > 1000, $"the cases do not exercise both forms: {centred} centred, {wide} Lipschitz");
+ }
+}
diff --git a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs
index f14fcda8..f0f61622 100644
--- a/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs
+++ b/packages/cultmath/tests/CultMath.Tests/GlslMirrorTests.cs
@@ -163,7 +163,7 @@ public sealed class GlslMirrorTests
}
if (want["check"] is not null)
- AssertFrustumBall(want["cases"]!.AsArray());
+ output.WriteLine($"{name}: {Families[f].Verify!(want["cases"]!.AsArray())}");
}
committed.Remove("functions");
@@ -188,8 +188,9 @@ public sealed class GlslMirrorTests
// FrustumBall applied to C#'s own results: every case's ball encloses the exact one and is no wider
// than its rounding widening allows.
- private static void AssertFrustumBall(JsonArray cases)
+ private static string AssertFrustumBall(JsonArray cases)
{
+ double low = double.PositiveInfinity, high = double.PositiveInfinity;
foreach (var entry in cases)
{
var sides = ((string)entry!).Split(" -> ");
@@ -203,7 +204,148 @@ public sealed class GlslMirrorTests
var c1 = Math.Abs(mx * zm) + Math.Abs(my * zm) + Math.Abs(zm);
Assert.True(b[3] >= reach, $"iv_frustum_ball case {entry}: radius short of the exact ball by {reach - b[3]}");
Assert.True(b[3] <= reach + Math.ScaleB(radius + c1, -19), $"iv_frustum_ball case {entry}: radius past the exact ball by {b[3] - reach}, more than 2^-19 (r + |c|_1)");
+ low = Math.Min(low, (b[3] - reach) / radius);
+ high = Math.Min(high, (reach + Math.ScaleB(radius + c1, -19) - b[3]) / Math.ScaleB(radius + c1, -19));
}
+ return $"least slack: {low:E3} of r above the exact ball, {high:F3} of 2^-19 (r + |c|_1) below its widening";
+ }
+
+ private static readonly double[] CheckEps = { -1.0, -0.5, 0.0, 0.5, 1.0 };
+
+ // The origin, the six axis directions and the eight cube corners, normalised.
+ private static readonly (double X, double Y, double Z)[] CheckDirections = CheckDirectionList().ToArray();
+
+ private static IEnumerable<(double X, double Y, double Z)> CheckDirectionList()
+ {
+ yield return (0.0, 0.0, 0.0);
+ foreach (var s in new[] { -1.0, 1.0 })
+ {
+ yield return (s, 0.0, 0.0);
+ yield return (0.0, s, 0.0);
+ yield return (0.0, 0.0, s);
+ }
+
+ var corner = 1.0 / Math.Sqrt(3.0);
+ foreach (var sx in new[] { -corner, corner })
+ foreach (var sy in new[] { -corner, corner })
+ foreach (var sz in new[] { -corner, corner })
+ yield return (sx, sy, sz);
+ }
+
+ // SampledForm applied to C#'s own results, with C#'s own snoise or fBm as the reference value. A form
+ // must enclose its reference at every sample, and be no wider than the Lipschitz form's allowance.
+ // allowance is the part of e that is the float32 allowance; a family that allowanceDecides must have a
+ // sample that falls outside the form once it is removed, so the family can tell a device whose error
+ // passes the allowance from one that does not.
+ private static string AssertSampledForm(JsonArray cases, string name, Func reference, Func widthBound,
+ Func allowance, bool allowanceDecides)
+ {
+ double least = double.PositiveInfinity, leastRelative = double.PositiveInfinity, tightest = double.PositiveInfinity;
+ var decided = 0;
+ foreach (var entry in cases)
+ {
+ var sides = ((string)entry!).Split(" -> ");
+ var tokens = sides[0].Split(' ');
+ double[] a = Floats(string.Join(' ', tokens.Take(7))), form = Floats(sides[1]);
+ double x0 = form[0], slope = form[1], e = form[2];
+ var withoutAllowance = e - allowance(tokens, a);
+ var allowanceNeeded = false;
+ foreach (var eps in CheckEps)
+ foreach (var d in CheckDirections)
+ {
+ var p = new float3((float)(a[0] + a[3] * eps + a[6] * d.X), (float)(a[1] + a[4] * eps + a[6] * d.Y), (float)(a[2] + a[5] * eps + a[6] * d.Z));
+ double value = reference(tokens, p), middle = x0 + slope * eps;
+ var inside = Math.Min(value - (middle - e), middle + e - value);
+ Assert.True(inside >= 0.0, $"{name} case {entry}: the reference {value:R} at eps {eps} and direction {d} is outside the form's range [{middle - e:R}, {middle + e:R}] by {-inside:R}");
+ least = Math.Min(least, inside);
+ leastRelative = Math.Min(leastRelative, inside / e);
+ allowanceNeeded |= Math.Abs(value - middle) > withoutAllowance;
+ }
+
+ if (allowanceNeeded)
+ decided++;
+
+ var bound = widthBound(tokens, a);
+ Assert.True(Math.Abs(slope) + e <= bound + Math.ScaleB(1.0 + bound, -16), $"{name} case {entry}: the width {Math.Abs(slope) + e:R} is past B + 2^-16 (1 + B) = {bound + Math.ScaleB(1.0 + bound, -16):R}");
+ tightest = Math.Min(tightest, (bound + Math.ScaleB(1.0 + bound, -16) - Math.Abs(slope) - e) / bound);
+ }
+
+ Assert.True(!allowanceDecides || decided > 0, $"{name}: no sample falls outside the form once the float32 allowance is removed, so the family cannot fail a device whose error passes it");
+ return $"least enclosure slack {least:E3} ({leastRelative:E3} of e), least tightness slack {tightest:E3} of B, {decided} of {cases.Count} cases need the allowance";
+ }
+
+ // The float32 allowance of one octave of af_snoise: 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R).
+ private static double SnoiseAllowance(double centre1, double reach) =>
+ Math.ScaleB(1.0, -14) + Math.ScaleB(reach, -12) + math.SNOISE_LIPSCHITZ * Math.ScaleB(centre1 + reach, -20);
+
+ // The Lipschitz form's width bound for one octave of the sampled-form check.
+ private static double SnoiseWidthBound(double centre1, double reach) => math.SNOISE_LIPSCHITZ * reach + SnoiseAllowance(centre1, reach);
+
+ private static double Length3(double[] a, int first) => Math.Sqrt(a[first] * a[first] + a[first + 1] * a[first + 1] + a[first + 2] * a[first + 2]);
+
+ private static double SnoiseOctave(Func octave, double[] a, double frequency) =>
+ octave((Math.Abs(a[0]) + Math.Abs(a[1]) + Math.Abs(a[2])) * frequency, (Length3(a, 3) + a[6]) * frequency);
+
+ // The amplitude-weighted sum of a per-octave quantity over the fBm's octaves.
+ private static double FbmOctaves(string[] t, double[] a, Func octave)
+ {
+ var (octaves, lacunarity, gain) = ((int)Convert.ToUInt32(t[7], 16), Floats(t[8])[0], Floats(t[9])[0]);
+ double sum = 0.0, amplitude = 1.0, frequency = 1.0;
+ for (var i = 0; i < Math.Clamp(octaves, 0, 16); i++)
+ {
+ sum += amplitude * SnoiseOctave(octave, a, frequency);
+ amplitude *= gain;
+ frequency *= lacunarity;
+ }
+
+ return sum;
+ }
+
+ private static string AssertSnoiseForm(JsonArray cases, bool allowanceDecides = false) =>
+ AssertSampledForm(cases, "af_snoise", (_, p) => math.snoise(p),
+ (_, a) => SnoiseOctave(SnoiseWidthBound, a, 1.0), (_, a) => SnoiseOctave(SnoiseAllowance, a, 1.0), allowanceDecides);
+
+ private static string AssertFbmForm(JsonArray cases, bool allowanceDecides = false) =>
+ AssertSampledForm(cases, "af_fbm",
+ (t, p) => math.fbm_grad(p, (int)Convert.ToUInt32(t[7], 16), (float)Floats(t[8])[0], (float)Floats(t[9])[0]).w,
+ (t, a) => FbmOctaves(t, a, SnoiseWidthBound), (t, a) => FbmOctaves(t, a, SnoiseAllowance), allowanceDecides);
+
+ // AffineFrustumBall applied to C#'s own results.
+ private static string AssertAffineFrustumBall(JsonArray cases)
+ {
+ double enclosure = double.PositiveInfinity, lower = double.PositiveInfinity, upper = double.PositiveInfinity;
+ var diagonal = new[] { (0.0, 0.0), (1.0, 0.0), (-1.0, 0.0), (0.0, 1.0), (0.0, -1.0), (Math.Sqrt(0.5), Math.Sqrt(0.5)), (Math.Sqrt(0.5), -Math.Sqrt(0.5)), (-Math.Sqrt(0.5), Math.Sqrt(0.5)), (-Math.Sqrt(0.5), -Math.Sqrt(0.5)) };
+ foreach (var entry in cases)
+ {
+ var sides = ((string)entry!).Split(" -> ");
+ var a = Floats(sides[0]);
+ var b = Floats(sides[1]);
+ double mx = a[0], my = a[1], z0 = a[2], z1 = a[3], fp = a[4], warp = a[5];
+ double zm = (z0 + z1) / 2.0, h = (z1 - z0) / 2.0;
+ var r0 = z1 * fp + warp;
+ var c1 = Math.Abs(mx * zm) + Math.Abs(my * zm) + Math.Abs(zm);
+ var spread = (Math.Abs(mx) + Math.Abs(my) + 1.0) * h;
+ double dx = b[0] - mx * zm, dy = b[1] - my * zm, dz = b[2] - zm;
+ var d = Math.Sqrt(dx * dx + dy * dy + dz * dz);
+ foreach (var z in new[] { z0, (3.0 * z0 + z1) / 4.0, zm, (z0 + 3.0 * z1) / 4.0, z1 })
+ {
+ var eps = h > 0.0 ? Math.Clamp((z - zm) / h, -1.0, 1.0) : 0.0;
+ foreach (var (ex, ey) in diagonal)
+ {
+ double px = (mx + fp * ex) * z - (b[0] + mx * h * eps), py = (my + fp * ey) * z - (b[1] + my * h * eps), pz = z - (b[2] + h * eps);
+ var slack = b[3] - (Math.Sqrt(px * px + py * py + pz * pz) + warp);
+ Assert.True(slack >= 0.0, $"af_frustum_ball case {entry}: the ray point at depth {z:R} and offset ({ex}, {ey}) is outside the ball by {-slack:R}");
+ enclosure = Math.Min(enclosure, slack / b[3]);
+ }
+ }
+
+ Assert.True(b[3] >= r0 + d, $"af_frustum_ball case {entry}: radius short of R0 + d by {r0 + d - b[3]}");
+ Assert.True(b[3] <= r0 + d + Math.ScaleB(r0 + c1 + spread, -19), $"af_frustum_ball case {entry}: radius past R0 + d by {b[3] - r0 - d}, more than 2^-19 (R0 + |c0|_1 + spread)");
+ lower = Math.Min(lower, (b[3] - r0 - d) / r0);
+ upper = Math.Min(upper, (r0 + d + Math.ScaleB(r0 + c1 + spread, -19) - b[3]) / Math.ScaleB(r0 + c1 + spread, -19));
+ }
+
+ return $"least enclosure slack {enclosure:E3} of the radius, least slack above R0 + d {lower:E3} of R0, below its widening {upper:F3} of 2^-19 (R0 + |c0|_1 + spread)";
}
// A committed case's arguments, decoded into the C# method's parameter types in Hex's field order.
@@ -249,7 +391,7 @@ public sealed class GlslMirrorTests
// phacelle's sums of exp, sin and cos cancel; Windows differs from Linux by up to 3.6e-7 of it.
private const double ScaledPlatformBound = 9.5367431640625e-7;
- private sealed record Family(string Glsl, string Tolerance, Func Arguments, string? Check = null, Platform Platform = Platform.None);
+ private sealed record Family(string Glsl, string Tolerance, Func Arguments, string? Check = null, Platform Platform = Platform.None, Func? Verify = null);
private static float Uniform(System.Random r, float lo, float hi) => lo + (hi - lo) * r.NextSingle();
private static float3 Point3(System.Random r) => new(Uniform(r, -50.0f, 50.0f), Uniform(r, -50.0f, 50.0f), Uniform(r, -50.0f, 50.0f));
@@ -291,6 +433,76 @@ public sealed class GlslMirrorTests
"and d = |GPU centre - c| (Euclidean); every case must have r + d <= GPU radius <= r + d + 2^-19 (r + |c|_1). " +
"Report the largest ulp distance per component as for any ulp-bounded family; only the two bounds fail the check.";
+ // An affine form (x0, a, e): e >= 0, spanning the widths a probe's forms take.
+ private static float3 Form(System.Random r) => new(Uniform(r, -20.0f, 20.0f), Uniform(r, -5.0f, 5.0f), MathF.Pow(10.0f, Uniform(r, -4.0f, 1.0f)));
+
+ // A slice's axis and radius in noise space, log-uniform from 1e-3 to 0.5: below about 0.15 the
+ // centred form of af_snoise wins, above it the Lipschitz form does, so both are drawn.
+ private static float3 Axis3(System.Random r)
+ {
+ var scale = MathF.Pow(10.0f, Uniform(r, -3.0f, -0.3f));
+ return new float3(Uniform(r, -1.0f, 1.0f) * scale, Uniform(r, -1.0f, 1.0f) * scale, Uniform(r, -1.0f, 1.0f) * scale);
+ }
+
+ private static float BallRadius(System.Random r) => MathF.Pow(10.0f, Uniform(r, -3.0f, -0.3f));
+
+ // A slice of reach 1e-6 to 1e-3, the short slices and small footprints near a camera, where the float32
+ // allowance is most of the form's width: the centre in [-50, 50] or [-1, 1], an axis of random direction
+ // (zero in one case of four) and a radius, each log-uniform in 1e-6 to 1e-3.
+ private static object[] SmallReachSlice(System.Random r)
+ {
+ var span = r.Next(2) == 0 ? 50.0f : 1.0f;
+ var centre = new float3(Uniform(r, -span, span), Uniform(r, -span, span), Uniform(r, -span, span));
+ var axis = new float3(0.0f, 0.0f, 0.0f);
+ if (r.Next(4) != 0)
+ {
+ var direction = math.normalize(new float3(Uniform(r, -1.0f, 1.0f), Uniform(r, -1.0f, 1.0f), Uniform(r, -1.0f, 1.0f)));
+ axis = direction * MathF.Pow(10.0f, Uniform(r, -6.0f, -3.0f));
+ }
+
+ return new object[] { centre, axis, MathF.Pow(10.0f, Uniform(r, -6.0f, -3.0f)) };
+ }
+
+ private const string SampledForm =
+ "the arguments are (cx, cy, cz, ax, ay, az, radius, ...) and the result is the form (x0, a, e). Enclosure: for eps in " +
+ "{-1, -0.5, 0, 0.5, 1} and d in {0, +-ex, +-ey, +-ez, (+-1, +-1, +-1) / sqrt(3)} (15 directions), form the point " +
+ "p = c + axis eps + radius d in double and round it to float32; the device's own reference value at p must lie in " +
+ "[x0 + a eps - e, x0 + a eps + e] with no tolerance, so a device whose gradient error exceeds the allowance fails. " +
+ "Tightness: with L = 7.9640074 and, for each octave (one for af_snoise), R = |axis| + radius, " +
+ "B = L R + 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R), the width |a| + e must be at most B + 2^-16 (1 + B). " +
+ "Report the least slack of each side, absolutely and as a fraction of e; only the two bounds fail the check. ";
+
+ private const string SnoiseForm = SampledForm + "The reference value is cultmath_snoise(p).";
+
+ private const string FbmForm = SampledForm +
+ "The reference value is cultmath_fbm_grad(p, octaves, lacunarity, gain).w, and B is the sum over octaves i of gain^i B_i, " +
+ "where B_i is B for the centre lacunarity^i c, the axis lacunarity^i axis and the radius lacunarity^i radius.";
+
+ // The two small-reach families add the centre leg to every af_snoise and af_fbm family. The device's
+ // reference value is its own noise, so a device whose noise is wrong everywhere encloses its own wrong
+ // values; C#'s value at the centre, the form's own x0 in the fixture, is the independent reading.
+ private const string CentreLeg =
+ " Centre leg, for every cultmath_af_snoise and cultmath_af_fbm family of this fixture, the earlier ones included: " +
+ "the fixture's own x0 in the result (C#'s value at the centre) must lie in [x0 - e, x0 + e] of the GPU's form, with " +
+ "no tolerance, so a device whose noise differs from C#'s by more than its e fails.";
+
+ private const string SmallReach =
+ " These cases have reach |axis| + radius of 1e-6 to 1e-3, where the float32 allowance is most of e and the second order " +
+ "remainder is not; the enclosure above fails a device whose gradient error exceeds the allowance.";
+
+ private const string SnoiseSmallForm = SnoiseForm + SmallReach + CentreLeg;
+
+ private const string FbmSmallForm = FbmForm + SmallReach + CentreLeg;
+
+ private const string AffineFrustumBall =
+ "enclosure and tightness: from the arguments (mx, my, z0, z1, fp, warpVariation) compute in double zm = (z0 + z1) / 2, " +
+ "h = (z1 - z0) / 2, axis = (mx h, my h, h), c0 = (mx zm, my zm, zm), |c0|_1 = |mx zm| + |my zm| + |zm|, R0 = z1 fp + warpVariation, " +
+ "spread = (|mx| + |my| + 1) h and d = |GPU centre - c0|. Enclosure: for z in {z0, (3 z0 + z1) / 4, zm, (z0 + 3 z1) / 4, z1}, " +
+ "eps = clamp((z - zm) / h, -1, 1) and the nine footprint offsets e in {(0, 0), (+-1, 0), (0, +-1), (+-1, +-1) / sqrt(2)}, " +
+ "the point P = ((mx + fp e.x) z, (my + fp e.y) z, z) satisfies |P - (GPU centre + axis eps)| + warpVariation <= GPU radius. " +
+ "Tightness: R0 + d <= GPU radius <= R0 + d + 2^-19 (R0 + |c0|_1 + spread). " +
+ "Report the least slack of each side; only the bounds fail the check.";
+
// A Phacelle stripe wave vector: each component in [-6, 6], about one stripe per cell.
private static float3 Side(System.Random r) => new(Uniform(r, -6.0f, 6.0f), Uniform(r, -6.0f, 6.0f), Uniform(r, -6.0f, 6.0f));
@@ -331,12 +543,38 @@ public sealed class GlslMirrorTests
var slope = new float2(Uniform(r, -1.0f, 1.0f), Uniform(r, -1.0f, 1.0f));
var z0 = Uniform(r, 0.1f, 100.0f);
return new object[] { slope, z0, z0 + Uniform(r, 0.01f, 50.0f), Uniform(r, 0.0001f, 0.05f), Uniform(r, 0.0f, 2.0f) };
- }, FrustumBall),
+ }, FrustumBall, Verify: AssertFrustumBall),
new("vec2 cultmath_iv_exp(vec2)", "ulp-bounded, platform exp", r => new object[] { Interval(r) }, Platform: Platform.Ulp),
new("CultPhasor cultmath_phacelle(vec3, vec3, float, float)", "ulp-bounded, platform exp, sin, cos; across platforms |diff| <= 2^-20 max(|v|, 1)",
r => new object[] { Point3(r), Side(r), Uniform(r, 0.0f, 1.0f), 0.5f }, Platform: Platform.Scaled),
new("float cultmath_snoise(vec3)", "ulp-bounded, on the simplex tie set", r => new object[] { TiePoint3(r) }),
new("vec4 cultmath_snoise_grad(vec3)", "ulp-bounded, on the simplex tie set", r => new object[] { TiePoint3(r) }),
+ new("vec3 cultmath_af_point(float)", "ulp-bounded", r => new object[] { Uniform(r, -20.0f, 20.0f) }),
+ new("vec3 cultmath_af_symbol(float, float)", "ulp-bounded", r => new object[] { Uniform(r, -20.0f, 20.0f), Uniform(r, -5.0f, 5.0f) }),
+ new("vec3 cultmath_af_from_iv(vec2)", "ulp-bounded", r => new object[] { Interval(r) }),
+ new("vec2 cultmath_af_range(vec3)", "ulp-bounded", r => new object[] { Form(r) }),
+ new("vec3 cultmath_af_add(vec3, vec3)", "ulp-bounded", r => new object[] { Form(r), Form(r) }),
+ new("vec3 cultmath_af_sub(vec3, vec3)", "ulp-bounded", r => new object[] { Form(r), Form(r) }),
+ new("vec3 cultmath_af_neg(vec3)", "ulp-bounded", r => new object[] { Form(r) }),
+ new("vec3 cultmath_af_scale(vec3, float)", "ulp-bounded", r => new object[] { Form(r), Uniform(r, -4.0f, 4.0f) }),
+ new("vec3 cultmath_af_add_iv(vec3, vec2)", "ulp-bounded", r => new object[] { Form(r), Interval(r) }),
+ new("vec3 cultmath_af_mul(vec3, vec3)", "ulp-bounded", r => new object[] { Form(r), Form(r) }),
+ new("vec3 cultmath_af_snoise(vec3, vec3, float)", "ulp-bounded", r => new object[] { Point3(r), Axis3(r), BallRadius(r) }, SnoiseForm, Verify: cases => AssertSnoiseForm(cases)),
+ new("vec3 cultmath_af_fbm(vec3, vec3, float, int, float, float)", "ulp-bounded", r => new object[] { Point3(r), Axis3(r), BallRadius(r), 4, 2.0f, 0.5f }, FbmForm, Verify: cases => AssertFbmForm(cases)),
+ new("vec3 cultmath_af_frustum_axis(vec2, float, float)", "ulp-bounded", r =>
+ {
+ var z0 = Uniform(r, 0.1f, 100.0f);
+ return new object[] { new float2(Uniform(r, -1.0f, 1.0f), Uniform(r, -1.0f, 1.0f)), z0, z0 + Uniform(r, 0.01f, 50.0f) };
+ }),
+ new("vec4 cultmath_af_frustum_ball(vec2, float, float, float, float)", "ulp-bounded", r =>
+ {
+ var slope = new float2(Uniform(r, -1.0f, 1.0f), Uniform(r, -1.0f, 1.0f));
+ var z0 = Uniform(r, 0.1f, 100.0f);
+ return new object[] { slope, z0, z0 + Uniform(r, 0.01f, 50.0f), Uniform(r, 0.0001f, 0.05f), Uniform(r, 0.0f, 2.0f) };
+ }, AffineFrustumBall, Verify: AssertAffineFrustumBall),
+ new("vec2 cultmath_iv_snoise_ball(vec2, float)", "ulp-bounded", r => new object[] { new float2(Uniform(r, -50.0f, 50.0f), Uniform(r, -50.0f, 50.0f)), Uniform(r, 0.001f, 2.0f) }),
+ new("vec3 cultmath_af_snoise(vec3, vec3, float)", "ulp-bounded, reach 1e-6 to 1e-3", SmallReachSlice, SnoiseSmallForm, Verify: cases => AssertSnoiseForm(cases, allowanceDecides: true)),
+ new("vec3 cultmath_af_fbm(vec3, vec3, float, int, float, float)", "ulp-bounded, reach 1e-6 to 1e-3", r => SmallReachSlice(r).Concat(new object[] { 4, 2.0f, 0.5f }).ToArray(), FbmSmallForm, Verify: cases => AssertFbmForm(cases, allowanceDecides: true)),
};
// The fixture text, each case's arguments given by family and point index.
diff --git a/packages/cultmath/tests/CultMath.Tests/HlslMirrorTests.cs b/packages/cultmath/tests/CultMath.Tests/HlslMirrorTests.cs
index 9e2dc9af..00a2e90a 100644
--- a/packages/cultmath/tests/CultMath.Tests/HlslMirrorTests.cs
+++ b/packages/cultmath/tests/CultMath.Tests/HlslMirrorTests.cs
@@ -66,6 +66,7 @@ public sealed class HlslMirrorTests
[InlineData("CultMath.hlsl")]
[InlineData("CultMath.Phacelle.hlsl")]
[InlineData("CultMath.Interval.hlsl")]
+ [InlineData("CultMath.Affine.hlsl")]
public void UnityPackageShaderIsIdenticalToTheCanonicalShader(string name)
{
var root = GetCultMathRoot();
diff --git a/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs b/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs
index ce38dea4..cba99817 100644
--- a/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs
+++ b/packages/cultmath/tests/CultMath.Tests/HlslSourceCompatibilityTests.cs
@@ -33,6 +33,10 @@ public sealed class HlslSourceCompatibilityTests
Assert.NotNull(ShaderFunction(shader, "cultmath_phacelle", typeof(float3), typeof(float3), typeof(float), typeof(float)));
Assert.NotNull(ShaderFunction(shader, "cultmath_iv_snoise_ball", typeof(float3), typeof(float)));
Assert.NotNull(ShaderFunction(shader, "cultmath_iv_fbm_ball", typeof(float3), typeof(float), typeof(int), typeof(float), typeof(float)));
+ Assert.NotNull(ShaderFunction(shader, "cultmath_iv_snoise_ball", typeof(float2), typeof(float)));
+ Assert.NotNull(ShaderFunction(shader, "cultmath_af_snoise", typeof(float3), typeof(float3), typeof(float)));
+ Assert.NotNull(ShaderFunction(shader, "cultmath_af_fbm", typeof(float3), typeof(float3), typeof(float), typeof(int), typeof(float), typeof(float)));
+ Assert.NotNull(ShaderFunction(shader, "cultmath_af_frustum_ball", typeof(float2), typeof(float), typeof(float), typeof(float), typeof(float)));
}
// HLSL functions carry no access modifier, so they compile as private instance methods.
@@ -133,7 +137,7 @@ public sealed class HlslSourceCompatibilityTests
}
Assert.True(mismatches.Count == 0, $"{mismatches.Count} mismatches:{Environment.NewLine}{string.Join(Environment.NewLine, mismatches.Take(12))}");
- Assert.Equal(53, compared.Count);
+ Assert.Equal(67, compared.Count);
}
///
@@ -165,6 +169,81 @@ public sealed class HlslSourceCompatibilityTests
}
}
+ ///
+ /// The generic comparison draws centre, axis and radius from [-100, 100], where the reach is far past the
+ /// 0.15 or so below which cultmath_af_snoise's centred form is the narrower one, so an HLSL edit
+ /// of the choice between the centred and the Lipschitz form (a threshold, a reordered sum) survives it.
+ /// This sweep draws realistic slices (axis and radius log-uniform in 1e-3 to 0.5, the reach of a tile
+ /// near a camera), which land on both sides of the choice and next to it, for cultmath_af_snoise
+ /// and cultmath_af_fbm.
+ ///
+ [Fact]
+ public void AffineSnoiseMirrorMatchesCSharpBitForBitOnBothSidesOfItsBranch()
+ {
+ var (assembly, errors) = CompileShaderMirror();
+ Assert.True(assembly is not null, string.Join(Environment.NewLine, errors));
+ var shaderType = assembly!.GetType("CultMathHlsl.HlslShader")!;
+ var shader = Activator.CreateInstance(shaderType);
+ var snoiseMirror = ShaderFunction(shaderType, "cultmath_af_snoise", typeof(float3), typeof(float3), typeof(float))!;
+ var fbmMirror = ShaderFunction(shaderType, "cultmath_af_fbm", typeof(float3), typeof(float3), typeof(float), typeof(int), typeof(float), typeof(float))!;
+
+ var random = new System.Random(0x5EED3);
+ float Next(float extent) => (random.NextSingle() * 2.0f - 1.0f) * extent;
+ float Reach() => 1.0e-3f * MathF.Pow(500.0f, random.NextSingle());
+ int centred = 0, lipschitz = 0;
+ for (var i = 0; i < 20000; i++)
+ {
+ var centre = new float3(Next(50.0f), Next(50.0f), Next(50.0f));
+ var axis = normalize(new float3(Next(1.0f), Next(1.0f), Next(1.0f))) * Reach();
+ var radius = Reach();
+ var expected = af_snoise(centre, axis, radius);
+ var actual = Values(snoiseMirror.Invoke(shader, new object[] { centre, axis, radius })!);
+ Assert.True(BitwiseEqual(Values(expected), actual), $"cultmath_af_snoise differs from C# at centre = {centre}, axis = {axis}, radius = {radius}");
+ if (expected.y != 0.0f)
+ centred++;
+ else
+ lipschitz++;
+
+ if (i % 8 == 0)
+ {
+ var fbmExpected = Values(af_fbm(centre, axis, radius, 4, 2.0f, 0.5f));
+ var fbmActual = Values(fbmMirror.Invoke(shader, new object[] { centre, axis, radius, 4, 2.0f, 0.5f })!);
+ Assert.True(BitwiseEqual(fbmExpected, fbmActual), $"cultmath_af_fbm differs from C# at centre = {centre}, axis = {axis}, radius = {radius}");
+ }
+ }
+
+ Assert.True(centred > 2000 && lipschitz > 2000, $"the sweep meets one branch too rarely: centred {centred}, Lipschitz {lipschitz} of 20000");
+ }
+
+ ///
+ /// The generic comparison stops at 1e7, so an HLSL edit of cultmath_af_range's NaN test that
+ /// misreads the finite values near the float maximum (or an overflowed endpoint) survives it. Forms
+ /// from zero to the float maximum, infinite and NaN components, both signs, in every slot: the mirror
+ /// returns C#'s bits, and neither endpoint is ever NaN.
+ ///
+ [Fact]
+ public void AffineRangeMirrorMatchesCSharpBitForBitAtTheFloatExtremes()
+ {
+ var (assembly, errors) = CompileShaderMirror();
+ Assert.True(assembly is not null, string.Join(Environment.NewLine, errors));
+ var shaderType = assembly!.GetType("CultMathHlsl.HlslShader")!;
+ var shader = Activator.CreateInstance(shaderType);
+ var mirror = ShaderFunction(shaderType, "cultmath_af_range", typeof(float3))!;
+
+ var magnitudes = new[] { 0.0f, 1.0f, 1.0e30f, 1.0e38f, float.MaxValue / 2.0f, float.MaxValue, float.PositiveInfinity, float.NaN };
+ var values = magnitudes.Concat(magnitudes.Where(m => !float.IsNaN(m)).Select(m => -m)).ToArray();
+ foreach (var x0 in values)
+ foreach (var a in values)
+ foreach (var e in values)
+ {
+ var form = new float3(x0, a, e);
+ var expected = af_range(form);
+ var actual = Values(mirror.Invoke(shader, new object[] { form })!);
+ Assert.True(BitwiseEqual(Values(expected), actual), $"cultmath_af_range differs from C# at {form}");
+ Assert.False(float.IsNaN(expected.x) || float.IsNaN(expected.y), $"af_range({form}) is {expected}, a NaN endpoint");
+ }
+ }
+
///
/// The dense sweep almost never meets a cell whose box bound is just under the 2.25 cut and whose
/// weight is still nonzero: a mirror cut of 2.245, 2.24 or 2.2 survives it. These points sit next
diff --git a/packages/cultmath/tests/CultMath.Tests/NoiseBoundTests.cs b/packages/cultmath/tests/CultMath.Tests/NoiseBoundTests.cs
index b79eda0a..78a3b795 100644
--- a/packages/cultmath/tests/CultMath.Tests/NoiseBoundTests.cs
+++ b/packages/cultmath/tests/CultMath.Tests/NoiseBoundTests.cs
@@ -5,9 +5,9 @@ using static CultMath.math;
namespace CultMath.Tests;
///
-/// The noise bounds (design.md, "Intervals"): iv_snoise_ball and iv_fbm_ball enclose their functions over
-/// a ball, a domain warp bounded by D is enclosed by enlarging the radius by D, SNOISE_LIPSCHITZ has
-/// measured provenance, iv_frustum_ball encloses a screen tile's rays over a depth segment, the bound
+/// The noise bounds (design.md, "Intervals" and "Affine forms"): iv_snoise_ball and iv_fbm_ball enclose
+/// their functions over a ball, a domain warp bounded by D is enclosed by enlarging the radius by D, or
+/// by the centred warp, SNOISE_LIPSCHITZ, SNOISE2_LIPSCHITZ and SNOISE_HESSIAN have measured provenance, iv_frustum_ball encloses a screen tile's rays over a depth segment, the bound
/// composed from an analytic envelope and the noise ball encloses the density, and a tile march over
/// fields with authored empty space is measured against a dense one for the same transmittance. Lines
/// starting IV-REPORT carry the numbers the cut report quotes.
@@ -121,7 +121,7 @@ public sealed class NoiseBoundTests
// One tile case of TileBallEnclosesEveryRaySegment: the r2 domain, or one of the extreme families
// where float32 rounding of the centre is largest against the radius (Soul's verdict s1).
- private static (int N, float Focal, float2 Slope, float Z0, float Z1, float Warp) DrawBallCase(System.Random random, string family)
+ internal static (int N, float Focal, float2 Slope, float Z0, float Z1, float Warp) DrawBallCase(System.Random random, string family)
{
int[] sizes = { 1, 4, 8, 16 };
float[] depths = { 12.0f, 1000.0f, 2400.0f };
@@ -251,10 +251,11 @@ public sealed class NoiseBoundTests
///
/// intervals-enclose for the composition the site and Aetheria use: over 2,000 seeded tile slices
- /// (Aetheria's wells, inside the fog, the void at every grid point, the shipped void and LOD-far;
- /// N in {1, 4, 8, 16}; a camera drawn per tile) the bound composed from the envelope over the slice's
- /// box, its fade, and the noise ball enlarged by the warp encloses the density at 64 points of the
- /// slice, each sampled through the field's own warp, with no tolerance. The void's footprint-truncated density (octave weights) is checked
+ /// (the deep well, the shallow wells and inside the fog, each under the centred-warp interval bound
+ /// and the affine bound; the void at every grid point, the shipped void and LOD-far; N in
+ /// {1, 4, 8, 16}; a camera drawn per tile) the bound composed from the envelope over the slice's box,
+ /// its fade, and the noise enclosure encloses the density at 64 points of the slice, each sampled
+ /// through the field's own warp, with no tolerance. The void's footprint-truncated density (octave weights) is checked
/// against the same bound; a quarter of the slices are LOD-far's, where the weights are strictly
/// between 0 and 1 and at 0, and the test asserts it sampled both.
///
@@ -263,7 +264,15 @@ public sealed class NoiseBoundTests
{
var random = new System.Random(0xE7B0);
int[] sizes = { 1, 4, 8, 16 };
- var fields = new List { FogField.Wells(FogField.AetheriaWarp), FogField.InsideFog(FogField.AetheriaWarp) };
+ var fog = new List();
+ foreach (var mode in new[] { BoundMode.Interval, BoundMode.Affine })
+ {
+ fog.Add(FogField.DeepWell(FogField.AetheriaWarp, mode));
+ fog.Add(FogField.Wells(FogField.AetheriaWarp, mode));
+ fog.Add(FogField.InsideFog(FogField.AetheriaWarp, mode));
+ }
+
+ var fields = new List();
foreach (var rh in VoidField.HollowRadii)
foreach (var offset in VoidField.CameraOffsets)
foreach (var ramp in VoidField.Ramps)
@@ -274,7 +283,7 @@ public sealed class NoiseBoundTests
var (partial, zero) = (0, 0);
for (var t = 0; t < 2000; t++)
{
- var field = t % 2 == 0 ? fields[(t / 2) % 2] : t % 4 == 1 ? fields[^1] : fields[2 + random.Next(fields.Count - 2)];
+ var field = t % 2 == 0 ? fog[(t / 2) % fog.Count] : t % 4 == 1 ? fields[^1] : fields[random.Next(fields.Count)];
var tile = field.DrawTile(random, sizes[random.Next(sizes.Length)]);
var near = field.Grid[0];
var far = field.Grid[^1];
@@ -474,6 +483,714 @@ public sealed class NoiseBoundTests
Assert.True(MathF.Abs(ratio - 1.0f) <= 0.005f, $"SNOISE_LIPSCHITZ is {ratio:R} times 1.10 x the re-measured {refined:R}; re-run MeasureLipschitz and re-pin");
}
+ // ---- The curvature and 2D Lipschitz constants (math.Affine.cs, math.Interval.cs) ----
+
+ // Central differences over exact float32 steps: the step actually taken is (p + h) - p in float32, so
+ // the quotient is not skewed by the rounding of p + h far from the origin.
+ private static double Step(float x, float h, out double back) { back = x - (double)(x - h); return (x + h) - (double)x; }
+
+ // The spectral norm (largest absolute eigenvalue) of the symmetrised Hessian of snoise(float3) at p,
+ // from central differences of snoise_grad at h = 1e-3.
+ private static double HessianNorm(float3 p)
+ {
+ const float h = 1.0e-3f;
+ var m = new double[3, 3];
+ for (var a = 0; a < 3; a++)
+ {
+ var e = new float3(a == 0 ? h : 0.0f, a == 1 ? h : 0.0f, a == 2 ? h : 0.0f);
+ var forward = Step(a == 0 ? p.x : a == 1 ? p.y : p.z, h, out var back);
+ var gp = snoise_grad(p + e);
+ var gm = snoise_grad(p - e);
+ m[0, a] = (gp.x - (double)gm.x) / (forward + back);
+ m[1, a] = (gp.y - (double)gm.y) / (forward + back);
+ m[2, a] = (gp.z - (double)gm.z) / (forward + back);
+ }
+
+ var (a00, a11, a22) = (m[0, 0], m[1, 1], m[2, 2]);
+ var (a01, a02, a12) = ((m[0, 1] + m[1, 0]) / 2, (m[0, 2] + m[2, 0]) / 2, (m[1, 2] + m[2, 1]) / 2);
+ var p1 = a01 * a01 + a02 * a02 + a12 * a12;
+ if (p1 == 0.0)
+ return Math.Max(Math.Abs(a00), Math.Max(Math.Abs(a11), Math.Abs(a22)));
+ var q = (a00 + a11 + a22) / 3;
+ var p2 = (a00 - q) * (a00 - q) + (a11 - q) * (a11 - q) + (a22 - q) * (a22 - q) + 2 * p1;
+ var s = Math.Sqrt(p2 / 6);
+ var (b00, b11, b22, b01, b02, b12) = ((a00 - q) / s, (a11 - q) / s, (a22 - q) / s, a01 / s, a02 / s, a12 / s);
+ var r = Math.Clamp((b00 * (b11 * b22 - b12 * b12) - b01 * (b01 * b22 - b12 * b02) + b02 * (b01 * b12 - b11 * b02)) / 2, -1.0, 1.0);
+ var phi = Math.Acos(r) / 3;
+ var largest = q + 2 * s * Math.Cos(phi);
+ var smallest = q + 2 * s * Math.Cos(phi + 2 * Math.PI / 3);
+ return Math.Max(Math.Abs(largest), Math.Abs(smallest));
+ }
+
+ // The gradient length of snoise(float2) at p, from central differences at h = 1e-3.
+ private static double Gradient2Norm(float2 p)
+ {
+ const float h = 1.0e-3f;
+ var fx = Step(p.x, h, out var bx);
+ var fy = Step(p.y, h, out var by);
+ var gx = (snoise(p + new float2(h, 0.0f)) - (double)snoise(p - new float2(h, 0.0f))) / (fx + bx);
+ var gy = (snoise(p + new float2(0.0f, h)) - (double)snoise(p - new float2(0.0f, h))) / (fy + by);
+ return Math.Sqrt(gx * gx + gy * gy);
+ }
+
+ // Hill-climbs f from p as AscendGradientNorm does: the ascent direction is f's central difference,
+ // the step grows on success and halves on failure. Returns the largest value reached.
+ private static double Ascend(Func f, float3 p) => AscendPoint(f, p).Best;
+
+ private static (double Best, float3 At) AscendPoint(Func f, float3 p)
+ {
+ const float h = 1.0e-3f;
+ var step = 1.0e-2f;
+ var best = f(p);
+ for (var k = 0; k < 200 && step > 1.0e-6f; k++)
+ {
+ var d = new float3(
+ (float)(f(p + new float3(h, 0.0f, 0.0f)) - f(p - new float3(h, 0.0f, 0.0f))),
+ (float)(f(p + new float3(0.0f, h, 0.0f)) - f(p - new float3(0.0f, h, 0.0f))),
+ (float)(f(p + new float3(0.0f, 0.0f, h)) - f(p - new float3(0.0f, 0.0f, h))));
+ if (dot(d, d) == 0.0f)
+ break;
+ var q = p + normalize(d) * step;
+ var value = f(q);
+ if (value > best)
+ {
+ p = q;
+ best = value;
+ step *= 1.5f;
+ }
+ else
+ {
+ step *= 0.5f;
+ }
+ }
+
+ return (best, p);
+ }
+
+ private static double Ascend2(Func f, float2 p) => Ascend(q => f(new float2(q.x, q.y)), new float3(p.x, p.y, 0.0f));
+
+ // The largest f over `samples` seeded points of [-256, 256]^dims, the largest after refining the
+ // `refine` largest by ascent, and the start whose ascent reached it (the witness).
+ private static (double Sampled, double Refined, float3 Witness) MeasureMax(Func f, bool planar, int seed, int samples, int refine)
+ {
+ var random = new System.Random(seed);
+ var points = new float3[samples];
+ var values = new double[samples];
+ for (var i = 0; i < samples; i++)
+ {
+ points[i] = new float3(Uniform(random, -256.0f, 256.0f), Uniform(random, -256.0f, 256.0f), planar ? 0.0f : Uniform(random, -256.0f, 256.0f));
+ values[i] = f(points[i]);
+ }
+
+ var order = Enumerable.Range(0, samples).OrderByDescending(i => values[i]).Take(Math.Max(refine, 1)).ToArray();
+ var refined = values[order[0]];
+ var witness = points[order[0]];
+ foreach (var i in order.Take(refine))
+ {
+ var value = planar ? Ascend2(q => f(new float3(q.x, q.y, 0.0f)), new float2(points[i].x, points[i].y)) : Ascend(f, points[i]);
+ if (value > refined)
+ {
+ refined = value;
+ witness = points[i];
+ }
+ }
+
+ return (values[order[0]], refined, witness);
+ }
+
+ private static double Gradient2At(float3 p) => Gradient2Norm(new float2(p.x, p.y));
+
+ ///
+ /// The provenance of SNOISE_HESSIAN: the largest spectral norm of snoise's Hessian (HessianNorm) over
+ /// 1e6 seeded points of [-256, 256]^3, the 1e4 largest refined by ascent, times 1.10. Prints the
+ /// start whose ascent reached the maximum, which HessianConstantPinsSampledCurvature climbs from
+ /// again. Slow; run explicitly after any change to the snoise kernel and re-pin the constant and the
+ /// witness.
+ ///
+ [Fact(Explicit = true)]
+ [Trait("Category", "Slow")]
+ public void MeasureHessian()
+ {
+ var (sampled, refined, witness) = MeasureMax(HessianNorm, false, 0x4E55, 1_000_000, 10_000);
+ output.WriteLine($"IV-REPORT hessian: max |H| sampled {sampled:R}, refined {refined:R}, x 1.10 = {(float)(refined * 1.10):R}, witness ({witness.x:R}, {witness.y:R}, {witness.z:R})");
+ Assert.True(refined <= SNOISE_HESSIAN, $"measured {refined:R} exceeds SNOISE_HESSIAN {SNOISE_HESSIAN:R}");
+ }
+
+ // The start MeasureHessian printed as its witness.
+ private static readonly float3 HessianWitness = new(-245.19885f, -53.01323f, -91.47363f);
+
+ ///
+ /// Pins SNOISE_HESSIAN: no Hessian norm over 1e5 seeded points exceeds it, and the ascent from
+ /// MeasureHessian's witness reaches a maximum that, times 1.10, is the constant to within half a
+ /// percent, so a constant moved by 1% fails here.
+ ///
+ [Fact]
+ public void HessianConstantPinsSampledCurvature()
+ {
+ var (sampled, _, _) = MeasureMax(HessianNorm, false, 0x4E56, 100_000, 0);
+ Assert.True(sampled <= SNOISE_HESSIAN, $"the Hessian norm reaches {sampled:R}, above SNOISE_HESSIAN {SNOISE_HESSIAN:R}");
+ var refined = Ascend(HessianNorm, HessianWitness);
+ Assert.True(refined <= SNOISE_HESSIAN, $"the Hessian norm reaches {refined:R}, above SNOISE_HESSIAN {SNOISE_HESSIAN:R}");
+ var ratio = SNOISE_HESSIAN / (1.10 * refined);
+ Assert.True(Math.Abs(ratio - 1.0) <= 0.005, $"SNOISE_HESSIAN is {ratio:R} times 1.10 x the re-measured {refined:R}; re-run MeasureHessian and re-pin");
+ }
+
+ ///
+ /// SNOISE_HESSIAN where the curvature is realised. At the point the ascent from MeasureHessian's witness
+ /// reaches, the absolute second difference of snoise along 4,000 seeded directions u at step 0.05 has a
+ /// largest value within 10% of SNOISE_HESSIAN / 1.10 (the realised curvature is there, so the check
+ /// has teeth), and af_snoise(witness, r u, 0) encloses snoise(witness + eps r u) at eps in
+ /// {-1, -1/2, 0, 1/2, 1} for r in {0.1, 0.3} and every one of those directions, no tolerance: a constant
+ /// under the realised curvature (40 against about 50.6) misses on the directions near the top
+ /// eigenvector. The enclosure tests on random balls cannot see a constant 20% low; this and
+ /// HessianConstantPinsSampledCurvature are its defence.
+ ///
+ [Fact]
+ public void SnoiseFormEnclosesTheCurvatureWitness()
+ {
+ var (_, witness) = AscendPoint(HessianNorm, HessianWitness);
+ var random = new System.Random(0xCA7E);
+ var directions = Enumerable.Range(0, 4000).Select(_ => UnitVector(random)).ToArray();
+ const float step = 0.05f;
+ var centreValue = snoise(witness);
+ var realised = directions.Max(u => Math.Abs(snoise(witness + u * step) + (double)snoise(witness - u * step) - 2.0 * centreValue) / ((double)step * step));
+ output.WriteLine($"IV-REPORT curvature witness ({witness.x:R}, {witness.y:R}, {witness.z:R}): largest second difference {realised:R} against SNOISE_HESSIAN {SNOISE_HESSIAN:R}");
+ Assert.True(realised >= 0.9 * SNOISE_HESSIAN / 1.10, $"the largest second difference at the witness is {realised:R}, under 0.9 SNOISE_HESSIAN / 1.10 = {0.9 * SNOISE_HESSIAN / 1.10:R}: the check has no teeth, or the constant moved");
+ foreach (var u in directions)
+ foreach (var r in new[] { 0.1f, 0.3f })
+ {
+ var form = af_snoise(witness, u * r, 0.0f);
+ foreach (var eps in new[] { -1.0f, -0.5f, 0.0f, 0.5f, 1.0f })
+ {
+ var value = snoise(witness + u * (r * eps));
+ Assert.True(Math.Abs(value - (form.x + (double)form.y * eps)) <= form.z, $"af_snoise(witness, {u * r}, 0) = {form} misses snoise = {value:R} at eps {eps:R}, direction {u}");
+ }
+ }
+ }
+
+ ///
+ /// The provenance of SNOISE2_LIPSCHITZ: the largest gradient length of snoise(float2) (Gradient2Norm)
+ /// over 1e6 seeded points of [-256, 256]^2, the 1e4 largest refined by ascent, times 1.10; and the
+ /// largest |snoise(float2)| reached by ascent from 1e4 starts, which is what lets iv_snoise_ball(float2)
+ /// intersect with [-1, 1]. Slow; run explicitly after any change to the 2D kernel and re-pin.
+ ///
+ [Fact(Explicit = true)]
+ [Trait("Category", "Slow")]
+ public void MeasureLipschitz2()
+ {
+ var (sampled, refined, witness) = MeasureMax(Gradient2At, true, 0x2D15, 1_000_000, 10_000);
+ var random = new System.Random(0x2D16);
+ var maxValue = Enumerable.Range(0, 10_000)
+ .Select(_ => new float2(Uniform(random, -256.0f, 256.0f), Uniform(random, -256.0f, 256.0f)))
+ .Max(p => Ascend2(q => Math.Abs(snoise(q)), p));
+ output.WriteLine($"IV-REPORT lipschitz2: max |grad snoise2| sampled {sampled:R}, refined {refined:R}, x 1.10 = {(float)(refined * 1.10):R}, witness ({witness.x:R}, {witness.y:R}); max |snoise2| refined {maxValue:R}");
+ Assert.True(refined <= SNOISE2_LIPSCHITZ, $"measured {refined:R} exceeds SNOISE2_LIPSCHITZ {SNOISE2_LIPSCHITZ:R}");
+ Assert.True(maxValue < 1.0, $"|snoise2| reaches {maxValue:R}; iv_snoise_ball(float2) may not intersect with [-1, 1]");
+ }
+
+ // The start MeasureLipschitz2 printed as its witness.
+ private static readonly float2 Lipschitz2Witness = new(-67.12454f, -129.53296f);
+
+ ///
+ /// Pins SNOISE2_LIPSCHITZ as LipschitzConstantPinsSampledGradients pins SNOISE_LIPSCHITZ: 1e5 seeded
+ /// points under it, and the ascent from MeasureLipschitz2's witness within half a percent of it / 1.10.
+ ///
+ [Fact]
+ public void Lipschitz2ConstantPins()
+ {
+ var (sampled, _, _) = MeasureMax(Gradient2At, true, 0x2D17, 100_000, 0);
+ Assert.True(sampled <= SNOISE2_LIPSCHITZ, $"|grad snoise2| reaches {sampled:R}, above SNOISE2_LIPSCHITZ {SNOISE2_LIPSCHITZ:R}");
+ var refined = Ascend2(Gradient2Norm, Lipschitz2Witness);
+ Assert.True(refined <= SNOISE2_LIPSCHITZ, $"|grad snoise2| reaches {refined:R}, above SNOISE2_LIPSCHITZ {SNOISE2_LIPSCHITZ:R}");
+ var ratio = SNOISE2_LIPSCHITZ / (1.10 * refined);
+ Assert.True(Math.Abs(ratio - 1.0) <= 0.005, $"SNOISE2_LIPSCHITZ is {ratio:R} times 1.10 x the re-measured {refined:R}; re-run MeasureLipschitz2 and re-pin");
+ }
+
+ ///
+ /// iv_snoise_ball(float2) encloses snoise(float2) over 2,000 seeded discs of radius log-uniform in
+ /// [1e-3, 1e3] x 64 points (the first eight on the rim), no tolerance.
+ ///
+ [Fact]
+ public void Snoise2BallEnclosesPoints()
+ {
+ var random = new System.Random(0xBA12);
+ for (var b = 0; b < 2000; b++)
+ {
+ var centre = new float2(Uniform(random, -20.0f, 20.0f), Uniform(random, -20.0f, 20.0f));
+ var radius = LogUniform(random, 1.0e-3f, 1.0e3f);
+ var bound = iv_snoise_ball(centre, radius);
+ for (var i = 0; i < 64; i++)
+ {
+ var angle = Uniform(random, 0.0f, 2.0f * MathF.PI);
+ var x = centre + new float2(MathF.Cos(angle), MathF.Sin(angle)) * (i < 8 ? radius : radius * MathF.Sqrt(random.NextSingle()));
+ Assert.True(Inside(snoise(x), bound), $"iv_snoise_ball({centre}, {radius:R}) = {bound} misses snoise({x}) = {snoise(x):R}");
+ }
+ }
+ }
+
+ ///
+ /// The centred warp (design.md, "Affine forms"): over 2,000 seeded balls of the deep well's flow (warp
+ /// D = 60, period 8, flow frequency 1/512; centres in [-2000, 2000]^3, radius log-uniform in [1e-3, 500],
+ /// a time per ball) x 64 points, each phase's warped point p + flow(p) shift_k lies in the ball
+ /// (c + flow(c) shift_k, r + |shift_k| rho), r the radius widened by (|c|_1 + r) 2^-20 as iv_frustum_ball
+ /// widens its ball (the float32 point p is inside only up to that, which matters below a radius of 1),
+ /// geometry allowing one part in 1e5 for the rounding of the warped point, as WarpedPointsStayEnclosed does, and snoise of it, at the coverage frequency, lies
+ /// in iv_snoise_ball of that ball with no tolerance. Dropping rho fails: some warped points lie
+ /// farther than r from the moved centre.
+ ///
+ [Fact]
+ public void CentredWarpStaysEnclosed()
+ {
+ var noise = new WarpedNoise { F0 = 1.0f / FogField.NoiseScale, Warp = FogField.AetheriaWarp };
+ var random = new System.Random(0xCE17);
+ var beyond = 0;
+ for (var b = 0; b < 2000; b++)
+ {
+ var centre = new float3(Uniform(random, -2000.0f, 2000.0f), Uniform(random, -2000.0f, 2000.0f), Uniform(random, -2000.0f, 2000.0f));
+ var radius = LogUniform(random, 1.0e-3f, 500.0f);
+ var reach = radius + (abs(centre.x) + abs(centre.y) + abs(centre.z) + radius) * 9.5367431640625e-7f;
+ var time = Uniform(random, 0.0f, 100.0f);
+ var (_, shift0, shift1) = noise.Phases(time);
+ var (c0, g0, c1, g1) = noise.CentredWarp(centre, reach, time);
+ for (var i = 0; i < 64; i++)
+ {
+ var p = PointInBall(random, centre, radius, i);
+ var flow = noise.Flow(p);
+ foreach (var (shift, moved, grow) in new[] { (shift0, c0, g0), (shift1, c1, g1) })
+ {
+ var warped = p + flow * shift;
+ var distance = length(warped - moved);
+ Assert.True(distance <= (reach + grow) * (1.0f + 1.0e-5f), $"warped point {warped} leaves the centred ball ({moved}, {reach + grow:R})");
+ beyond += distance > radius ? 1 : 0;
+ var bound = iv_snoise_ball(moved * noise.F0, (reach + grow) * noise.F0);
+ var value = snoise(warped * noise.F0);
+ Assert.True(Inside(value, bound), $"iv_snoise_ball over the centred ball ({moved}, {reach + grow:R}) = {bound} misses snoise = {value:R} at {warped}");
+ }
+ }
+ }
+
+ output.WriteLine($"IV-REPORT centred warp: {beyond} of {2000 * 64 * 2} warped points lie beyond r from the moved centre");
+ Assert.True(beyond > 0, "no warped point needs rho: the check cannot tell a centred warp without it");
+ }
+
+ ///
+ /// FlowVariation's width, pinned both ways: over 2,000 seeded balls (centres in [-2000, 2000]^3, radius
+ /// log-uniform in [1e-3, 500]) it equals min(sqrt(u^2 + v^2), 2) A, A = FlowAmplitude, with each of u and v
+ /// the reach of iv_snoise_ball(float2) at the flow plane's argument (plus its offset) plus the float32
+ /// allowance 2^-14 + L2 2^-20 (|q|_1 + r FlowFrequency), to 0.3% (the float32 sum n + e rounds at 6e-8, against an allowance of 6e-5). The enclosure test sees the
+ /// allowance only where a float32 flow differs from the exact one by more than the bound's slack, which
+ /// on the CPU is rare (CentredWarpStaysEnclosed); this is the test that sees it.
+ ///
+ [Fact]
+ public void FlowVariationCarriesItsAllowance()
+ {
+ var noise = new WarpedNoise { F0 = 1.0f / FogField.NoiseScale, Warp = FogField.AetheriaWarp };
+ var amplitude = noise.Warp * 2.0 / noise.Period;
+ var random = new System.Random(0xF10E);
+ double Reach(float2 q, double r)
+ {
+ var n = snoise(q);
+ var e = SNOISE2_LIPSCHITZ * r;
+ return Math.Max(Math.Min(e, 1.0 - n), Math.Min(e, n + 1.0));
+ }
+
+ for (var b = 0; b < 2000; b++)
+ {
+ var centre = new float3(Uniform(random, -2000.0f, 2000.0f), Uniform(random, -2000.0f, 2000.0f), Uniform(random, -2000.0f, 2000.0f));
+ var radius = LogUniform(random, 1.0e-3f, 500.0f);
+ var rq = (double)radius * noise.FlowFrequency;
+ double Component(float2 offset)
+ {
+ var q = new float2(centre.x, centre.z) * noise.FlowFrequency + offset;
+ return Reach(q, rq) + Math.ScaleB(1.0, -14) + SNOISE2_LIPSCHITZ * Math.ScaleB(Math.Abs((double)q.x) + Math.Abs((double)q.y) + rq, -20);
+ }
+
+ var (u, v) = (Component(new float2(17.0f, 3.0f)), Component(new float2(-5.0f, 41.0f)));
+ var expected = Math.Min(Math.Sqrt(u * u + v * v), 2.0) * amplitude;
+ var observed = noise.FlowVariation(centre, radius);
+ Assert.True(Math.Abs(observed - expected) <= 3.0e-3 * expected, $"FlowVariation({centre}, {radius:R}) = {observed:R}, the documented rule gives {expected:R}");
+ }
+ }
+
+ ///
+ /// The centred warp over an affine slice (FogField.Slice, the owner AffineBound reads): over 3,000
+ /// seeded tile slices (the deep well, the shallow wells and inside the fog; N in {1, 4, 8, 16}; a
+ /// slice of length log-uniform in [0.5, 1500] from a drawn depth, so the axis is from far under to far
+ /// over the ball's radius) x 64 rays each (the first two at the slice's ends), each phase's warped ray
+ /// point p + flow(p) shift_k lies within radius + growth_k of moved_k + axis eps(z), eps(z) =
+ /// clamp((z - z_m) / h, -1, 1), no tolerance but one part in 1e5 for the rounding of the warped point.
+ /// The check sees each term of the slice: a reach of the ball's radius instead of |axis| + radius, a
+ /// phase's growth dropped, or rho halved leaves rays outside; the report counts the rays that need
+ /// each phase's growth, and the test asserts both phases have some.
+ ///
+ [Fact]
+ public void AffineWarpStaysEnclosed()
+ {
+ var random = new System.Random(0xAF77);
+ int[] sizes = { 1, 4, 8, 16 };
+ var fields = new[]
+ {
+ FogField.DeepWell(FogField.AetheriaWarp, BoundMode.Affine), FogField.Wells(FogField.AetheriaWarp, BoundMode.Affine), FogField.InsideFog(FogField.AetheriaWarp, BoundMode.Affine),
+ };
+ var needing = new[] { 0, 0 };
+ for (var t = 0; t < 3000; t++)
+ {
+ var field = fields[t % fields.Length];
+ var tile = field.DrawTile(random, sizes[random.Next(sizes.Length)]);
+ var z0 = Uniform(random, field.Grid[0], field.Grid[^1] * 0.9f);
+ var z1 = MathF.Min(z0 + LogUniform(random, 0.5f, 1500.0f), field.Grid[^1]);
+ var slice = field.Slice(tile, z0, z1);
+ var (_, shift0, shift1) = field.Noise.Phases(tile.Time);
+ var (zm, h) = (slice.Ball.z, slice.AxisCamera.z);
+
+ // The arguments are built from the centred warp of the slice's own centre and reach, the detail
+ // from the unwarped set: no phase takes another's growth, nor the detail a warp.
+ var (moved0, grow0, moved1, grow1) = field.Noise.CentredWarp(slice.Centre, slice.Reach, tile.Time);
+ var (coverageFrequency, detailFrequency) = (field.Noise.F0, 4.0f * field.Noise.F0);
+ var expected = new[]
+ {
+ (slice.Coverage0, moved0 * coverageFrequency, (slice.Ball.w + grow0) * coverageFrequency),
+ (slice.Coverage1, moved1 * coverageFrequency, (slice.Ball.w + grow1) * coverageFrequency),
+ (slice.Detail, slice.Centre * detailFrequency + 17.0f, slice.Ball.w * detailFrequency),
+ };
+ foreach (var (arg, centre, radius) in expected)
+ {
+ Assert.True(length(arg.Centre - centre) <= 1.0e-6f * (1.0f + length(centre)) && Math.Abs(arg.Radius - radius) <= 1.0e-6f * radius, $"{field.Name}: argument ({arg.Centre}, {arg.Radius:R}) is not the documented ({centre}, {radius:R})");
+ }
+
+ var reachRule = length(slice.Coverage0.Axis) / coverageFrequency + slice.Ball.w;
+ Assert.True(Math.Abs(slice.Reach - reachRule) <= 1.0e-5f * reachRule, $"{field.Name}: the reach {slice.Reach:R} is not |axis| + radius = {reachRule:R}");
+ var axisTolerance = 1.0e-6f * length(slice.Coverage0.Axis);
+ Assert.True(length(slice.Coverage1.Axis - slice.Coverage0.Axis) <= axisTolerance && length(slice.Detail.Axis - slice.Coverage0.Axis * (detailFrequency / coverageFrequency)) <= 4.0f * axisTolerance, $"{field.Name}: the arguments do not share one axis");
+
+ for (var i = 0; i < 64; i++)
+ {
+ var m = tile.PixelSlope(random.Next(tile.N), random.Next(tile.N), random.NextSingle(), random.NextSingle());
+ var z = i < 2 ? (i == 0 ? z0 : z1) : Uniform(random, z0, z1);
+ var p = tile.World(new float3(m.x * z, m.y * z, z));
+ var flow = field.Noise.Flow(p);
+ var eps = h == 0.0f ? 0.0f : clamp((z - zm) / h, -1.0f, 1.0f);
+ var phases = new[] { (shift0, slice.Coverage0, coverageFrequency), (shift1, slice.Coverage1, coverageFrequency) };
+ for (var k = 0; k < 2; k++)
+ {
+ var (shift, arg, frequency) = phases[k];
+ var point = (p + flow * shift) * frequency;
+ var distance = length(point - (arg.Centre + arg.Axis * eps));
+ Assert.True(distance <= arg.Radius * (1.0f + 1.0e-5f) + 1.0e-6f * length(point), $"{field.Name}: phase {k} warped ray point at depth {z:R} is {distance:R} from the argument's centre + axis eps, outside radius {arg.Radius:R} (reach {slice.Reach:R}, slice [{z0:R}, {z1:R}])");
+ needing[k] += distance > slice.Ball.w * frequency ? 1 : 0;
+ }
+
+ var detail = p * detailFrequency + 17.0f;
+ var detailDistance = length(detail - (slice.Detail.Centre + slice.Detail.Axis * eps));
+ Assert.True(detailDistance <= slice.Detail.Radius * (1.0f + 1.0e-5f) + 1.0e-6f * length(detail), $"{field.Name}: the detail ray point at depth {z:R} is {detailDistance:R} from the argument's centre + axis eps, outside radius {slice.Detail.Radius:R} (slice [{z0:R}, {z1:R}])");
+ }
+ }
+
+ output.WriteLine($"IV-REPORT affine warp: rays beyond the unwarped radius, phase 0 {needing[0]}, phase 1 {needing[1]}");
+ Assert.True(needing[0] > 0 && needing[1] > 0, $"no ray needs phase growth ({needing[0]}, {needing[1]}): the check cannot tell a slice without it");
+ }
+
+ ///
+ /// The affine composition earns its place: over seeded slices of the deep well and the shallow wells
+ /// (warp 0 and the Aetheria warp, N = 8, slices of length log-uniform in [0.5, 100] from a drawn
+ /// depth), AffineBound is exactly the intersection of its two sound pieces (the affine arithmetic's
+ /// own, and the interval composition over the forms' ranges), and where the interval piece does not
+ /// already prove the slice empty the affine piece is the narrower of the two in at least 35% of
+ /// them and the intersection is narrower than the interval piece in total width by at least 0.5%
+ /// (measured: 43% and 1.1%). The affine piece alone is wider in total (the shared symbol pays where the forms are
+ /// correlated and loses to the clipped ranges where they are not), so it is the intersection's gain
+ /// that measures it. The cost contract (IntervalSkipHalvesEvaluations) sees only the sum, in which
+ /// af_snoise's Hessian forms already beat iv_snoise_ball; this is the test that sees af_add, af_mul and
+ /// af_range, the shared symbol, break.
+ ///
+ [Fact]
+ public void AffineCompositionTightensItsRanges()
+ {
+ var random = new System.Random(0xAC0F);
+ var (open, wins, intersectionWidth, intervalWidth) = (0, 0, 0.0, 0.0);
+ foreach (var warp in new[] { 0.0f, FogField.AetheriaWarp })
+ foreach (var field in new[] { FogField.DeepWell(warp, BoundMode.Affine), FogField.Wells(warp, BoundMode.Affine) })
+ for (var t = 0; t < 1500; t++)
+ {
+ var tile = field.DrawTile(random, 8);
+ var z0 = Uniform(random, field.Grid[0], field.Grid[^1] * 0.9f);
+ var z1 = MathF.Min(z0 + LogUniform(random, 0.5f, 100.0f), field.Grid[^1]);
+ var (affine, interval) = field.AffinePieces(tile, z0, z1, new Counts());
+ var bound = field.Bound(tile, z0, z1, false, new Counts());
+ Assert.True(bound.x == max(affine.x, interval.x) && bound.y == min(affine.y, interval.y), $"{field.Name}: Bound {bound} is not the intersection of the affine piece {affine} and the interval piece {interval}");
+ if (!(interval.y > 0.0f))
+ continue;
+ open++;
+ wins += affine.y - affine.x < interval.y - interval.x ? 1 : 0;
+ intersectionWidth += bound.y - bound.x;
+ intervalWidth += interval.y - interval.x;
+ }
+
+ output.WriteLine($"IV-REPORT affine composition: {open} open slices, affine narrower in {wins} ({(double)wins / open:F3}), intersection width {intersectionWidth:F1} against the interval piece's {intervalWidth:F1} ({intersectionWidth / intervalWidth:F3})");
+ Assert.True(open > 0, "no slice is open");
+ Assert.True(wins >= 0.35 * open, $"the affine piece is narrower than the interval piece in {wins} of {open} open slices, under 35%");
+ Assert.True(intersectionWidth <= 0.995 * intervalWidth, $"the intersection's width {intersectionWidth:F1} is not under 0.995 of the interval piece's {intervalWidth:F1}");
+ }
+
+ ///
+ /// The gate only ever gives up what the probes could not have delivered. Gated, a slice the best
+ /// conceivable probe cannot prove empty returns the envelope; so a slice the ungated bound proves
+ /// empty (its upper density 0) must be proved empty gated too. A gate that errs toward giving up
+ /// (the reach inflated, a gradient or Hessian term overstated) loosens the bound exactly there and
+ /// costs only culling, which no enclosure test sees; a gate that errs the other way only costs probes,
+ /// which the cost contract (IntervalSkipHalvesEvaluations) sees. Over seeded slices of both wells and the fog interior at
+ /// warp 0 and the Aetheria warp, N = 8, in both modes, no slice the ungated bound proves empty is
+ /// left open by the gated one, and at least 200 are proved empty.
+ ///
+ [Fact]
+ public void GateNeverGivesUpAProvableCull()
+ {
+ var random = new System.Random(0x6A7E);
+ var (proved, lost) = (0, new List());
+ foreach (var mode in new[] { BoundMode.Interval, BoundMode.Affine })
+ foreach (var warp in new[] { 0.0f, FogField.AetheriaWarp })
+ foreach (var field in new[] { FogField.DeepWell(warp, mode), FogField.Wells(warp, mode), FogField.InsideFog(warp, mode) })
+ for (var t = 0; t < 1500; t++)
+ {
+ var tile = field.DrawTile(random, 8);
+ var z0 = Uniform(random, field.Grid[0], field.Grid[^1] * 0.9f);
+ var z1 = MathF.Min(z0 + LogUniform(random, 0.5f, 100.0f), field.Grid[^1]);
+ if (field.Bound(tile, z0, z1, false, new Counts()).y > 0.0f)
+ continue;
+ proved++;
+ var gated = field.Bound(tile, z0, z1, true, new Counts());
+ if (gated.y > 0.0f)
+ lost.Add($"{field.Name} {mode} warp {warp}: slice [{z0:R}, {z1:R}] is proved empty ungated but the gate leaves it at {gated}");
+ }
+
+ output.WriteLine($"IV-REPORT gate: {proved} slices proved empty ungated, {lost.Count} left open by the gate");
+ Assert.True(proved >= 200, $"only {proved} slices are proved empty ungated: the check cannot tell a gate that loses them");
+ Assert.True(lost.Count == 0, $"{lost.Count} provable culls given up by the gate, first: {lost.FirstOrDefault()}");
+ }
+
+ // Why a field is not ten bands deep and wide, or null. The band G is the span of s where only the
+ // noise decides density: s in [F + A lo, F + A hi] for the free noise range [lo, hi], with the fade at 1.
+ private static string? TenBandsShortfall(FogField field, int cameras)
+ {
+ var band = FogField.Amplitude * (FogField.FreeNoise.y - FogField.FreeNoise.x);
+ var well = field.Bowls[^1];
+ var rim = well.Scale / 2.0f;
+ float At(float r) => field.HeightAt(well.Centre + new float2(r, 0.0f));
+ var depth = At(0.0f) - At(rim);
+ var half = (At(0.0f) + At(rim)) / 2.0f;
+ float lo = 0.0f, hi = rim;
+ for (var k = 0; k < 60; k++)
+ {
+ var mid = (lo + hi) / 2.0f;
+ if (At(mid) > half)
+ lo = mid;
+ else
+ hi = mid;
+ }
+
+ var problems = new List();
+ if (depth < 10.0f * band)
+ problems.Add($"depth {depth:R} is under 10 G = {10.0f * band:R}");
+ if (lo < 10.0f * band)
+ problems.Add($"half-depth radius {lo:R} is under 10 G = {10.0f * band:R}");
+ var random = new System.Random(0xD33B);
+ for (var c = 0; c < cameras; c++)
+ {
+ var origin = field.DrawTile(random, 8).Origin;
+ var xz = new float2(origin.x, origin.z);
+ var s = origin.y + field.HeightAt(xz);
+ if (!(length(xz - well.Centre) < lo && origin.y < FogField.FloorOffset - At(rim) && s >= FogField.FloorOffset + FogField.Amplitude * FogField.FreeNoise.y))
+ {
+ problems.Add($"camera {origin} is not inside the well, below the rim's fog surface, in empty air");
+ break;
+ }
+ }
+
+ return problems.Count == 0 ? null : $"{field.Name}: G = {band:R}; " + string.Join("; ", problems);
+ }
+
+ ///
+ /// Ruling wells-scale-order-of-magnitude: the band G is computed from FogField's FloorOffset, Amplitude
+ /// and free noise range (60). The deep well's depth, h(centre) - h(rim), and its half-depth radius,
+ /// found by bisection on the well map, are each at least 10 G, and each of 1,000 drawn cameras sits
+ /// inside that radius, below the rim's fog surface and in empty air (s above the band). A well of depth
+ /// 150 fails the same check.
+ ///
+ [Fact]
+ public void DeepWellIsTenBandsDeepAndWide()
+ {
+ var deep = FogField.DeepWell(FogField.AetheriaWarp, BoundMode.Interval);
+ Assert.Null(TenBandsShortfall(deep, 1000));
+ Assert.NotNull(TenBandsShortfall(FogField.DeepWell(FogField.AetheriaWarp, BoundMode.Interval, depth: 150.0f), 1000));
+ var band = FogField.Amplitude * (FogField.FreeNoise.y - FogField.FreeNoise.x);
+ output.WriteLine($"IV-REPORT deep well: G = {band:R}, depth {deep.HeightAt(new float2(0.0f, 0.0f)) - deep.HeightAt(new float2(FogField.DeepWellScale / 2.0f, 0.0f)):R}");
+ }
+
+ // ---- The cull map ----
+
+ // An approximation of viridis at nine anchors, interpolated linearly, for t in [0, 1].
+ private static readonly (byte R, byte G, byte B)[] Viridis =
+ {
+ (68, 1, 84), (72, 40, 120), (62, 74, 137), (49, 104, 142), (38, 130, 142), (31, 158, 137), (53, 183, 121), (110, 206, 88), (253, 231, 37),
+ };
+
+ private static (byte, byte, byte) Colour(double t)
+ {
+ t = Math.Clamp(t, 0.0, 1.0) * (Viridis.Length - 1);
+ var i = Math.Min((int)t, Viridis.Length - 2);
+ var f = t - i;
+ byte Mix(byte a, byte b) => (byte)Math.Round(a + (b - a) * f);
+ return (Mix(Viridis[i].R, Viridis[i + 1].R), Mix(Viridis[i].G, Viridis[i + 1].G), Mix(Viridis[i].B, Viridis[i + 1].B));
+ }
+
+ private static uint[] CrcTable() => Enumerable.Range(0, 256).Select(n =>
+ {
+ var c = (uint)n;
+ for (var k = 0; k < 8; k++)
+ c = (c & 1) != 0 ? 0xEDB88320u ^ (c >> 1) : c >> 1;
+ return c;
+ }).ToArray();
+
+ // A minimal 8-bit RGB PNG: one IDAT of zlib-compressed rows, filter 0.
+ private static void WritePng(string path, int width, int height, byte[] rgb)
+ {
+ var table = CrcTable();
+ using var file = File.Create(path);
+ void Chunk(string type, byte[] data)
+ {
+ var name = System.Text.Encoding.ASCII.GetBytes(type);
+ var length = new[] { (byte)(data.Length >> 24), (byte)(data.Length >> 16), (byte)(data.Length >> 8), (byte)data.Length };
+ file.Write(length);
+ file.Write(name);
+ file.Write(data);
+ var crc = 0xFFFFFFFFu;
+ foreach (var b in name.Concat(data))
+ crc = table[(crc ^ b) & 0xFF] ^ (crc >> 8);
+ crc ^= 0xFFFFFFFFu;
+ file.Write(new[] { (byte)(crc >> 24), (byte)(crc >> 16), (byte)(crc >> 8), (byte)crc });
+ }
+
+ file.Write(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 });
+ Chunk("IHDR", new byte[] { (byte)(width >> 24), (byte)(width >> 16), (byte)(width >> 8), (byte)width, (byte)(height >> 24), (byte)(height >> 16), (byte)(height >> 8), (byte)height, 8, 2, 0, 0, 0 });
+ using var packed = new MemoryStream();
+ using (var z = new System.IO.Compression.ZLibStream(packed, System.IO.Compression.CompressionLevel.Optimal, leaveOpen: true))
+ {
+ for (var y = 0; y < height; y++)
+ {
+ z.WriteByte(0);
+ z.Write(rgb, y * width * 3, width * 3);
+ }
+ }
+
+ Chunk("IDAT", packed.ToArray());
+ Chunk("IEND", Array.Empty());
+ }
+
+ ///
+ /// The cull map of one deep-well frame at warp D, for the operator: a camera inside the well at xz
+ /// (0, -200), y = F - h / 2, looking along +z across the well, 960 x 540 pixels at a 60 degree vertical
+ /// field of view, in 8 x 8 tiles (the last row of tiles half off the frame). Each tile runs the
+ /// pre-pass under the centred-warp interval bound and under the affine bound; each pixel's ray (through
+ /// the pixel's centre) is marched densely for its transmittance and over each tile mask and the oracle
+ /// mask (the cells some ray of the tile samples nonzero), with the early-out at 0.02. The PNG is
+ /// 1920 x 1080 in four panels: top left the cells per ray the interval march integrates, top right the
+ /// affine march's, bottom left the oracle march's (all three on one viridis scale, logarithmic,
+ /// log(1 + n) / log(1 + the largest count)), bottom right the transmittance (black opaque, white clear). It is written only when
+ /// CULTMATH_WRITE_CULLMAP names a directory; the mean cells per ray are printed either way.
+ ///
+ [Fact(Explicit = true)]
+ [Trait("Category", "Slow")]
+ public void DeepWellCullMap()
+ {
+ const int width = 960, height = 540, size = 8;
+ var interval = FogField.DeepWell(FogField.AetheriaWarp, BoundMode.Interval);
+ var affine = FogField.DeepWell(FogField.AetheriaWarp, BoundMode.Affine);
+ var focal = height / 2.0f / MathF.Tan(MathF.PI / 6.0f);
+ var xz = new float2(0.0f, -200.0f);
+ var origin = new float3(xz.x, FogField.FloorOffset - 0.5f * interval.HeightAt(xz), xz.y);
+ var grid = interval.Grid;
+ var (cellsInterval, cellsAffine, cellsOracle) = (new int[width * height], new int[width * height], new int[width * height]);
+ var transmittance = new float[width * height];
+ var (tilesX, tilesY) = (width / size, (height + size - 1) / size);
+ var probes = new Counts[tilesX * tilesY];
+ var clock = System.Diagnostics.Stopwatch.StartNew();
+ Parallel.For(0, tilesX * tilesY, index =>
+ {
+ var (tx, ty) = (index % tilesX, index / tilesX);
+ var slope = new float2((tx * size + size / 2.0f - width / 2.0f) / focal, (height / 2.0f - (ty * size + size / 2.0f)) / focal);
+ var tile = interval.TileAt(origin, 0.0f, slope, size, focal, 3.0f);
+ probes[index] = new Counts();
+ var (maskInterval, _, _) = MarchTile(interval, tile, probes[index]);
+ var (maskAffine, _, _) = MarchTile(affine, tile, new Counts());
+ var scratch = new Counts();
+ var rays = new List<(int Pixel, float2 Slope)>();
+ for (var j = 0; j < size; j++)
+ for (var i = 0; i < size; i++)
+ {
+ var (px, py) = (tx * size + i, ty * size + (size - 1 - j));
+ rays.Add((py < height ? py * width + px : -1, tile.PixelSlope(i, j, 0.5f, 0.5f)));
+ }
+
+ var oracle = Enumerable.Range(0, grid.Length - 1).Where(c => rays.Any(r => interval.Density(tile, r.Slope, (grid[c] + grid[c + 1]) * 0.5f, false, scratch) > 0.0f)).ToList();
+ foreach (var (pixel, ray) in rays)
+ {
+ if (pixel < 0)
+ continue;
+ int Steps(List mask)
+ {
+ var t = 1.0f;
+ var k = 0;
+ for (; k < mask.Count && t >= 0.02f; k++)
+ t *= Integrate(interval, tile, ray, grid[mask[k]], grid[mask[k] + 1], lod: false, scratch);
+ return k;
+ }
+
+ var dense = 1.0f;
+ for (var c = 0; c < grid.Length - 1 && dense >= 0.02f; c++)
+ dense *= Integrate(interval, tile, ray, grid[c], grid[c + 1], lod: false, scratch);
+ transmittance[pixel] = dense;
+ cellsInterval[pixel] = Steps(maskInterval);
+ cellsAffine[pixel] = Steps(maskAffine);
+ cellsOracle[pixel] = Steps(oracle);
+ }
+ });
+
+ var most = Math.Max(cellsInterval.Max(), Math.Max(cellsAffine.Max(), cellsOracle.Max()));
+ output.WriteLine($"IV-REPORT cull map (deep well, warp {FogField.AetheriaWarp:R}, {width}x{height}, {size}x{size} tiles, {clock.Elapsed.TotalSeconds:F0} s): cells per ray interval {cellsInterval.Average():F2}, affine {cellsAffine.Average():F2}, oracle {cellsOracle.Average():F2}; "
+ + $"largest {most}; interval probes per tile env {probes.Average(p => p.Envelope):F1} snoise {probes.Average(p => p.Snoise):F2}; mean transmittance {transmittance.Average():F3}");
+ var directory = Environment.GetEnvironmentVariable("CULTMATH_WRITE_CULLMAP");
+ if (string.IsNullOrEmpty(directory))
+ return;
+ var rgb = new byte[2 * width * 2 * height * 3];
+ void Put(int x, int y, (byte R, byte G, byte B) c)
+ {
+ var o = (y * 2 * width + x) * 3;
+ (rgb[o], rgb[o + 1], rgb[o + 2]) = c;
+ }
+
+ for (var y = 0; y < height; y++)
+ for (var x = 0; x < width; x++)
+ {
+ var p = y * width + x;
+ Put(x, y, Colour(Math.Log(1.0 + cellsInterval[p]) / Math.Log(1.0 + most)));
+ Put(width + x, y, Colour(Math.Log(1.0 + cellsAffine[p]) / Math.Log(1.0 + most)));
+ Put(x, height + y, Colour(Math.Log(1.0 + cellsOracle[p]) / Math.Log(1.0 + most)));
+ var grey = (byte)Math.Round(255.0 * transmittance[p]);
+ Put(width + x, height + y, (grey, grey, grey));
+ }
+
+ for (var k = 0; k < 2 * width; k++)
+ for (var d = -1; d <= 0; d++)
+ Put(k, height + d, (255, 255, 255));
+ for (var k = 0; k < 2 * height; k++)
+ for (var d = -1; d <= 0; d++)
+ Put(width + d, k, (255, 255, 255));
+ Directory.CreateDirectory(directory);
+ var path = Path.Combine(directory, "deep-well-cull-map.png");
+ WritePng(path, 2 * width, 2 * height, rgb);
+ output.WriteLine($"IV-REPORT cull map written to {path}");
+ }
+
///
/// Mean of interval width over the true range (max - min of the 64 sampled values) per ball: how
/// loose the Lipschitz bound is, for a later affine cut to beat. Asserts only finiteness.
@@ -519,12 +1236,18 @@ public sealed class NoiseBoundTests
// counts are printed, so any other weight can be applied to them.
internal const double EnvelopeCost = 0.2;
+ // One snoise_grad evaluation (af_snoise's one call) costs this much in snoise units: the value and
+ // three gradient components over the same corners. An estimate, printed beside the count as the
+ // envelope weight is, and not tuned toward any contract.
+ internal const double GradCost = 2.0;
+
internal sealed class Counts
{
public long Snoise;
public long Envelope;
+ public long Grad;
- public double Cost => Snoise + EnvelopeCost * Envelope;
+ public double Cost => Snoise + EnvelopeCost * Envelope + GradCost * Grad;
}
///
@@ -580,6 +1303,13 @@ public sealed class NoiseBoundTests
/// noise ball only when the best outcome any centre value could give would prove it; ungated, the ball
/// is always evaluated.
///
+ /// FogField's bound: the centred-warp interval composition, or the affine one (design.md, "Affine forms").
+ internal enum BoundMode
+ {
+ Interval,
+ Affine,
+ }
+
internal abstract class Scenario
{
public required string Name { get; init; }
@@ -645,7 +1375,7 @@ public sealed class NoiseBoundTests
private float FlowAmplitude => Warp * 2.0f / Period;
- private float3 Flow(float3 p)
+ public float3 Flow(float3 p)
{
var q = (FlowInXY ? new float2(p.x, p.y) : new float2(p.x, p.z)) * FlowFrequency;
var v = new float2(snoise(q + new float2(17.0f, 3.0f)), snoise(q + new float2(-5.0f, 41.0f)));
@@ -653,7 +1383,7 @@ public sealed class NoiseBoundTests
return FlowInXY ? new float3(v.x, v.y, 0.0f) : new float3(v.x, 0.0f, v.y);
}
- private (float W0, float Shift0, float Shift1) Phases(float time)
+ public (float W0, float Shift0, float Shift1) Phases(float time)
{
var phase0 = frac(time / Period);
var phase1 = frac(time / Period + 0.5f);
@@ -674,12 +1404,54 @@ public sealed class NoiseBoundTests
return snoise(p * (4.0f * F0) + 17.0f);
}
- // Both phases' warped points lie in a ball that carries the warp, so one ball encloses both snoise;
- // the cross-fade is enclosed term by term with the frame's own weights.
- public float2 CoverageBound(float2 ball, float time)
+ // The cross-fade of the two phases' noise enclosures, term by term with the frame's own weights.
+ // A field whose ball carries the whole warp passes the same enclosure for both phases.
+ public float2 CoverageBound(float2 phase0, float2 phase1, float time)
{
var w0 = Phases(time).W0;
- return iv_add(iv_scale(ball, w0), iv_scale(ball, 1.0f - w0));
+ return iv_add(iv_scale(phase0, w0), iv_scale(phase1, 1.0f - w0));
+ }
+
+ ///
+ /// How far the flow can move across a ball of radius r about c: each flow component is snoise(float2)
+ /// of the point projected to the flow plane and scaled by FlowFrequency, which varies over the ball by
+ /// at most iv_snoise_ball(float2)'s reach from its centre value, plus Deviation's float32 allowance; the
+ /// projection and the clamp to the unit disc are nonexpansive, and two unit-disc vectors differ by at
+ /// most 2.
+ ///
+ public float FlowVariation(float3 centre, float radius)
+ {
+ var q = (FlowInXY ? new float2(centre.x, centre.y) : new float2(centre.x, centre.z)) * FlowFrequency;
+ var u = Deviation(q + new float2(17.0f, 3.0f), radius * FlowFrequency);
+ var v = Deviation(q + new float2(-5.0f, 41.0f), radius * FlowFrequency);
+ return min(sqrt(u * u + v * v), 2.0f) * FlowAmplitude;
+ }
+
+ // How far snoise(float2) can differ from its value at q over radius, in float32: the ball's reach plus
+ // the allowance of af_snoise's convention for the 2D value, 2^-14 + L2 2^-20 (|q|_1 + r). The point
+ // q + offset rounds at the magnitude of q + offset (a unit in the last place of 20 is 2^-19), so the
+ // flow at two points of a ball differs by more than the exact function can, and the iv_snoise_ball
+ // bound, which is exact for the point it is given, does not carry that.
+ private static float Deviation(float2 q, float radius)
+ {
+ var n = snoise(q);
+ var ball = iv_snoise_ball(q, radius);
+ var allowance = 6.103515625e-5f + SNOISE2_LIPSCHITZ * 9.5367431640625e-7f * (abs(q.x) + abs(q.y) + radius);
+ return max(ball.y - n, n - ball.x) + allowance;
+ }
+
+ ///
+ /// The centred warp (design.md, "Affine forms"): phase k moves a point p of a set within reach of c
+ /// to p + flow(p) shift_k, which lies within |shift_k| rho of (p - c) + c + flow(c) shift_k, rho =
+ /// FlowVariation(c, reach). So phase k's noise argument is the set moved by flow(c) shift_k and
+ /// grown by |shift_k| rho, instead of grown by the whole warp. At warp 0 both phases are the set.
+ ///
+ public (float3 Centre0, float Grow0, float3 Centre1, float Grow1) CentredWarp(float3 centre, float reach, float time)
+ {
+ var (_, shift0, shift1) = Phases(time);
+ var flow = Flow(centre);
+ var rho = FlowVariation(centre, reach);
+ return (centre + flow * shift0, abs(shift0) * rho, centre + flow * shift1, abs(shift1) * rho);
}
public float2 CoverageBall(float3 centre, float radius, Counts counts) => NoiseBall(centre * F0, radius * F0, counts);
@@ -713,9 +1485,10 @@ public sealed class NoiseBoundTests
public const float NoiseScale = 414.2167f; // :409
public const float AetheriaWarp = 60.0f; // Flow GlobalAmplitude 15 x Period 8 / 2, :402-405
public const float ZoneRadius = 2000.0f;
- private static readonly float2 FreeNoise = new(-1.5f, 1.5f);
+ internal static readonly float2 FreeNoise = new(-1.5f, 1.5f);
public required WarpedNoise Noise { get; init; }
+ public required BoundMode Mode { get; init; }
public (float2 Centre, float Scale, float Exponent, float Depth)[] Bowls { get; init; } = Array.Empty<(float2, float, float, float)>();
public required Func CameraAt { get; init; }
public required float2 SlopesY { get; init; }
@@ -731,26 +1504,60 @@ public sealed class NoiseBoundTests
private static WarpedNoise AetheriaNoise(float warp) => new() { F0 = 1.0f / NoiseScale, Warp = warp };
+ private static string Named(string name, BoundMode mode) => $"{name} [{(mode == BoundMode.Affine ? "affine" : "interval")}]";
+
/// (a) Height fog: no wells, the camera above the safety band at y = S + 30, rays level and up.
- public static FogField HeightFog(float warp) => new()
+ public static FogField HeightFog(float warp, BoundMode mode) => new()
{
- Name = "(a) height fog", Noise = AetheriaNoise(warp), SlopesY = new float2(0.0f, 0.5f),
+ Name = Named("(a) height fog", mode), Mode = mode, Noise = AetheriaNoise(warp), SlopesY = new float2(0.0f, 0.5f),
CameraAt = (random, _) => new float3(Uniform(random, -1000.0f, 1000.0f), Safety + 30.0f, Uniform(random, -1000.0f, 1000.0f)),
};
/// (b) Inside the fog: no wells, the camera at y = F - 10, rays level.
- public static FogField InsideFog(float warp) => new()
+ public static FogField InsideFog(float warp, BoundMode mode) => new()
{
- Name = "(b) inside the fog", Noise = AetheriaNoise(warp), SlopesY = new float2(-0.05f, 0.05f),
+ Name = Named("(b) inside the fog", mode), Mode = mode, Noise = AetheriaNoise(warp), SlopesY = new float2(-0.05f, 0.05f),
CameraAt = (random, _) => new float3(Uniform(random, -1000.0f, 1000.0f), FloorOffset - 10.0f, Uniform(random, -1000.0f, 1000.0f)),
};
+ // The deep well's geometry (ruling wells-scale-order-of-magnitude): one PowerPulse well of exponent
+ // 2, scale 2220 and depth 600 at the zone's centre, so its depth and half-depth radius are each
+ // about 600, ten times the band (DeepWellIsTenBandsDeepAndWide measures both).
+ public const float DeepWellScale = 2220.0f;
+ public const float DeepWellDepth = 600.0f;
+ public const float DeepWellCameraRadius = 300.0f;
+
///
- /// (c) Aetheria-like: the zone bowl R = 2000 and four wells of mass 100, 1000, 10000 and 1000 at seeded
- /// positions inside it; the camera at a seeded xz in the bowl, above the noise band at
- /// y = max(0, S + 10 - h), gazing across with m_y in [-0.25, 0.1].
+ /// (c) The deep well, the case Aetheria plays in: there the camera is always in some gravity well,
+ /// gazing across a bowl a sun's gravity carves (ruling wells-scale-order-of-magnitude). The zone bowl
+ /// R = 2000 plus one well at its centre, PowerPulse exponent 2, scale 2220, depth 600, so the well's
+ /// depth and half-depth radius are each about ten times G = 3 A = 60, the band of s where only the
+ /// noise decides density (s in [F - 1.5 A, F + 1.5 A] with the fade at 1). The camera's xz is uniform
+ /// within 300 of the centre, at y = F - h(xz) / 2, halfway between the sunken fog surface and the
+ /// rim's, in empty air; slopes and yaw as the shallow wells, m_y in [-0.25, 0.1]. A level ray crosses
+ /// hundreds of units of empty well before the far wall's band.
///
- public static FogField Wells(float warp)
+ public static FogField DeepWell(float warp, BoundMode mode, float depth = DeepWellDepth) => new()
+ {
+ Name = Named("(c) deep well", mode), Mode = mode, Noise = AetheriaNoise(warp), SlopesY = new float2(-0.25f, 0.1f),
+ Bowls = new (float2, float, float, float)[] { (new float2(0.0f, 0.0f), 2.0f * ZoneRadius, 2.0f, 64.0f), (new float2(0.0f, 0.0f), DeepWellScale, 2.0f, depth) },
+ CameraAt = (r, field) =>
+ {
+ var angle = Uniform(r, 0.0f, 2.0f * MathF.PI);
+ var radius = DeepWellCameraRadius * MathF.Sqrt(r.NextSingle());
+ var xz = new float2(radius * MathF.Cos(angle), radius * MathF.Sin(angle));
+ return new float3(xz.x, FloorOffset - 0.5f * field.HeightAt(xz), xz.y);
+ },
+ };
+
+ ///
+ /// (c-band) Shallow wells, the band-dominated row, printed only: the zone bowl R = 2000 (64 deep) and
+ /// four wells of mass 100, 1000, 10000 and 1000 at seeded positions inside it, 30 M^0.175 deep (67 to
+ /// 150, 1.1 to 2.5 times G) and 500 M^0.25 wide at exponent 16; the camera at a seeded xz in the bowl,
+ /// just above the noise band at y = max(0, S + 10 - h), gazing across with m_y in [-0.25, 0.1]. Most
+ /// of its cost is the band itself, which is where affine noise gains most.
+ ///
+ public static FogField Wells(float warp, BoundMode mode)
{
var random = new System.Random(0xA37E);
var bowls = new List<(float2, float, float, float)> { (new float2(0.0f, 0.0f), 2.0f * ZoneRadius, 2.0f, 64.0f) };
@@ -763,14 +1570,13 @@ public sealed class NoiseBoundTests
return new FogField
{
- Name = "(c) Aetheria wells", Noise = AetheriaNoise(warp), Bowls = bowls.ToArray(), SlopesY = new float2(-0.25f, 0.1f),
+ Name = Named("(c-band) shallow wells", mode), Mode = mode, Noise = AetheriaNoise(warp), Bowls = bowls.ToArray(), SlopesY = new float2(-0.25f, 0.1f),
CameraAt = (r, field) =>
{
var angle = Uniform(r, 0.0f, 2.0f * MathF.PI);
var radius = ZoneRadius * MathF.Sqrt(r.NextSingle());
var xz = new float2(radius * MathF.Cos(angle), radius * MathF.Sin(angle));
- var h = field.Height(field.Bowls.Select(b => b.Centre - xz).ToArray(), 0.0f, 0.0f);
- return new float3(xz.x, max(0.0f, Safety + 10.0f - h), xz.y);
+ return new float3(xz.x, max(0.0f, Safety + 10.0f - field.HeightAt(xz)), xz.y);
},
};
}
@@ -784,11 +1590,15 @@ public sealed class NoiseBoundTests
{
var origin = CameraAt(random, this);
var yaw = Uniform(random, 0.0f, 2.0f * MathF.PI);
- var tile = new FogTile
- {
- Origin = origin, N = n, Focal = Focal, Time = Uniform(random, 0.0f, 100.0f),
- Slope = new float2(Uniform(random, -1.0f, 1.0f), Uniform(random, SlopesY.x, SlopesY.y)),
- };
+ var time = Uniform(random, 0.0f, 100.0f);
+ var slope = new float2(Uniform(random, -1.0f, 1.0f), Uniform(random, SlopesY.x, SlopesY.y));
+ return TileAt(origin, yaw, slope, n, Focal, time);
+ }
+
+ /// The tile of a camera at origin, yawed about y (0 looks along +z), at the given slope, size, focal length and time.
+ public Tile TileAt(float3 origin, float yaw, float2 slope, int n, float focal, float time)
+ {
+ var tile = new FogTile { Origin = origin, N = n, Focal = focal, Time = time, Slope = slope };
tile.Look(new float3(MathF.Sin(yaw), 0.0f, MathF.Cos(yaw)));
tile.Centres = Bowls.Select(b =>
{
@@ -819,6 +1629,9 @@ public sealed class NoiseBoundTests
return h;
}
+ /// The well map h at the world point (x, z).
+ public float HeightAt(float2 xz) => Height(Bowls.Select(b => b.Centre).ToArray(), xz.x, xz.y);
+
// Each bowl's term over the box is [pulse(far), pulse(near)], pulse decreasing in distance; pow is
// not required to be correctly rounded, so both ends are widened by one ulp.
private float2 HeightBound(float2[] centres, float2 x, float2 z)
@@ -861,35 +1674,184 @@ public sealed class NoiseBoundTests
return max(0.0f, (FloorOffset - (s + fade * n * Amplitude)) / FloorBlend);
}
+ ///
+ /// The envelope first: the height and slope intervals over the slice's box, the fade, and the noise
+ /// at its free range. Where that already proves the slice empty the envelope is the answer;
+ /// otherwise Mode's bound, which (gated) returns the envelope when the best any probe could give
+ /// would not prove the slice either.
+ ///
public override float2 Bound(Tile t, float z0, float z1, bool gated, Counts counts)
{
var tile = (FogTile)t;
+ var frame = FrameOf(tile, z0, z1, counts);
+ if (gated && frame.Envelope.y <= 0.0f)
+ return frame.Envelope;
+ return Mode == BoundMode.Affine
+ ? AffineBound(tile, z0, z1, frame, gated, counts)
+ : IntervalBound(tile, z0, z1, frame.S, frame.Fade, frame.Envelope, gated, counts);
+ }
+
+ // The height interval, the density level s over the slice's box, its fade and the envelope.
+ private readonly record struct Frame(float2 Height, float2 S, float2 Fade, float2 Envelope);
+
+ private Frame FrameOf(FogTile tile, float z0, float z1, Counts counts)
+ {
var depth = new float2(z0, z1);
counts.Envelope++;
var height = HeightBound(tile.Centres, iv_mul(depth, tile.SlopesX), depth);
var s = iv_add(iv_add(iv_point(tile.Origin.y), iv_mul(depth, tile.SlopesY)), height);
var fade = iv_sub(iv_point(1.0f), iv_smoothstep(0.75f * Safety, Safety, s));
- var envelope = Compose(s, fade, FreeNoise);
- if (gated && envelope.y <= 0.0f)
- return envelope;
- var ball = iv_frustum_ball(tile.Slope, z0, z1, tile.Footprint, Noise.Warp);
+ return new Frame(height, s, fade, Compose(s, fade, FreeNoise));
+ }
+
+ ///
+ /// The two sound bounds AffineBound intersects, ungated: the affine arithmetic's own (the shared
+ /// symbol through af_add, af_mul and af_range), and the interval composition over the same forms'
+ /// ranges (NoiseBoundTests.AffineCompositionTightensItsRanges).
+ ///
+ internal (float2 Affine, float2 Interval) AffinePieces(Tile t, float z0, float z1, Counts counts)
+ {
+ var tile = (FogTile)t;
+ return AffinePieces(tile, z0, z1, FrameOf(tile, z0, z1, counts), counts);
+ }
+
+ private static bool Same(float3 a, float3 b, float ga, float gb) => all(a == b) && ga == gb;
+
+ ///
+ /// The centred-warp interval bound. The slice's ball is iv_frustum_ball with no warp; each phase's
+ /// coverage ball is that ball moved by the flow at its centre and grown by what the flow can vary
+ /// across it (WarpedNoise.CentredWarp), one ball when the phases coincide (warp 0). The detail octave
+ /// reads the unwarped point, so its ball is the unwarped one.
+ ///
+ private float2 IntervalBound(FogTile tile, float z0, float z1, float2 s, float2 fade, float2 envelope, bool gated, Counts counts)
+ {
+ var ball = iv_frustum_ball(tile.Slope, z0, z1, tile.Footprint, 0.0f);
+ var centre = tile.World(new float3(ball.x, ball.y, ball.z));
+ var (c0, g0, c1, g1) = Noise.CentredWarp(centre, ball.w, tile.Time);
if (gated)
{
var provable = false;
foreach (var low in new[] { true, false })
{
- var best = iv_add(Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w), low), tile.Time), iv_scale(BestBall(Noise.DetailRadius(ball.w), low), 0.5f));
- provable |= Compose(s, fade, best).y <= 0.0f;
+ var coverage = Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w + g0), low), BestBall(Noise.CoverageRadius(ball.w + g1), low), tile.Time);
+ provable |= Compose(s, fade, iv_add(coverage, iv_scale(BestBall(Noise.DetailRadius(ball.w), low), 0.5f))).y <= 0.0f;
}
if (!provable)
return envelope;
}
- var centre = tile.World(new float3(ball.x, ball.y, ball.z));
- var noise = iv_add(Noise.CoverageBound(Noise.CoverageBall(centre, ball.w, counts), tile.Time), iv_scale(Noise.DetailBall(centre, ball.w, counts), 0.5f));
+ var n0 = Noise.CoverageBall(c0, ball.w + g0, counts);
+ var n1 = Same(c0, c1, g0, g1) ? n0 : Noise.CoverageBall(c1, ball.w + g1, counts);
+ var noise = iv_add(Noise.CoverageBound(n0, n1, tile.Time), iv_scale(Noise.DetailBall(centre, ball.w, counts), 0.5f));
return Compose(s, fade, noise);
}
+
+ ///
+ /// The affine slice of a tile over [z0, z1] in the world frame, with the centred warp applied: the
+ /// camera-frame axis and ball (af_frustum_axis, af_frustum_ball with no warp), the ball's world
+ /// centre, the world axis, and the reach R = |axis| + radius of the whole set from that centre (the
+ /// distance the flow is varied over). It returns the final af_snoise arguments, so a consumer has no
+ /// term left to wire: each phase's coverage argument is the set moved by the flow at its centre
+ /// (WarpedNoise.CentredWarp over R) and grown by what the flow can vary across it, and the detail
+ /// argument is the unwarped set. The rays at depth z lie within an argument's radius of its centre
+ /// + axis eps(z), eps(z) = clamp((z - z_m) / h, -1, 1) (NoiseBoundTests.AffineWarpStaysEnclosed).
+ ///
+ internal AffineSlice Slice(Tile t, float z0, float z1)
+ {
+ var tile = (FogTile)t;
+ var axisCamera = af_frustum_axis(tile.Slope, z0, z1);
+ var ball = af_frustum_ball(tile.Slope, z0, z1, tile.Footprint, 0.0f);
+ var centre = tile.World(new float3(ball.x, ball.y, ball.z));
+ var axis = tile.Right * axisCamera.x + tile.Up * axisCamera.y + tile.Forward * axisCamera.z;
+ var reach = length(axis) + ball.w;
+ var (c0, g0, c1, g1) = Noise.CentredWarp(centre, reach, tile.Time);
+ var coverageFrequency = Noise.F0;
+ var detailFrequency = 4.0f * Noise.F0;
+ return new AffineSlice(
+ axisCamera, ball, centre, reach,
+ new NoiseArg(c0 * coverageFrequency, axis * coverageFrequency, (ball.w + g0) * coverageFrequency),
+ new NoiseArg(c1 * coverageFrequency, axis * coverageFrequency, (ball.w + g1) * coverageFrequency),
+ new NoiseArg(centre * detailFrequency + 17.0f, axis * detailFrequency, ball.w * detailFrequency));
+ }
+
+ /// One af_snoise argument in noise space: the centre, the axis along eps, and the radius.
+ internal readonly record struct NoiseArg(float3 Centre, float3 Axis, float Radius)
+ {
+ /// The distance of the whole set from its centre: the gate's reach.
+ public float Reach => length(Axis) + Radius;
+
+ public float3 Snoise() => af_snoise(Centre, Axis, Radius);
+ }
+
+ internal readonly record struct AffineSlice(float3 AxisCamera, float4 Ball, float3 Centre, float Reach, NoiseArg Coverage0, NoiseArg Coverage1, NoiseArg Detail);
+
+ // The best interval any centre value and gradient could give af_snoise over a set of reach R (the
+ // gradient 0, the value at the far end), toward low or high values: the affine gate.
+ private static float2 BestForm(float reach, bool low)
+ {
+ var e = min(SNOISE_LIPSCHITZ * reach, 0.5f * SNOISE_HESSIAN * reach * reach);
+ if (e >= 2.0f)
+ return new float2(-1.0f, 1.0f);
+ return low ? new float2(-1.0f, min(-1.0f + e, 1.0f)) : new float2(max(1.0f - e, -1.0f), 1.0f);
+ }
+
+ private static float2 Clip(float2 range) => new(max(range.x, -1.0f), min(range.y, 1.0f));
+
+ ///
+ /// The affine bound, one shared symbol: depth z = z_m + h eps over the slice (af_frustum_axis and
+ /// af_frustum_ball give the noise argument the same eps). s = O_y + m_c,y z + (m_y - m_c,y) z + h(xz)
+ /// is affine in eps, with the lateral slope-depth term (at most Half z1, plus the rounding of the
+ /// pointwise m_y z) and the height interval in e. Each phase's coverage and the unwarped detail are
+ /// af_snoise over the slice moved and grown by the centred warp, the fade enters as af_from_iv, and
+ /// s' = s + A fade n is ranged by af_range. The result is intersected with the interval composition
+ /// over the same forms' ranges, each clipped to [-1, 1] (both sound, no further evaluation). The gate
+ /// is BestForm's.
+ ///
+ private float2 AffineBound(FogTile tile, float z0, float z1, Frame frame, bool gated, Counts counts)
+ {
+ if (gated)
+ {
+ var slice = Slice(tile, z0, z1);
+ var (s, fade) = (frame.S, frame.Fade);
+ var provable = false;
+ foreach (var low in new[] { true, false })
+ {
+ var coverage = Noise.CoverageBound(BestForm(slice.Coverage0.Reach, low), BestForm(slice.Coverage1.Reach, low), tile.Time);
+ provable |= Compose(s, fade, iv_add(coverage, iv_scale(BestForm(slice.Detail.Reach, low), 0.5f))).y <= 0.0f;
+ }
+
+ if (!provable)
+ return frame.Envelope;
+ }
+
+ var (affine, interval) = AffinePieces(tile, z0, z1, frame, counts);
+ return new float2(max(affine.x, interval.x), min(affine.y, interval.y));
+ }
+
+ private (float2 Affine, float2 Interval) AffinePieces(FogTile tile, float z0, float z1, Frame frame, Counts counts)
+ {
+ var slice = Slice(tile, z0, z1);
+ var (ball, axisCamera) = (slice.Ball, slice.AxisCamera);
+ var (height, s, fade) = (frame.Height, frame.S, frame.Fade);
+ var shared = slice.Coverage0 == slice.Coverage1;
+ counts.Grad += shared ? 2 : 3;
+ var n0 = slice.Coverage0.Snoise();
+ var n1 = shared ? n0 : slice.Coverage1.Snoise();
+ var nd = slice.Detail.Snoise();
+ var w0 = Noise.Phases(tile.Time).W0;
+ var noise = af_add(af_add(af_scale(n0, w0), af_scale(n1, 1.0f - w0)), af_scale(nd, 0.5f));
+
+ // The clamp residual of z = z_m + h eps(z), 2^-23 (|z_m| + h) (af_frustum_ball).
+ var residual = (abs(ball.z) + axisCamera.z) * 1.1920928955078125e-7f;
+ var depth = af_add_iv(af_symbol(ball.z, axisCamera.z), new float2(-residual, residual));
+ var lateral = tile.Half * z1 + (abs(tile.Slope.y) + tile.Half) * z1 * 2.384185791015625e-7f;
+ var level = af_add_iv(af_add_iv(af_add(af_point(tile.Origin.y), af_scale(depth, tile.Slope.y)), new float2(-lateral, lateral)), height);
+ var displaced = af_range(af_add(level, af_scale(af_mul(af_from_iv(fade), noise), Amplitude)));
+ var affine = new float2(max(0.0f, (FloorOffset - displaced.y) / FloorBlend), max(0.0f, (FloorOffset - displaced.x) / FloorBlend));
+ var interval = Compose(s, fade, iv_add(Noise.CoverageBound(Clip(af_range(n0)), Clip(af_range(n1)), tile.Time), iv_scale(Clip(af_range(nd)), 0.5f)));
+ return (affine, interval);
+ }
}
///
@@ -937,9 +1899,10 @@ public sealed class NoiseBoundTests
{
var maybe = new float2(0.0f, float.MaxValue);
var ball = iv_frustum_ball(tile.Slope, z0, z1, tile.Footprint, Noise.Warp);
- if (gated && Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w), low: true), tile.Time).y > Cutoff)
+ if (gated && Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w), low: true), BestBall(Noise.CoverageRadius(ball.w), low: true), tile.Time).y > Cutoff)
return maybe;
- var coverage = Noise.CoverageBound(Noise.CoverageBall(tile.World(new float3(ball.x, ball.y, ball.z)), ball.w, counts), tile.Time);
+ var coverageBall = Noise.CoverageBall(tile.World(new float3(ball.x, ball.y, ball.z)), ball.w, counts);
+ var coverage = Noise.CoverageBound(coverageBall, coverageBall, tile.Time);
return coverage.y <= Cutoff ? new float2(0.0f, 0.0f) : maybe;
}
}
@@ -1162,7 +2125,7 @@ public sealed class NoiseBoundTests
var provable = false;
foreach (var low in new[] { true, false })
{
- var best = iv_add(iv_mul(Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w), low), tile.Time), wc), iv_mul(iv_scale(BestBall(Noise.DetailRadius(ball.w), low), 0.5f), wd));
+ var best = iv_add(iv_mul(Noise.CoverageBound(BestBall(Noise.CoverageRadius(ball.w), low), BestBall(Noise.CoverageRadius(ball.w), low), tile.Time), wc), iv_mul(iv_scale(BestBall(Noise.DetailRadius(ball.w), low), 0.5f), wd));
provable |= Compose(d, fade, best).y <= 0.0f;
}
@@ -1171,7 +2134,8 @@ public sealed class NoiseBoundTests
}
var centre = tile.World(new float3(ball.x, ball.y, ball.z));
- var noise = iv_add(iv_mul(Noise.CoverageBound(Noise.CoverageBall(centre, ball.w, counts), tile.Time), wc), iv_mul(iv_scale(Noise.DetailBall(centre, ball.w, counts), 0.5f), wd));
+ var coverage = Noise.CoverageBall(centre, ball.w, counts);
+ var noise = iv_add(iv_mul(Noise.CoverageBound(coverage, coverage, tile.Time), wc), iv_mul(iv_scale(Noise.DetailBall(centre, ball.w, counts), 0.5f), wd));
return Compose(d, fade, noise);
}
}
@@ -1301,6 +2265,7 @@ public sealed class NoiseBoundTests
public readonly Counts Probes = new();
public readonly Counts Lod = new();
public readonly Counts Oracle = new();
+ public readonly Counts Range = new();
public long Rays;
public long Tiles;
public long DenseSteps;
@@ -1314,6 +2279,10 @@ public sealed class NoiseBoundTests
public float MaxOracleDifference;
public long OracleEmpty;
public long OracleEmptySkipped;
+ public long RangeEmpty;
+ public long RangeEmptySkipped;
+ public long RangeViolations;
+ public bool Ranged;
public double MaxLodDepthError;
public double MaxRefDepthError;
@@ -1334,6 +2303,17 @@ public sealed class NoiseBoundTests
// The oracle-empty cells the pre-pass proves empty; a pre-pass that skips nothing scores 0.
public double CullFraction => (double)OracleEmptySkipped / OracleEmpty;
+
+ // The range ceiling: the oracle march's cost over the range mask's, with probes free. The range
+ // mask is what an exact enclosure of each cell over the tile's whole slice could prove, so no sound
+ // bound can reach the oracle, only this; it is sampled, so it is an upper estimate.
+ public double RangeCeiling => Oracle.Cost / Range.Cost;
+
+ // The tile march's efficiency against the range ceiling: the range mask's cost over the tile
+ // march's with its probes.
+ public double RangeEfficiency => Range.Cost / (Masked.Cost + Probes.Cost);
+
+ public double RangeCull => (double)RangeEmptySkipped / RangeEmpty;
}
///
@@ -1344,12 +2324,15 @@ public sealed class NoiseBoundTests
/// footprint-aware march as well, and the agreement at the body start (or the grid's end): the optical
/// depth of a cutoff-0 footprint march and of the fixed-step cells, each against ConvergedDepth at
/// h = 0.5. The oracle mask and the agreement marches count into throwaway Counts, the oracle march into
- /// its own, so the cost rows do not move.
+ /// its own, so the cost rows do not move. With range, the range mask as well: the oracle mask plus
+ /// every cell where the density is positive at any of 5 x 5 slopes over the tile's slope square
+ /// (corners included) x 9 depths over the cell; each ray is marched over it into Range, and a cell of
+ /// it the pre-pass skipped is counted as a range violation (a sampled point a bound failed to enclose).
///
- private static RunStats Run(Scenario field, int n, int tiles, int seed, bool lod = false)
+ private static RunStats Run(Scenario field, int n, int tiles, int seed, bool lod = false, bool range = false)
{
var random = new System.Random(seed);
- var stats = new RunStats();
+ var stats = new RunStats { Ranged = range };
var scratch = new Counts();
var grid = field.Grid;
for (var t = 0; t < tiles; t++)
@@ -1379,6 +2362,34 @@ public sealed class NoiseBoundTests
}
}
+ var ranged = new List();
+ if (range)
+ {
+ var inOracle = new HashSet(oracle);
+ for (var c = 0; c < grid.Length - 1; c++)
+ {
+ var sampled = inOracle.Contains(c);
+ for (var a = 0; a < 5 && !sampled; a++)
+ for (var b = 0; b < 5 && !sampled; b++)
+ for (var k = 0; k < 9 && !sampled; k++)
+ {
+ var slope = new float2(tile.SlopesX.x + (tile.SlopesX.y - tile.SlopesX.x) * a / 4.0f, tile.SlopesY.x + (tile.SlopesY.y - tile.SlopesY.x) * b / 4.0f);
+ sampled = field.Density(tile, slope, grid[c] + (grid[c + 1] - grid[c]) * k / 8.0f, false, scratch) > 0.0f;
+ }
+
+ if (sampled)
+ {
+ ranged.Add(c);
+ stats.RangeViolations += inMask.Contains(c) ? 0 : 1;
+ }
+ else
+ {
+ stats.RangeEmpty++;
+ stats.RangeEmptySkipped += inMask.Contains(c) ? 0 : 1;
+ }
+ }
+ }
+
var stop = bodyStart >= 0 ? bodyStart : grid.Length - 1;
foreach (var slope in slopes)
{
@@ -1391,6 +2402,9 @@ public sealed class NoiseBoundTests
var exact = 1.0f;
for (var c = 0; c < oracle.Count && exact >= 0.02f; c++)
exact *= Integrate(field, tile, slope, grid[oracle[c]], grid[oracle[c] + 1], lod: false, stats.Oracle);
+ var rangedT = 1.0f;
+ for (var c = 0; c < ranged.Count && rangedT >= 0.02f; c++)
+ rangedT *= Integrate(field, tile, slope, grid[ranged[c]], grid[ranged[c] + 1], lod: false, stats.Range);
stats.Rays++;
stats.MaxDifference = MathF.Max(stats.MaxDifference, MathF.Abs(dense - masked));
stats.MaxOracleDifference = MathF.Max(stats.MaxOracleDifference, MathF.Abs(dense - exact));
@@ -1420,10 +2434,13 @@ public sealed class NoiseBoundTests
private void Report(string label, RunStats s) => output.WriteLine(
$"IV-REPORT {label}: dense snoise/ray {s.PerRay(s.Dense.Snoise):F2} env/ray {s.PerRay(s.Dense.Envelope):F2} (samples/ray {s.PerRay(s.DenseSteps):F2}); "
- + $"tile snoise/ray {s.PerRay(s.Masked.Snoise + (double)s.Probes.Snoise):F2} env/ray {s.PerRay(s.Masked.Envelope + (double)s.Probes.Envelope):F2} "
- + $"(probes/tile env {(double)s.Probes.Envelope / s.Tiles:F1} snoise {(double)s.Probes.Snoise / s.Tiles:F2}; dense cells/ray {s.PerRay(s.MaskedSteps):F2}); "
+ + $"tile snoise/ray {s.PerRay(s.Masked.Snoise + (double)s.Probes.Snoise):F2} env/ray {s.PerRay(s.Masked.Envelope + (double)s.Probes.Envelope):F2} grad/ray {s.PerRay(s.Probes.Grad):F2} "
+ + $"(probes/tile env {(double)s.Probes.Envelope / s.Tiles:F1} snoise {(double)s.Probes.Snoise / s.Tiles:F2} grad {(double)s.Probes.Grad / s.Tiles:F2}; dense cells/ray {s.PerRay(s.MaskedSteps):F2}); "
+ $"cost ratio {s.Ratio:F2}x, oracle ceiling {s.OracleCeiling:F2}x, efficiency {s.Efficiency:F3}, cull fraction {s.CullFraction:F3} ({s.OracleEmptySkipped}/{s.OracleEmpty}), "
- + $"probe overhead {s.ProbeOverhead:F3}; max |dT| {s.MaxDifference:R}, oracle {s.MaxOracleDifference:R}; unfinished rays {s.Unfinished}");
+ + $"probe overhead {s.ProbeOverhead:F3}; max |dT| {s.MaxDifference:R}, oracle {s.MaxOracleDifference:R}; unfinished rays {s.Unfinished}"
+ + (s.Ranged
+ ? $"; range ceiling {s.RangeCeiling:F3} (oracle cost over the range mask's), efficiency against it {s.RangeEfficiency:F3}, range cull {s.RangeCull:F3} ({s.RangeEmptySkipped}/{s.RangeEmpty}), range violations {s.RangeViolations}"
+ : ""));
private void ReportVoid(string label, RunStats s) => output.WriteLine(
$"IV-REPORT {label}: steps/px ref {s.PerRay(s.DenseSteps):F2}, masked {s.PerRay(s.MaskedSteps):F2}, LOD {s.PerRay(s.LodSteps):F2} ({(double)s.DenseSteps / s.LodSteps:F2}x fewer); "
@@ -1497,8 +2514,10 @@ public sealed class NoiseBoundTests
var scenarios = new (float Warp, Func Make)[]
{
- (FogField.AetheriaWarp, FogField.HeightFog), (FogField.AetheriaWarp, FogField.InsideFog),
- (FogField.AetheriaWarp, FogField.Wells), (SlabField.SlabWarp, SlabField.Create),
+ (FogField.AetheriaWarp, w => FogField.HeightFog(w, BoundMode.Interval)), (FogField.AetheriaWarp, w => FogField.InsideFog(w, BoundMode.Interval)),
+ (FogField.AetheriaWarp, w => FogField.DeepWell(w, BoundMode.Interval)), (FogField.AetheriaWarp, w => FogField.DeepWell(w, BoundMode.Affine)),
+ (FogField.AetheriaWarp, w => FogField.Wells(w, BoundMode.Interval)), (FogField.AetheriaWarp, w => FogField.Wells(w, BoundMode.Affine)),
+ (SlabField.SlabWarp, SlabField.Create),
};
foreach (var (warp, make) in scenarios)
foreach (var w in new[] { 0.0f, warp })
@@ -1513,34 +2532,41 @@ public sealed class NoiseBoundTests
}
///
- /// The proving ground (docs/cultmath-interval-ground-cut.md, "Pass 3" and "Pass 4"). Scenarios
- /// (a) height fog, (b) inside the fog, (c) Aetheria's wells and (d) r1's uniform slab, each over 64
- /// tiles at N in {1, 4, 8, 16} and warp in {0, D}: the tile march integrates exactly the dense march's
+ /// The proving ground (docs/cultmath-interval-ground-cut.md, "Pass 3", "Pass 4" and "Pass 5b").
+ /// Scenarios (a) height fog and (b) inside the fog under the centred-warp interval bound, (c) the deep
+ /// well and (c-band) the shallow wells each under the centred-warp interval bound and the affine bound
+ /// on the same seeds, and (d) r1's uniform slab, each over 64 tiles at N in {1, 4, 8, 16} and warp in
+ /// {0, D}; (c) and (c-band) also print the range ceiling at N = 8, and no range-mask cell is skipped: the tile march integrates exactly the dense march's
/// cells, so the transmittance agrees within 1e-3 (a difference would be a skipped cell that was not
/// empty), the oracle march (each ray over the oracle mask: the cells whose mid-depth density is nonzero
/// for at least one of the tile's rays) agrees with the dense march exactly, and no (a)-(d) tile reports
/// a body. (e) the void: the grid over hollow radius, camera offset and ramp width (32 tiles at N = 8),
/// LOD-far (32 tiles) and the one shipped void (200 tiles), three marches each, the footprint-aware one
- /// taking the analytic body step. Contracts at N = 8, the lower of warp 0 and D: (a) at least 2x
- /// combined cost; (c) (ruling wells-overhead-plus-floor) probe overhead, the tile march over the tile
- /// march plus its probes, at least 0.90, and, hard, the pre-pass proves at least half of the
- /// oracle-empty cells empty; the oracle ceiling, the efficiency against it and the cull fraction are
- /// printed; (e) at the shipped void the masked fixed-step march agrees with the reference exactly, the
+ /// taking the analytic body step. Contracts at N = 8: (a) at least 2x combined cost, the lower of warp
+ /// 0 and D; (c) (ruling affine-wells-contract-cheaper-than-interval) on the deep well the affine
+ /// bound's combined cost ratio exceeds the centred interval's at warp 0 and at warp D, and, hard
+ /// (ruling wells-overhead-plus-floor), the pre-pass proves at least half of the oracle-empty cells
+ /// empty under both bounds at both warps; probe overhead, the efficiency against the oracle and against
+ /// the range ceiling, the ceilings and the cull fraction are printed, not asserted; (c-band) is
+ /// printed only; (e) at the shipped void the masked fixed-step march agrees with the reference exactly, the
/// footprint-aware march's optical depth at the body start is off a converged march (h = 0.5, every
/// cell) by at most twice the fixed-step march's error, and it takes at most half the reference's
- /// steps per pixel. A shortfall skips naming saving-2x-scenarios and every shortfall; the fields, the
- /// grids and the envelope cost are not tuned toward it.
+ /// steps per pixel. A broken (c) contract fails the test; a shortfall of the (a) or (e) saving skips
+ /// naming saving-2x-scenarios and every such shortfall. The fields, the grids and the envelope cost are
+ /// not tuned toward either.
///
[Fact]
public void IntervalSkipHalvesEvaluations()
{
- var ratios = new Dictionary();
- var cullFloor = double.MaxValue;
+ var atEight = new Dictionary<(string Key, float Warp), RunStats>();
var scenarios = new (string Key, float Warp, Func Make)[]
{
- ("a", FogField.AetheriaWarp, FogField.HeightFog),
- ("b", FogField.AetheriaWarp, FogField.InsideFog),
- ("c", FogField.AetheriaWarp, FogField.Wells),
+ ("a", FogField.AetheriaWarp, w => FogField.HeightFog(w, BoundMode.Interval)),
+ ("b", FogField.AetheriaWarp, w => FogField.InsideFog(w, BoundMode.Interval)),
+ ("c interval", FogField.AetheriaWarp, w => FogField.DeepWell(w, BoundMode.Interval)),
+ ("c affine", FogField.AetheriaWarp, w => FogField.DeepWell(w, BoundMode.Affine)),
+ ("c-band interval", FogField.AetheriaWarp, w => FogField.Wells(w, BoundMode.Interval)),
+ ("c-band affine", FogField.AetheriaWarp, w => FogField.Wells(w, BoundMode.Affine)),
("d", SlabField.SlabWarp, SlabField.Create),
};
foreach (var (key, warp, make) in scenarios)
@@ -1548,19 +2574,39 @@ public sealed class NoiseBoundTests
foreach (var w in new[] { 0.0f, warp })
{
var field = make(w);
- var stats = Run(field, n, 64, 0x5A7E + n);
+ var stats = Run(field, n, 64, 0x5A7E + n, range: n == 8 && key.StartsWith('c'));
Report($"{field.Name} N={n} warp={w:R}", stats);
+ Assert.True(stats.RangeViolations == 0, $"{field.Name} N={n} warp={w:R}: the pre-pass skipped {stats.RangeViolations} cells where a sampled density is positive");
Assert.True(stats.MaxDifference <= 1.0e-3f, $"{field.Name} N={n} warp={w:R}: transmittance differs by {stats.MaxDifference:R}");
Assert.True(stats.MaxOracleDifference == 0.0f, $"{field.Name} N={n} warp={w:R}: the oracle march differs from the dense march by {stats.MaxOracleDifference:R}");
if (key == "d")
output.WriteLine($"IV-REPORT (d) N={n} warp={w:R}: ungated dense snoise/ray {3.0 * stats.PerRay(stats.DenseSteps):F2} (three per dense sample, as r1 counted)");
if (n == 8)
- ratios[key] = Math.Min(ratios.GetValueOrDefault(key, double.MaxValue), key == "c" ? stats.ProbeOverhead : stats.Ratio);
- if (n == 8 && key == "c")
+ atEight[(key, w)] = stats;
+ }
+
+ var warps = new[] { 0.0f, FogField.AetheriaWarp };
+ var costA = warps.Min(w => atEight[("a", w)].Ratio);
+ var cullFloor = double.MaxValue;
+ var gains = new List();
+ var shortfalls = new List();
+ var broken = new List();
+ foreach (var w in warps)
+ {
+ var interval = atEight[("c interval", w)];
+ var affine = atEight[("c affine", w)];
+ foreach (var (mode, stats) in new[] { ("interval", interval), ("affine", affine) })
{
- Assert.True(stats.CullFraction >= 0.5, $"(c) warp={w:R}: the pre-pass proves {stats.CullFraction:F3} of the oracle-empty cells empty, under the 0.5 floor (ruling wells-overhead-plus-floor)");
+ Assert.True(stats.CullFraction >= 0.5, $"(c) {mode} warp={w:R}: the pre-pass proves {stats.CullFraction:F3} of the oracle-empty cells empty, under the 0.5 floor (ruling wells-overhead-plus-floor)");
cullFloor = Math.Min(cullFloor, stats.CullFraction);
}
+
+ var band = (atEight[("c-band interval", w)], atEight[("c-band affine", w)]);
+ gains.Add($"warp {w:R}: (c) affine {affine.Ratio:F2}x against centred interval {interval.Ratio:F2}x ({affine.Ratio / interval.Ratio:F2}x), probe overhead {affine.ProbeOverhead:F3} and {interval.ProbeOverhead:F3}, "
+ + $"efficiency {affine.Efficiency:F3} and {interval.Efficiency:F3} against the oracle, {affine.RangeEfficiency:F3} and {interval.RangeEfficiency:F3} against the range ceiling {affine.RangeCeiling:F3}; "
+ + $"(c-band) {band.Item2.Ratio:F2}x against {band.Item1.Ratio:F2}x ({band.Item2.Ratio / band.Item1.Ratio:F2}x)");
+ if (!(affine.Ratio > interval.Ratio))
+ broken.Add($"(c) warp {w:R}: affine {affine.Ratio:F2}x is not cheaper than the centred interval's {interval.Ratio:F2}x");
}
foreach (var rh in VoidField.HollowRadii)
@@ -1581,15 +2627,15 @@ public sealed class NoiseBoundTests
Assert.True(headline.MaxLodDepthError <= 2.0 * headline.MaxRefDepthError, $"at the body start the footprint-aware march's optical depth is off the converged march's by {headline.MaxLodDepthError:G6} relative, more than twice the fixed-step march's {headline.MaxRefDepthError:G6}");
var steps = (double)headline.DenseSteps / headline.LodSteps;
- var shortfalls = new List();
- if (ratios["a"] < 2.0)
- shortfalls.Add($"(a) saves {ratios["a"]:F2}x combined cost, under 2x");
- if (ratios["c"] < 0.90)
- shortfalls.Add($"(c) probe overhead {ratios["c"]:F3}, under 0.90");
+ if (costA < 2.0)
+ shortfalls.Add($"(a) saves {costA:F2}x combined cost, under 2x");
if (steps < 2.0)
shortfalls.Add($"(e) takes {steps:F2}x fewer steps per pixel at the shipped void, under 2x");
- output.WriteLine($"IV-REPORT contracts at N=8 (lower of warp 0 and D): (a) {ratios["a"]:F2}x cost; (c) probe overhead {ratios["c"]:F3} (at least 0.90), cull fraction {cullFloor:F3} (at least 0.5, hard); "
+ output.WriteLine($"IV-REPORT contracts at N=8: (a) {costA:F2}x cost (lower of warp 0 and D, at least 2x); (c) affine cheaper than the centred interval at both warps, cull fraction {cullFloor:F3} (at least 0.5 under both bounds, hard); "
+ $"(e) {steps:F2}x fewer steps/px, depth error at the body start LOD {headline.MaxLodDepthError:G4} vs fixed-step {headline.MaxRefDepthError:G4} (at most 2x)");
+ foreach (var line in gains)
+ output.WriteLine($"IV-REPORT (c) at N=8, {line}");
+ Assert.True(broken.Count == 0, "ruling affine-wells-contract-cheaper-than-interval: " + string.Join("; ", broken));
if (shortfalls.Count > 0)
Assert.Skip("saving-2x-scenarios: " + string.Join("; ", shortfalls));
}
diff --git a/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json b/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json
index 775bbd83..2a81ae8e 100644
--- a/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json
+++ b/packages/cultmath/tests/CultMath.Tests/fixtures/glsl-parity.json
@@ -7866,6 +7866,4465 @@
"4256e995 c229166b c225166b -> c03e87af 404ed03a 3f250ae5 be5f05f6",
"40b5fd99 4206bfb4 41a57f66 -> 4007362a bf7b6b1a bf118d1e 3f2d6b64"
]
+ },
+ {
+ "glsl": "vec3 cultmath_af_point(float)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "c100e863 -> c100e863 00000000 00000000",
+ "c157318a -> c157318a 00000000 00000000",
+ "3fe21080 -> 3fe21080 00000000 00000000",
+ "40170740 -> 40170740 00000000 00000000",
+ "c10f7504 -> c10f7504 00000000 00000000",
+ "41180cbc -> 41180cbc 00000000 00000000",
+ "c1577606 -> c1577606 00000000 00000000",
+ "40af8864 -> 40af8864 00000000 00000000",
+ "c0006dc0 -> c0006dc0 00000000 00000000",
+ "40fea250 -> 40fea250 00000000 00000000",
+ "411f93f6 -> 411f93f6 00000000 00000000",
+ "419e382c -> 419e382c 00000000 00000000",
+ "c06c0b10 -> c06c0b10 00000000 00000000",
+ "41886cbe -> 41886cbe 00000000 00000000",
+ "40732908 -> 40732908 00000000 00000000",
+ "c0d8619c -> c0d8619c 00000000 00000000",
+ "c1607274 -> c1607274 00000000 00000000",
+ "408b9b40 -> 408b9b40 00000000 00000000",
+ "3ff0ee20 -> 3ff0ee20 00000000 00000000",
+ "41692bc0 -> 41692bc0 00000000 00000000",
+ "40a5c5f0 -> 40a5c5f0 00000000 00000000",
+ "402690c8 -> 402690c8 00000000 00000000",
+ "41326d56 -> 41326d56 00000000 00000000",
+ "411bb610 -> 411bb610 00000000 00000000",
+ "c03c2cd0 -> c03c2cd0 00000000 00000000",
+ "c10162e3 -> c10162e3 00000000 00000000",
+ "c169c276 -> c169c276 00000000 00000000",
+ "c0cccb2c -> c0cccb2c 00000000 00000000",
+ "c149162d -> c149162d 00000000 00000000",
+ "c1926dea -> c1926dea 00000000 00000000",
+ "c14ac648 -> c14ac648 00000000 00000000",
+ "c190b787 -> c190b787 00000000 00000000",
+ "4153a474 -> 4153a474 00000000 00000000",
+ "414332f0 -> 414332f0 00000000 00000000",
+ "c14e198b -> c14e198b 00000000 00000000",
+ "c0b05794 -> c0b05794 00000000 00000000",
+ "be7d3100 -> be7d3100 00000000 00000000",
+ "410da948 -> 410da948 00000000 00000000",
+ "41731d34 -> 41731d34 00000000 00000000",
+ "41206a28 -> 41206a28 00000000 00000000",
+ "407e7480 -> 407e7480 00000000 00000000",
+ "419dbc20 -> 419dbc20 00000000 00000000",
+ "3fde4680 -> 3fde4680 00000000 00000000",
+ "c09c7f94 -> c09c7f94 00000000 00000000",
+ "4018a490 -> 4018a490 00000000 00000000",
+ "40625700 -> 40625700 00000000 00000000",
+ "c0357360 -> c0357360 00000000 00000000",
+ "c157aec4 -> c157aec4 00000000 00000000",
+ "3e1a6400 -> 3e1a6400 00000000 00000000",
+ "c18b9397 -> c18b9397 00000000 00000000",
+ "bfb0efd0 -> bfb0efd0 00000000 00000000",
+ "c184437f -> c184437f 00000000 00000000",
+ "c0ad8f06 -> c0ad8f06 00000000 00000000",
+ "418e7d26 -> 418e7d26 00000000 00000000",
+ "410f9790 -> 410f9790 00000000 00000000",
+ "4115736a -> 4115736a 00000000 00000000",
+ "c0933dc0 -> c0933dc0 00000000 00000000",
+ "41408c00 -> 41408c00 00000000 00000000",
+ "c16b32fc -> c16b32fc 00000000 00000000",
+ "4198f6f0 -> 4198f6f0 00000000 00000000",
+ "40839e64 -> 40839e64 00000000 00000000",
+ "414eef90 -> 414eef90 00000000 00000000",
+ "bff92d10 -> bff92d10 00000000 00000000",
+ "c06cfe70 -> c06cfe70 00000000 00000000",
+ "3f2176e0 -> 3f2176e0 00000000 00000000",
+ "41010306 -> 41010306 00000000 00000000",
+ "c1573420 -> c1573420 00000000 00000000",
+ "40839498 -> 40839498 00000000 00000000",
+ "411ef306 -> 411ef306 00000000 00000000",
+ "c12b09f6 -> c12b09f6 00000000 00000000",
+ "4157c3f4 -> 4157c3f4 00000000 00000000",
+ "c0386ef0 -> c0386ef0 00000000 00000000",
+ "4112b06e -> 4112b06e 00000000 00000000",
+ "413db39a -> 413db39a 00000000 00000000",
+ "c1167161 -> c1167161 00000000 00000000",
+ "40aed570 -> 40aed570 00000000 00000000",
+ "c199124e -> c199124e 00000000 00000000",
+ "c07d4b80 -> c07d4b80 00000000 00000000",
+ "c14a7314 -> c14a7314 00000000 00000000",
+ "41585f0c -> 41585f0c 00000000 00000000",
+ "416bf9f8 -> 416bf9f8 00000000 00000000",
+ "4196f628 -> 4196f628 00000000 00000000",
+ "415730dc -> 415730dc 00000000 00000000",
+ "c171eeff -> c171eeff 00000000 00000000",
+ "40450898 -> 40450898 00000000 00000000",
+ "c1811fa5 -> c1811fa5 00000000 00000000",
+ "40eab0ec -> 40eab0ec 00000000 00000000",
+ "4176aa28 -> 4176aa28 00000000 00000000",
+ "c186324f -> c186324f 00000000 00000000",
+ "c00e33d0 -> c00e33d0 00000000 00000000",
+ "4198b98c -> 4198b98c 00000000 00000000",
+ "40f6fe78 -> 40f6fe78 00000000 00000000",
+ "40637110 -> 40637110 00000000 00000000",
+ "418097aa -> 418097aa 00000000 00000000",
+ "c161650a -> c161650a 00000000 00000000",
+ "4130ad92 -> 4130ad92 00000000 00000000",
+ "3fd4ef20 -> 3fd4ef20 00000000 00000000",
+ "c168f794 -> c168f794 00000000 00000000",
+ "4167a8c8 -> 4167a8c8 00000000 00000000",
+ "41652620 -> 41652620 00000000 00000000",
+ "c040d880 -> c040d880 00000000 00000000",
+ "4150d8dc -> 4150d8dc 00000000 00000000",
+ "c05a8728 -> c05a8728 00000000 00000000",
+ "c1128c7c -> c1128c7c 00000000 00000000",
+ "c12eeb24 -> c12eeb24 00000000 00000000",
+ "c194011f -> c194011f 00000000 00000000",
+ "c0b66eda -> c0b66eda 00000000 00000000",
+ "402e1380 -> 402e1380 00000000 00000000",
+ "40e6d758 -> 40e6d758 00000000 00000000",
+ "c183e994 -> c183e994 00000000 00000000",
+ "41079806 -> 41079806 00000000 00000000",
+ "419ada00 -> 419ada00 00000000 00000000",
+ "4095fe28 -> 4095fe28 00000000 00000000",
+ "c1039209 -> c1039209 00000000 00000000",
+ "c17a0c17 -> c17a0c17 00000000 00000000",
+ "40a7c5c8 -> 40a7c5c8 00000000 00000000",
+ "419bdf5a -> 419bdf5a 00000000 00000000",
+ "c0da6d46 -> c0da6d46 00000000 00000000",
+ "41537e3c -> 41537e3c 00000000 00000000",
+ "c04ea520 -> c04ea520 00000000 00000000",
+ "c19a2ab8 -> c19a2ab8 00000000 00000000",
+ "c10dde4a -> c10dde4a 00000000 00000000",
+ "3f62ee80 -> 3f62ee80 00000000 00000000",
+ "c0fb0008 -> c0fb0008 00000000 00000000",
+ "c11c7d0c -> c11c7d0c 00000000 00000000",
+ "c163bb46 -> c163bb46 00000000 00000000",
+ "41590800 -> 41590800 00000000 00000000",
+ "4151811c -> 4151811c 00000000 00000000",
+ "40be3148 -> 40be3148 00000000 00000000",
+ "bee3de80 -> bee3de80 00000000 00000000",
+ "c1819995 -> c1819995 00000000 00000000",
+ "4176d2f8 -> 4176d2f8 00000000 00000000",
+ "3fc822c0 -> 3fc822c0 00000000 00000000",
+ "c0df3266 -> c0df3266 00000000 00000000",
+ "c05dab50 -> c05dab50 00000000 00000000",
+ "c1926f73 -> c1926f73 00000000 00000000",
+ "40123860 -> 40123860 00000000 00000000",
+ "4026f560 -> 4026f560 00000000 00000000",
+ "417cfc24 -> 417cfc24 00000000 00000000",
+ "3fca2330 -> 3fca2330 00000000 00000000",
+ "4118f824 -> 4118f824 00000000 00000000",
+ "c1762c6c -> c1762c6c 00000000 00000000",
+ "c13cc183 -> c13cc183 00000000 00000000",
+ "419db744 -> 419db744 00000000 00000000",
+ "4114db06 -> 4114db06 00000000 00000000",
+ "419ddf8a -> 419ddf8a 00000000 00000000",
+ "c187bfec -> c187bfec 00000000 00000000",
+ "c10391b3 -> c10391b3 00000000 00000000",
+ "413b3b6a -> 413b3b6a 00000000 00000000",
+ "3f2b8120 -> 3f2b8120 00000000 00000000",
+ "4138eee0 -> 4138eee0 00000000 00000000",
+ "c1382b7a -> c1382b7a 00000000 00000000",
+ "c0f8eba4 -> c0f8eba4 00000000 00000000",
+ "c012b7c0 -> c012b7c0 00000000 00000000",
+ "41597b90 -> 41597b90 00000000 00000000",
+ "c16257d4 -> c16257d4 00000000 00000000",
+ "c0faac1a -> c0faac1a 00000000 00000000",
+ "c17921c6 -> c17921c6 00000000 00000000",
+ "c19b07b8 -> c19b07b8 00000000 00000000",
+ "c18597ef -> c18597ef 00000000 00000000",
+ "c1410a40 -> c1410a40 00000000 00000000",
+ "3f9a3bb0 -> 3f9a3bb0 00000000 00000000",
+ "4186361e -> 4186361e 00000000 00000000",
+ "c1457560 -> c1457560 00000000 00000000",
+ "419db000 -> 419db000 00000000 00000000",
+ "4150c50c -> 4150c50c 00000000 00000000",
+ "c00d4158 -> c00d4158 00000000 00000000",
+ "c10567b8 -> c10567b8 00000000 00000000",
+ "4173d8cc -> 4173d8cc 00000000 00000000",
+ "c18a9698 -> c18a9698 00000000 00000000",
+ "c188559b -> c188559b 00000000 00000000",
+ "c047fa98 -> c047fa98 00000000 00000000",
+ "c028cb20 -> c028cb20 00000000 00000000",
+ "c105c628 -> c105c628 00000000 00000000",
+ "40e6bd30 -> 40e6bd30 00000000 00000000",
+ "4180eb7e -> 4180eb7e 00000000 00000000",
+ "c1888e64 -> c1888e64 00000000 00000000",
+ "3f960300 -> 3f960300 00000000 00000000",
+ "403693d8 -> 403693d8 00000000 00000000",
+ "c1183c20 -> c1183c20 00000000 00000000",
+ "c18a1db6 -> c18a1db6 00000000 00000000",
+ "3fe4cdb0 -> 3fe4cdb0 00000000 00000000",
+ "c194dd26 -> c194dd26 00000000 00000000",
+ "c16b9f6f -> c16b9f6f 00000000 00000000",
+ "40ffe45c -> 40ffe45c 00000000 00000000",
+ "4174f850 -> 4174f850 00000000 00000000",
+ "404d2328 -> 404d2328 00000000 00000000",
+ "c18126db -> c18126db 00000000 00000000",
+ "bf114c40 -> bf114c40 00000000 00000000",
+ "c1151300 -> c1151300 00000000 00000000",
+ "41187728 -> 41187728 00000000 00000000",
+ "c0094088 -> c0094088 00000000 00000000",
+ "3ffe6640 -> 3ffe6640 00000000 00000000",
+ "41482c04 -> 41482c04 00000000 00000000",
+ "c0cb62b6 -> c0cb62b6 00000000 00000000",
+ "c13a4f54 -> c13a4f54 00000000 00000000",
+ "c14298aa -> c14298aa 00000000 00000000",
+ "c19ba612 -> c19ba612 00000000 00000000",
+ "c19ff8bd -> c19ff8bd 00000000 00000000",
+ "41820afc -> 41820afc 00000000 00000000",
+ "3ff87b50 -> 3ff87b50 00000000 00000000",
+ "4135e7e0 -> 4135e7e0 00000000 00000000",
+ "c05da9f8 -> c05da9f8 00000000 00000000",
+ "4110689a -> 4110689a 00000000 00000000",
+ "c01272e0 -> c01272e0 00000000 00000000",
+ "c0aa24f6 -> c0aa24f6 00000000 00000000",
+ "4132074e -> 4132074e 00000000 00000000",
+ "c19b57d5 -> c19b57d5 00000000 00000000",
+ "4127f378 -> 4127f378 00000000 00000000",
+ "418bd24a -> 418bd24a 00000000 00000000",
+ "c1889d86 -> c1889d86 00000000 00000000",
+ "412fe994 -> 412fe994 00000000 00000000",
+ "3fc9ca20 -> 3fc9ca20 00000000 00000000",
+ "41222cb0 -> 41222cb0 00000000 00000000",
+ "c19b7a38 -> c19b7a38 00000000 00000000",
+ "40c4b818 -> 40c4b818 00000000 00000000",
+ "be3f8f00 -> be3f8f00 00000000 00000000",
+ "41380bac -> 41380bac 00000000 00000000",
+ "beacf180 -> beacf180 00000000 00000000",
+ "c179984c -> c179984c 00000000 00000000",
+ "c12283bd -> c12283bd 00000000 00000000",
+ "c0c20540 -> c0c20540 00000000 00000000",
+ "4143ad0c -> 4143ad0c 00000000 00000000",
+ "4091d798 -> 4091d798 00000000 00000000",
+ "c0db48ac -> c0db48ac 00000000 00000000",
+ "40a349d8 -> 40a349d8 00000000 00000000",
+ "416e3494 -> 416e3494 00000000 00000000",
+ "409b4268 -> 409b4268 00000000 00000000",
+ "418ff59a -> 418ff59a 00000000 00000000",
+ "bf9290b0 -> bf9290b0 00000000 00000000",
+ "41046fa4 -> 41046fa4 00000000 00000000",
+ "c18ce852 -> c18ce852 00000000 00000000",
+ "3f958ed0 -> 3f958ed0 00000000 00000000",
+ "40d31df8 -> 40d31df8 00000000 00000000",
+ "4108b474 -> 4108b474 00000000 00000000",
+ "c10a234c -> c10a234c 00000000 00000000",
+ "c16bfbcc -> c16bfbcc 00000000 00000000",
+ "c0f445d0 -> c0f445d0 00000000 00000000",
+ "40f1fa90 -> 40f1fa90 00000000 00000000",
+ "c0d5f6ae -> c0d5f6ae 00000000 00000000",
+ "c17d0eff -> c17d0eff 00000000 00000000",
+ "4027e1d0 -> 4027e1d0 00000000 00000000",
+ "c0d48260 -> c0d48260 00000000 00000000",
+ "3ffa3530 -> 3ffa3530 00000000 00000000",
+ "c143d7f4 -> c143d7f4 00000000 00000000",
+ "419446c8 -> 419446c8 00000000 00000000",
+ "41823b4e -> 41823b4e 00000000 00000000",
+ "413da018 -> 413da018 00000000 00000000",
+ "413f2074 -> 413f2074 00000000 00000000",
+ "40efe534 -> 40efe534 00000000 00000000",
+ "4108aee8 -> 4108aee8 00000000 00000000",
+ "c06a9158 -> c06a9158 00000000 00000000",
+ "3f61b6a0 -> 3f61b6a0 00000000 00000000",
+ "4179a6d4 -> 4179a6d4 00000000 00000000",
+ "40cd336c -> 40cd336c 00000000 00000000",
+ "c13fedf5 -> c13fedf5 00000000 00000000"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_symbol(float, float)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "41991d6a 403fa9b6 -> 41991d6a 403fa9b6 00000000",
+ "c083e620 4049be5c -> c083e620 4049be5c 00000000",
+ "be51c380 c05b99e6 -> be51c380 c05b99e6 00000000",
+ "c18b4d6e c005ba72 -> c18b4d6e c005ba72 00000000",
+ "c12ccb11 c09bb534 -> c12ccb11 c09bb534 00000000",
+ "c122c845 406faa44 -> c122c845 406faa44 00000000",
+ "c19343e2 40132edc -> c19343e2 40132edc 00000000",
+ "3f657d80 c048db56 -> 3f657d80 c048db56 00000000",
+ "c18078ce c05a6c36 -> c18078ce c05a6c36 00000000",
+ "c19e44a7 3fe7079c -> c19e44a7 3fe7079c 00000000",
+ "c19b60b8 c01b999c -> c19b60b8 c01b999c 00000000",
+ "c04cf108 bfac63d0 -> c04cf108 bfac63d0 00000000",
+ "410d2e50 c087b5c2 -> 410d2e50 c087b5c2 00000000",
+ "414e80c0 c0180766 -> 414e80c0 c0180766 00000000",
+ "4124ff00 c000ec04 -> 4124ff00 c000ec04 00000000",
+ "3fc09f90 3fb21608 -> 3fc09f90 3fb21608 00000000",
+ "c19e855c 3e0a2680 -> c19e855c 3e0a2680 00000000",
+ "c0f8bc40 bfd74b04 -> c0f8bc40 bfd74b04 00000000",
+ "4183e814 406f3eec -> 4183e814 406f3eec 00000000",
+ "41584bb8 408f4574 -> 41584bb8 408f4574 00000000",
+ "3d135000 c092435f -> 3d135000 c092435f 00000000",
+ "c0e7dc90 c04c6d8c -> c0e7dc90 c04c6d8c 00000000",
+ "410b55d6 c09599d5 -> 410b55d6 c09599d5 00000000",
+ "412427dc c08a0734 -> 412427dc c08a0734 00000000",
+ "c1566540 3e8c51f0 -> c1566540 3e8c51f0 00000000",
+ "c0f36576 bfaef0c0 -> c0f36576 bfaef0c0 00000000",
+ "41763020 40998af2 -> 41763020 40998af2 00000000",
+ "c1492c84 400dd470 -> c1492c84 400dd470 00000000",
+ "c09a3414 c095e094 -> c09a3414 c095e094 00000000",
+ "c181b7fa bf4f6e28 -> c181b7fa bf4f6e28 00000000",
+ "c0d43550 40416c88 -> c0d43550 40416c88 00000000",
+ "3faa3470 408a1078 -> 3faa3470 408a1078 00000000",
+ "bf77e580 3f885970 -> bf77e580 3f885970 00000000",
+ "416cb4fc 3e86aea0 -> 416cb4fc 3e86aea0 00000000",
+ "c041cc10 c04602a5 -> c041cc10 c04602a5 00000000",
+ "c110ab7e c0303088 -> c110ab7e c0303088 00000000",
+ "c0e56fda c08d8a1a -> c0e56fda c08d8a1a 00000000",
+ "c14d0f82 4096e2a6 -> c14d0f82 4096e2a6 00000000",
+ "418c2a56 c026ceb5 -> 418c2a56 c026ceb5 00000000",
+ "40bcf084 3ff0c3f4 -> 40bcf084 3ff0c3f4 00000000",
+ "c0e726c2 40228f28 -> c0e726c2 40228f28 00000000",
+ "c180d113 c02c8b3e -> c180d113 c02c8b3e 00000000",
+ "419c635c c05073af -> 419c635c c05073af 00000000",
+ "4122dae6 c098104f -> 4122dae6 c098104f 00000000",
+ "c0dc6224 3f5735c0 -> c0dc6224 3f5735c0 00000000",
+ "4190ba44 40739150 -> 4190ba44 40739150 00000000",
+ "4132aee0 bf4f6300 -> 4132aee0 bf4f6300 00000000",
+ "40914b20 3ffe4d90 -> 40914b20 3ffe4d90 00000000",
+ "3ec65680 bf901e74 -> 3ec65680 bf901e74 00000000",
+ "410310ce c078d6e0 -> 410310ce c078d6e0 00000000",
+ "c157e8a6 c02cadf6 -> c157e8a6 c02cadf6 00000000",
+ "40b8c938 4097ceb2 -> 40b8c938 4097ceb2 00000000",
+ "c11dca43 c084c11a -> c11dca43 c084c11a 00000000",
+ "c1926039 40514454 -> c1926039 40514454 00000000",
+ "41402568 c036f1d2 -> 41402568 c036f1d2 00000000",
+ "41357fc4 c0664b54 -> 41357fc4 c0664b54 00000000",
+ "c09472d0 bf6f47b8 -> c09472d0 bf6f47b8 00000000",
+ "c1802414 3f4d58c0 -> c1802414 3f4d58c0 00000000",
+ "41030eb0 bffc5c6a -> 41030eb0 bffc5c6a 00000000",
+ "418dad1e bffe1554 -> 418dad1e bffe1554 00000000",
+ "416151d0 405cd59c -> 416151d0 405cd59c 00000000",
+ "c140f91c 4059bf8c -> c140f91c 4059bf8c 00000000",
+ "c127772c bf88799c -> c127772c bf88799c 00000000",
+ "c00b7da0 4080906a -> c00b7da0 4080906a 00000000",
+ "c00ee710 be436480 -> c00ee710 be436480 00000000",
+ "bfc36b30 3f018f90 -> bfc36b30 3f018f90 00000000",
+ "3fb103f0 3eba7900 -> 3fb103f0 3eba7900 00000000",
+ "3f825500 c08372b5 -> 3f825500 c08372b5 00000000",
+ "c179d574 c0713f8b -> c179d574 c0713f8b 00000000",
+ "41989f84 40812476 -> 41989f84 40812476 00000000",
+ "c16bb33c 4088cb48 -> c16bb33c 4088cb48 00000000",
+ "c1304606 c0773f40 -> c1304606 c0773f40 00000000",
+ "41404dac 4047bfdc -> 41404dac 4047bfdc 00000000",
+ "be0d5200 bfa2fe66 -> be0d5200 bfa2fe66 00000000",
+ "c0e7212e c0955851 -> c0e7212e c0955851 00000000",
+ "419e0c0c c03b9f17 -> 419e0c0c c03b9f17 00000000",
+ "c00da5d8 bf779228 -> c00da5d8 bf779228 00000000",
+ "c11a28b0 bfe97c80 -> c11a28b0 bfe97c80 00000000",
+ "c195da6e 4042a510 -> c195da6e 4042a510 00000000",
+ "41171490 4066728c -> 41171490 4066728c 00000000",
+ "40b2ba68 c065e145 -> 40b2ba68 c065e145 00000000",
+ "c09603d2 bfe7489c -> c09603d2 bfe7489c 00000000",
+ "41217b94 c02ae422 -> 41217b94 c02ae422 00000000",
+ "40872858 405e7778 -> 40872858 405e7778 00000000",
+ "4173e370 c09cb15f -> 4173e370 c09cb15f 00000000",
+ "bf96a2e0 3f5138e8 -> bf96a2e0 3f5138e8 00000000",
+ "c0deda76 c0937758 -> c0deda76 c0937758 00000000",
+ "c153576e 4087dda0 -> c153576e 4087dda0 00000000",
+ "409a3740 c084dcee -> 409a3740 c084dcee 00000000",
+ "c1934710 bf3cdc20 -> c1934710 bf3cdc20 00000000",
+ "417df878 c088b01b -> 417df878 c088b01b 00000000",
+ "4052c5a8 bf642480 -> 4052c5a8 bf642480 00000000",
+ "bf04e620 c01cce4f -> bf04e620 c01cce4f 00000000",
+ "c17c32a4 c06bfafa -> c17c32a4 c06bfafa 00000000",
+ "c10e882f c03af71f -> c10e882f c03af71f 00000000",
+ "c18d9848 bff8f50a -> c18d9848 bff8f50a 00000000",
+ "c090a838 c0753384 -> c090a838 c0753384 00000000",
+ "c117144a 409d1704 -> c117144a 409d1704 00000000",
+ "3fe4c3d0 4081af24 -> 3fe4c3d0 4081af24 00000000",
+ "c0b175a8 3f2cc738 -> c0b175a8 3f2cc738 00000000",
+ "c13bd452 3fbea680 -> c13bd452 3fbea680 00000000",
+ "beac5480 bff45bb4 -> beac5480 bff45bb4 00000000",
+ "40208ef0 bf60d888 -> 40208ef0 bf60d888 00000000",
+ "4173ce24 bf71eb20 -> 4173ce24 bf71eb20 00000000",
+ "c12a8d1b bfd3c7e0 -> c12a8d1b bfd3c7e0 00000000",
+ "40fc4c40 408f0280 -> 40fc4c40 408f0280 00000000",
+ "41293330 bff368d0 -> 41293330 bff368d0 00000000",
+ "41943d08 3f2af5a8 -> 41943d08 3f2af5a8 00000000",
+ "4015b548 4097039c -> 4015b548 4097039c 00000000",
+ "4154aa10 bcdb0e00 -> 4154aa10 bcdb0e00 00000000",
+ "c16eb17e be8386c0 -> c16eb17e be8386c0 00000000",
+ "4033fe98 3fddb520 -> 4033fe98 3fddb520 00000000",
+ "4190e6e8 c05659d8 -> 4190e6e8 c05659d8 00000000",
+ "c1435daa c03a39b7 -> c1435daa c03a39b7 00000000",
+ "4130259a c04d8577 -> 4130259a c04d8577 00000000",
+ "c099ba74 4009bd56 -> c099ba74 4009bd56 00000000",
+ "410f00f8 be8dff60 -> 410f00f8 be8dff60 00000000",
+ "c13362b6 c0215ac8 -> c13362b6 c0215ac8 00000000",
+ "405009c0 c01120bc -> 405009c0 c01120bc 00000000",
+ "415ed324 c0880c20 -> 415ed324 c0880c20 00000000",
+ "c0a138e8 40004824 -> c0a138e8 40004824 00000000",
+ "417e9224 408dade0 -> 417e9224 408dade0 00000000",
+ "3edc5800 c0793590 -> 3edc5800 c0793590 00000000",
+ "3fd29250 c0874fda -> 3fd29250 c0874fda 00000000",
+ "c15dad96 3ffc5c98 -> c15dad96 3ffc5c98 00000000",
+ "c02cfd20 3f3a4508 -> c02cfd20 3f3a4508 00000000",
+ "c188a5e5 4068fb48 -> c188a5e5 4068fb48 00000000",
+ "c01872d0 40149c88 -> c01872d0 40149c88 00000000",
+ "c186d632 404bc2cc -> c186d632 404bc2cc 00000000",
+ "c0b7f754 bf8304dc -> c0b7f754 bf8304dc 00000000",
+ "c134d879 3fdc0fb8 -> c134d879 3fdc0fb8 00000000",
+ "40a6bf38 c08e83d2 -> 40a6bf38 c08e83d2 00000000",
+ "41917ca4 409a3464 -> 41917ca4 409a3464 00000000",
+ "c130fbf7 c0050ce4 -> c130fbf7 c0050ce4 00000000",
+ "c18328d9 4009d4da -> c18328d9 4009d4da 00000000",
+ "419b5d7e c00971f4 -> 419b5d7e c00971f4 00000000",
+ "c170cbec 4024c252 -> c170cbec 4024c252 00000000",
+ "c17119a8 bf3be688 -> c17119a8 bf3be688 00000000",
+ "4043f410 3fa347c8 -> 4043f410 3fa347c8 00000000",
+ "c1580830 405b0360 -> c1580830 405b0360 00000000",
+ "409ea7b8 c074bdf4 -> 409ea7b8 c074bdf4 00000000",
+ "c18e4610 c0870458 -> c18e4610 c0870458 00000000",
+ "411db9d0 40449184 -> 411db9d0 40449184 00000000",
+ "40b61240 406605b0 -> 40b61240 406605b0 00000000",
+ "c195d19c bdffe7c0 -> c195d19c bdffe7c0 00000000",
+ "c153ae64 40283fa4 -> c153ae64 40283fa4 00000000",
+ "41856d78 befd5370 -> 41856d78 befd5370 00000000",
+ "4164c038 40015bb0 -> 4164c038 40015bb0 00000000",
+ "c1898bbe 405b99c8 -> c1898bbe 405b99c8 00000000",
+ "419c313e 3e93cfc0 -> 419c313e 3e93cfc0 00000000",
+ "4177c668 c020a0d1 -> 4177c668 c020a0d1 00000000",
+ "419bd8fe bf1e09c0 -> 419bd8fe bf1e09c0 00000000",
+ "41077350 c061cd54 -> 41077350 c061cd54 00000000",
+ "c0028b48 bfec1c38 -> c0028b48 bfec1c38 00000000",
+ "411a14f0 c09b918a -> 411a14f0 c09b918a 00000000",
+ "c15c607d befa8240 -> c15c607d befa8240 00000000",
+ "40c795f8 3e100f40 -> 40c795f8 3e100f40 00000000",
+ "412f29b6 c0800d42 -> 412f29b6 c0800d42 00000000",
+ "409527f8 3f05a138 -> 409527f8 3f05a138 00000000",
+ "c0f582e8 c061983c -> c0f582e8 c061983c 00000000",
+ "c0cd40b0 bfae034e -> c0cd40b0 bfae034e 00000000",
+ "c11969ab 3f835b18 -> c11969ab 3f835b18 00000000",
+ "3fec19f0 c03184a7 -> 3fec19f0 c03184a7 00000000",
+ "c0a899c2 3fddbd04 -> c0a899c2 3fddbd04 00000000",
+ "4180010c bf49d560 -> 4180010c bf49d560 00000000",
+ "c0b7c44a 4015633e -> c0b7c44a 4015633e 00000000",
+ "40b282d4 3faafbb0 -> 40b282d4 3faafbb0 00000000",
+ "41919e7c bfa016a4 -> 41919e7c bfa016a4 00000000",
+ "c16c6ff2 3f95eca0 -> c16c6ff2 3f95eca0 00000000",
+ "c0aaf800 3f7e1c90 -> c0aaf800 3f7e1c90 00000000",
+ "c0b59754 bfddd188 -> c0b59754 bfddd188 00000000",
+ "c1740f40 c09a4012 -> c1740f40 c09a4012 00000000",
+ "c0d73d7e 400ba1e4 -> c0d73d7e 400ba1e4 00000000",
+ "c17b8b58 bf789818 -> c17b8b58 bf789818 00000000",
+ "40e257bc 4024dabe -> 40e257bc 4024dabe 00000000",
+ "c1849c26 3e380360 -> c1849c26 3e380360 00000000",
+ "3fb2d9c0 4059fab4 -> 3fb2d9c0 4059fab4 00000000",
+ "c146e5b0 3e6c8100 -> c146e5b0 3e6c8100 00000000",
+ "419c646c bf93f71c -> 419c646c bf93f71c 00000000",
+ "417afa54 bde10140 -> 417afa54 bde10140 00000000",
+ "41327f8e 40307eac -> 41327f8e 40307eac 00000000",
+ "c05840d0 bfe6eb70 -> c05840d0 bfe6eb70 00000000",
+ "40c97e20 bf470ef0 -> 40c97e20 bf470ef0 00000000",
+ "41476e50 c098d96e -> 41476e50 c098d96e 00000000",
+ "40170fe8 bf8195f2 -> 40170fe8 bf8195f2 00000000",
+ "41962ab8 409fced8 -> 41962ab8 409fced8 00000000",
+ "c1491bb2 4005b768 -> c1491bb2 4005b768 00000000",
+ "4139336c c09bdbca -> 4139336c c09bdbca 00000000",
+ "c122f268 c024e987 -> c122f268 c024e987 00000000",
+ "c112b3b5 4051e158 -> c112b3b5 4051e158 00000000",
+ "c175f94f 4094ec92 -> c175f94f 4094ec92 00000000",
+ "419ed952 c064d8a6 -> 419ed952 c064d8a6 00000000",
+ "c0d27a18 40589da4 -> c0d27a18 40589da4 00000000",
+ "c140f7fb 403f46b6 -> c140f7fb 403f46b6 00000000",
+ "c00e71e8 bf2e2c58 -> c00e71e8 bf2e2c58 00000000",
+ "c091a858 401d8b9c -> c091a858 401d8b9c 00000000",
+ "410ffbfc 40718c08 -> 410ffbfc 40718c08 00000000",
+ "414d0798 3f52d6a8 -> 414d0798 3f52d6a8 00000000",
+ "418393b8 403f6678 -> 418393b8 403f6678 00000000",
+ "c0b27e6a 4083127e -> c0b27e6a 4083127e 00000000",
+ "418219cc c084ec3e -> 418219cc c084ec3e 00000000",
+ "415c1600 c00e092a -> 415c1600 c00e092a 00000000",
+ "41388550 c0846afd -> 41388550 c0846afd 00000000",
+ "c0d6c82e 4050a3d4 -> c0d6c82e 4050a3d4 00000000",
+ "c18f9c5c c04f2e1c -> c18f9c5c c04f2e1c 00000000",
+ "c10e458a 401db262 -> c10e458a 401db262 00000000",
+ "c17747da c08b7383 -> c17747da c08b7383 00000000",
+ "c0a21d74 4048a668 -> c0a21d74 4048a668 00000000",
+ "4132cc08 c011378d -> 4132cc08 c011378d 00000000",
+ "419ae3aa 404c216c -> 419ae3aa 404c216c 00000000",
+ "c130cbc2 c09bec34 -> c130cbc2 c09bec34 00000000",
+ "4047a678 c06eb0f0 -> 4047a678 c06eb0f0 00000000",
+ "c19bfb67 c0313630 -> c19bfb67 c0313630 00000000",
+ "c1105e4e bff54f78 -> c1105e4e bff54f78 00000000",
+ "4178afd0 c03b823c -> 4178afd0 c03b823c 00000000",
+ "c17edf04 bf096380 -> c17edf04 bf096380 00000000",
+ "417455ac bfb1b162 -> 417455ac bfb1b162 00000000",
+ "4186d6e0 c0961069 -> 4186d6e0 c0961069 00000000",
+ "c1723cda 400bbbce -> c1723cda 400bbbce 00000000",
+ "c0babbf0 c0206713 -> c0babbf0 c0206713 00000000",
+ "3e803780 bfa3379a -> 3e803780 bfa3379a 00000000",
+ "411e7f6c c0146e5d -> 411e7f6c c0146e5d 00000000",
+ "c15d458c 3fb2f2e8 -> c15d458c 3fb2f2e8 00000000",
+ "40a9a6ec 3fcdc600 -> 40a9a6ec 3fcdc600 00000000",
+ "3e26b100 c09dcf69 -> 3e26b100 c09dcf69 00000000",
+ "4141e9a0 3fb0bdf8 -> 4141e9a0 3fb0bdf8 00000000",
+ "41499f24 3ed4fae0 -> 41499f24 3ed4fae0 00000000",
+ "40ede17c 407c0c00 -> 40ede17c 407c0c00 00000000",
+ "3e87bcc0 400ac6f0 -> 3e87bcc0 400ac6f0 00000000",
+ "c116125c 3f26ee08 -> c116125c 3f26ee08 00000000",
+ "41478854 c0985e2d -> 41478854 c0985e2d 00000000",
+ "418bfa00 405c4984 -> 418bfa00 405c4984 00000000",
+ "c188278c 40541358 -> c188278c 40541358 00000000",
+ "41695cb0 402190d8 -> 41695cb0 402190d8 00000000",
+ "c16494c7 bfc9dbd0 -> c16494c7 bfc9dbd0 00000000",
+ "40f5c684 c08c77e3 -> 40f5c684 c08c77e3 00000000",
+ "41861336 40162e66 -> 41861336 40162e66 00000000",
+ "c0efc09c 4060d00c -> c0efc09c 4060d00c 00000000",
+ "c11657d4 bff3500a -> c11657d4 bff3500a 00000000",
+ "41974a4e bfa2e084 -> 41974a4e bfa2e084 00000000",
+ "4067d968 3f917d60 -> 4067d968 3f917d60 00000000",
+ "4142bd80 40744ea4 -> 4142bd80 40744ea4 00000000",
+ "c075af70 beb9f000 -> c075af70 beb9f000 00000000",
+ "40a80ff8 bfcc935e -> 40a80ff8 bfcc935e 00000000",
+ "40e06d20 c0972f1e -> 40e06d20 c0972f1e 00000000",
+ "3f7a1480 bf740f20 -> 3f7a1480 bf740f20 00000000",
+ "bff18eb0 4038e688 -> bff18eb0 4038e688 00000000",
+ "c01fbda0 be341ea0 -> c01fbda0 be341ea0 00000000",
+ "c0263f40 40811af4 -> c0263f40 40811af4 00000000",
+ "c1441f46 bfe2b1c4 -> c1441f46 bfe2b1c4 00000000",
+ "41301cc2 407342a0 -> 41301cc2 407342a0 00000000",
+ "3f377c80 c0587754 -> 3f377c80 c0587754 00000000",
+ "c0ed0428 401ad968 -> c0ed0428 401ad968 00000000",
+ "410c3892 c08647a0 -> 410c3892 c08647a0 00000000",
+ "c12d8054 405620b4 -> c12d8054 405620b4 00000000",
+ "40a4c7a8 c0421a14 -> 40a4c7a8 c0421a14 00000000"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_from_iv(vec2)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "4104ebdf 413378c5 -> 411c3252 00000000 3fba33f2",
+ "4197e194 4197e394 -> 4197e294 00000000 3a04bf1d",
+ "c1337a3e c1337976 -> c13379da 00000000 38de6f48",
+ "c01cca84 c0158a7c -> c0192a80 00000000 3d680373",
+ "c1404a76 c13f9ed2 -> c13ff4a4 00000000 3cabbc09",
+ "c187533f c1875279 -> c18752dc 00000000 3956ea68",
+ "414b6b37 414b7669 -> 414b70d0 00000000 3ab4b6ed",
+ "408a824b 408a85f5 -> 408a8420 00000000 396ed430",
+ "c10d3886 c0ed17bd -> c101e232 00000000 3f3565c9",
+ "c056b53c c0564be4 -> c0568090 00000000 3b52e5ad",
+ "c176f478 c1741d08 -> c17588c0 00000000 3db5e3b8",
+ "406e6178 40829b34 -> 4079cbf0 00000000 3e36a885",
+ "c1820399 c180b57f -> c1815c8c 00000000 3da71520",
+ "4024b8c4 4031ccec -> 402b42d8 00000000 3dd143e4",
+ "411c1508 411cfdd4 -> 411c896e 00000000 3ce8dfa0",
+ "c182c9d8 c16bff08 -> c178c95c 00000000 3f4ca646",
+ "c08195f2 c081724e -> c0818420 00000000 3b0ed0cb",
+ "40cc912d 40ce966b -> 40cd93cc 00000000 3d0155f5",
+ "41491e26 4149249a -> 41492160 00000000 3a51a492",
+ "c117d836 c117b7ea -> c117c810 00000000 3b817bec",
+ "bfc13aab bfb6bcd5 -> bfbbfbc0 00000000 3d27dee2",
+ "c17167ea c1716092 -> c171643e 00000000 3a6ec5a0",
+ "4141d33c 4141fd74 -> 4141e858 00000000 3ba940ff",
+ "c0c7d0d8 c0c7cfb8 -> c0c7d048 00000000 389c7d0e",
+ "c16b1d21 c169b42d -> c16a68a7 00000000 3d3488b2",
+ "41353eca 4135671a -> 413552f2 00000000 3ba19ab4",
+ "c0510e5d c050eae3 -> c050fca0 00000000 3a8e5087",
+ "c18648f9 c186485d -> c18648ab 00000000 392cc91f",
+ "c1031961 c10310cd -> c1031517 00000000 3a8a4633",
+ "c17f1a84 c17ddffe -> c17e7d41 00000000 3d1d52f2",
+ "bf562c5e bd73e218 -> bee56a80 00000000 3ec6ee57",
+ "4168fcdb 416bce1d -> 416a657c 00000000 3db457de",
+ "c05e4d83 c05e349d -> c05e4110 00000000 3a480e4e",
+ "410a51af 410ac559 -> 410a8b84 00000000 3c6776b1",
+ "40a23995 40a23b03 -> 40a23a4c 00000000 38c123b0",
+ "c0ebc3c1 c0ebc22b -> c0ebc2f6 00000000 38d9bc3c",
+ "402ca56f 402ca7f1 -> 402ca6b0 00000000 38a5e540",
+ "417e925a 417f511e -> 417ef1bc 00000000 3cbee3ea",
+ "3f8a3515 3f8ae6cb -> 3f8a8df0 00000000 3b31c75d",
+ "41813a8b 418390d9 -> 418265b2 00000000 3e15979d",
+ "c10148fd c1007d15 -> c100e309 00000000 3ccbf829",
+ "3f91114d 3f9124f3 -> 3f911b20 00000000 399dc125",
+ "4128571f 412e3175 -> 412b444a 00000000 3e3b4d79",
+ "c046afa3 c046a82d -> c046abe8 00000000 3971dabf",
+ "c1223e78 c1212826 -> c121b34f 00000000 3d0b3324",
+ "c116edf2 c116075a -> c1167aa6 00000000 3ce6aade",
+ "c16a61a6 c16615f4 -> c1683bcd 00000000 3e0979ea",
+ "4177d404 417c1844 -> 4179f624 00000000 3e088bf0",
+ "410a5c85 410abc2f -> 410a8c5a 00000000 3c3f76af",
+ "41577b2e 4158921a -> 415806a4 00000000 3d0b8389",
+ "40d0928a 4105fc53 -> 40ee4598 00000000 3f6d98f6",
+ "c07e1b42 c07e16de -> c07e1910 00000000 3910786d",
+ "c1148d0b c10dbea5 -> c11125d8 00000000 3e59cf12",
+ "4153e3da 415404f6 -> 4153f468 00000000 3b84da02",
+ "c0a8de2f c0a72281 -> c0a80058 00000000 3cdde18e",
+ "bd972560 40ae28ee -> 402bcc58 00000000 4030859a",
+ "c0b7a179 c0b7465b -> c0b773ea 00000000 3bb669e8",
+ "c13a76d0 c0c240e9 -> c10dcba2 00000000 4032ace6",
+ "c123050d c11d4c6d -> c12028bd 00000000 3e37168c",
+ "4171a43b 4176bb75 -> 41742fd8 00000000 3e22eb1b",
+ "4148438c 41499b3c -> 4148ef64 00000000 3d2be49a",
+ "c12497a5 c12496d3 -> c124973c 00000000 38e692f5",
+ "412fe85d 413ab07f -> 41354c6e 00000000 3eac8395",
+ "4178971c 4190c71e -> 41868956 00000000 3fa3dd11",
+ "c162637e c1625eba -> c162611c 00000000 3a1c098e",
+ "414af8b3 414af975 -> 414af914 00000000 38db5f2f",
+ "3ebd7340 3ec00ac0 -> 3ebebf00 00000000 3b25e600",
+ "c19dd647 c19db3f1 -> c19dc51c 00000000 3c09a6eb",
+ "c167616a c1671e66 -> c1673fe8 00000000 3c0641d8",
+ "4174b643 4174b6ed -> 4174b698 00000000 38c896de",
+ "417423d8 41742480 -> 4174242c 00000000 38c68490",
+ "4125c05f 412ad8b9 -> 41284c8c 00000000 3e230deb",
+ "419fc511 419fcce7 -> 419fc8fc 00000000 3afd3f34",
+ "c147b2fc c140b936 -> c1443619 00000000 3e5f3bdf",
+ "c0c7e582 bf954638 -> c06d3710 00000000 4022940d",
+ "c0254660 c02544a0 -> c0254580 00000000 386a5466",
+ "406bdb29 406be317 -> 406bdf20 00000000 3980b7c6",
+ "4121b3e4 4121b534 -> 4121b48c 00000000 39321b53",
+ "408ddea6 408e07ea -> 408df348 00000000 3b255704",
+ "c0fd9af4 c0fc8090 -> c0fd0dc2 00000000 3c8d41da",
+ "4116ac26 417026b2 -> 4143696c 00000000 4032f554",
+ "c1297450 c12971dc -> c1297316 00000000 39a24ba2",
+ "4112a44e 41133c02 -> 4112f028 00000000 3c97c668",
+ "c01c1fa4 c01c1dac -> c01c1ea8 00000000 3882e0fd",
+ "c094a2c1 c04b175d -> c07a2e70 00000000 3f3c5c94",
+ "413e2f18 414f8668 -> 4146dac0 00000000 3f0abb50",
+ "41457ba4 415ec09c -> 41521e20 00000000 3f4a289f",
+ "414654b3 41521145 -> 414c32fc 00000000 3ebbcac4",
+ "414d894b 414e5be5 -> 414df298 00000000 3cd2b3cb",
+ "c18c9306 c18c66de -> c18c7cf2 00000000 3c30e64a",
+ "40390b34 40391a3c -> 403912b8 00000000 39f1f234",
+ "bf838ad0 bf836810 -> bf837970 00000000 3a0b41c5",
+ "41289fae 413adac2 -> 4131bd38 00000000 3f11d95b",
+ "bfc6e47c bfc5f644 -> bfc66d60 00000000 3b6e50dd",
+ "3febc758 40a6d9da -> 4061cbb0 00000000 3fd7d032",
+ "414dea2c 415d97ac -> 4155c0ec 00000000 3efad9bb",
+ "c1662aa0 c1660bf4 -> c1661b4a 00000000 3b76462b",
+ "c14d2d19 c1041555 -> c128a137 00000000 40122fbb",
+ "4142bd5c 41447b44 -> 41439c50 00000000 3d5f0048",
+ "41969e37 4196d515 -> 4196b9a6 00000000 3c5bc36b",
+ "41719d23 4171a04d -> 41719eb8 00000000 39d20d02",
+ "c0e06397 c0de05d5 -> c0df34b6 00000000 3d177783",
+ "c16d9b9c c16b6344 -> c16c7f70 00000000 3d8e1d6d",
+ "c1530702 c149c5fa -> c14e667e 00000000 3e941226",
+ "c133c0db c0551893 -> c0e90700 00000000 407cf599",
+ "c10d0f63 c10d0e7b -> c10d0eef 00000000 38f9a1ec",
+ "c11930e9 c1011801 -> c10d2475 00000000 3f40c7d9",
+ "418acccc 418bba1c -> 418b4374 00000000 3d6d6177",
+ "bf7dfc63 bf7df31d -> bf7df7c0 00000000 38965bf9",
+ "c0dac064 c03bc918 -> c09c5278 00000000 3ff9b7e7",
+ "c18f34e5 c18f3473 -> c18f34ac 00000000 3903e69d",
+ "c03a4ab9 c03857f7 -> c0395158 00000000 3c796ca5",
+ "419fdc52 419fdc8e -> 419fdc70 00000000 389ff724",
+ "40d4ddad 40d5753b -> 40d52974 00000000 3c17a8af",
+ "4030e6b6 40afb00d -> 408411b4 00000000 3fae7990",
+ "419593b9 41959623 -> 419594ee 00000000 3a1f2cb1",
+ "4033df13 4038b0fd -> 40364808 00000000 3d1a4023",
+ "40640da1 4064a7bf -> 40645ab0 00000000 3b9a3a95",
+ "41515e4a 418223d7 -> 416ad2fc 00000000 3fcba612",
+ "c1881f10 c1881dec -> c1881e7e 00000000 399a81f1",
+ "40a5b67e 40b0e952 -> 40ab4fe8 00000000 3e332ea2",
+ "c18f0c17 c18e29eb -> c18e9b01 00000000 3d623de2",
+ "409686be 40abfd7a -> 40a1421c 00000000 3eabb68c",
+ "3f3fc0a1 3f409bdf -> 3f402e40 00000000 3adb5613",
+ "c01ea3fb c0163b25 -> c01a6f90 00000000 3d868e9d",
+ "c006d9be bfad2743 -> bfdd6d60 00000000 3ec118b5",
+ "c12d1e94 c12d1dd4 -> c12d1e34 00000000 38d5a3d2",
+ "c04f7580 c006f7d0 -> c02b36a8 00000000 3f10fb94",
+ "4114d64d 412b2903 -> 411fffa8 00000000 3f32965b",
+ "403dfb10 403e0170 -> 403dfe40 00000000 394ef806",
+ "4192250c 41957b68 -> 4193d03a 00000000 3e559bac",
+ "c16095e9 c1605b7f -> c16078b4 00000000 3bea184b",
+ "c19c1df6 c19c1d86 -> c19c1dbe 00000000 390383bf",
+ "be8891c0 3d849902 -> bdced6ff 00000000 3e29b811",
+ "c122ba2d c121ebad -> c12252ed 00000000 3cce9457",
+ "411cc4d2 411df6c6 -> 411d5dcc 00000000 3d1903df",
+ "4191c1bc 4191c494 -> 4191c328 00000000 3a3a8e25",
+ "c10a03f4 c109ee8a -> c109f93f 00000000 3b2bda04",
+ "c1a1064b c19711db -> c19c0c13 00000000 3f1f4842",
+ "416d3e2e 416d4442 -> 416d4138 00000000 3a463511",
+ "be827828 be7e5ab1 -> be80d2c0 00000000 3b52b7f4",
+ "c1bb2c17 c17809d6 -> c19b9881 00000000 407c9d0e",
+ "c032503f c0324151 -> c03248c8 00000000 39f044a0",
+ "419b0415 419b542b -> 419b2c20 00000000 3ca052d5",
+ "c16b31f2 c15eb87e -> c164f538 00000000 3ec79916",
+ "40b932c6 40b9340a -> 40b93368 00000000 38ad9341",
+ "c11fb5df c07a61ec -> c0de4e5a 00000000 40423af0",
+ "c1646837 c12bc8a5 -> c148186e 00000000 3fe27eba",
+ "4014398f 401c9d81 -> 40186b88 00000000 3d864059",
+ "4074f671 407909cf -> 40770020 00000000 3d026fa4",
+ "c11e0eb3 c10b1cbd -> c11495b8 00000000 3f17904e",
+ "c199cd1a c180bf00 -> c18d460d 00000000 3fc8716a",
+ "415d3a58 41833304 -> 4171d030 00000000 3fa4af43",
+ "414ccc73 414cccdd -> 414ccca8 00000000 3883999c",
+ "412bbd47 412bbe6d -> 412bbdda 00000000 391dbbe7",
+ "411ade0b 41632c01 -> 413f0506 00000000 40109c25",
+ "41929bf3 4192a635 -> 4192a114 00000000 3b25454c",
+ "409d7acc 40a0b094 -> 409f15b0 00000000 3d4d7706",
+ "410695f6 410698da -> 41069768 00000000 39bd34c7",
+ "c1a4e4d7 c19acc9b -> c19fd8b9 00000000 3f21850a",
+ "c1a5bc8f c14dc94a -> c186509a 00000000 407b5ffb",
+ "401d9b65 401f01cb -> 401e4e98 00000000 3c333cf0",
+ "417a8e91 41800c94 -> 417d53dc 00000000 3e3156e0",
+ "c17008f6 c0a430df -> c12110b3 00000000 409df0a4",
+ "c192d411 c192c4c5 -> c192cc6b 00000000 3b75e5a8",
+ "4135c796 4135eb9a -> 4135d998 00000000 3b906af6",
+ "c131a02c c13191a8 -> c13198ea 00000000 3ae9a340",
+ "419442a1 41963f5f -> 41954100 00000000 3dfe6864",
+ "c0fc01d4 c0fbfec4 -> c0fc004c 00000000 394be00f",
+ "c17f663c c17e8474 -> c17ef558 00000000 3ce1e7ed",
+ "c114836d bf768210 -> c0a3eb8e 00000000 40851b5f",
+ "41200f2e 41200fee -> 41200f8e 00000000 38d401fe",
+ "41981756 419b0d6e -> 41999262 00000000 3e3d8ad8",
+ "c1a8a951 c1489276 -> c1867946 00000000 4088c056",
+ "c0d7f925 c0d5372f -> c0d6982a 00000000 3d308440",
+ "c1406810 c14043aa -> c14055dd 00000000 3b91f834",
+ "409150d7 40a9ab79 -> 409d7e28 00000000 3ec2d5ba",
+ "bf47a777 bf46f149 -> bf474c60 00000000 3ab646f5",
+ "c11ee6d3 c11d7787 -> c11e2f2d 00000000 3d37afee",
+ "c19eef5e c19eedec -> c19eeea5 00000000 39c2eef6",
+ "4096ce09 40bf9d97 -> 40ab35d0 00000000 3f233e98",
+ "41930c6e 41931f7a -> 419315f4 00000000 3b98f31f",
+ "c0f9653c c0f909b4 -> c0f93778 00000000 3bb74e59",
+ "41040c46 4106d69e -> 41057172 00000000 3db29a37",
+ "c0f70d58 c0195af9 -> c0a1dd6a 00000000 402a5ffb",
+ "c102960b c101103d -> c101d324 00000000 3d42ef29",
+ "c18a41c9 c18a1c6d -> c18a2f1b 00000000 3c15b521",
+ "c00474db c0046fe5 -> c0047260 00000000 3920d1d3",
+ "c12dc27f c12d32c9 -> c12d7aa4 00000000 3c8fcbb8",
+ "bef4649c bef3f9e4 -> bef42f40 00000000 39d5ad19",
+ "40a3f920 40a409d8 -> 40a4017c 00000000 3a86640a",
+ "40d4dad7 40d573b1 -> 40d52744 00000000 3c18f4ae",
+ "c14ff822 c14fd1ba -> c14fe4ee 00000000 3b9a07fc",
+ "4129f846 412a3e02 -> 412a1b24 00000000 3c0ba290",
+ "4150d776 4154c07a -> 4152cbf8 00000000 3dfa47a6",
+ "c048a23e c0313cd2 -> c03cef88 00000000 3e3b2c29",
+ "c18e9d3c c1545a17 -> c178ca48 00000000 4011c109",
+ "41846a38 4184de78 -> 4184a458 00000000 3ce8a138",
+ "c1983990 c1982d2a -> c198335d 00000000 3b479073",
+ "411dd735 411efa1b -> 411e68a8 00000000 3d117cf0",
+ "c19e66da c19e496e -> c19e5824 00000000 3bebfe67",
+ "40904532 40908bce -> 40906880 00000000 3b8d5c23",
+ "c10747e9 c1059c19 -> c1067201 00000000 3d55f074",
+ "c0e469a3 c0e463c9 -> c0e466b6 00000000 39bed1a7",
+ "c0dc442f c0dbffd1 -> c0dc2200 00000000 3b88f311",
+ "c18ef03d c18abfc3 -> c18cd800 00000000 3e86117c",
+ "c18451e6 c1743803 -> c17e6de8 00000000 3f235f51",
+ "3fd593aa 3fd68076 -> 3fd60a10 00000000 3b6ce6d0",
+ "c15d537c c15cc98c -> c15d0e84 00000000 3c8a0baa",
+ "c150d04f c1177491 -> c1342270 00000000 3fe56f60",
+ "40b816f0 40b827b8 -> 40b81f54 00000000 3a86f828",
+ "4149b509 414e88f7 -> 414c1f00 00000000 3e1a80fa",
+ "3f38657b 3f4dd385 -> 3f431c80 00000000 3d2b711e",
+ "bf1f7bc5 bf1f5c3b -> bf1f6c00 00000000 397cef7c",
+ "bcdd8000 4042cd20 -> 3fc11220 00000000 3fc48838",
+ "c192388d c17f8e35 -> c188ffd4 00000000 3f938c26",
+ "410850a0 41466b80 -> 41275e10 00000000 3ff86be3",
+ "c14ebf01 c14ebb0f -> c14ebd08 00000000 3a017afc",
+ "40bee0cf 40bef541 -> 40beeb08 00000000 3aa44ef5",
+ "c1577504 c1564e60 -> c156e1b2 00000000 3d135f77",
+ "c189115f c188501b -> c188b0bd 00000000 3d415522",
+ "c1747cba c17437e6 -> c1745a50 00000000 3c09e51f",
+ "409297c4 409adacc -> 4096b948 00000000 3e0431b6",
+ "408ceebe 408d05da -> 408cfa4c 00000000 3ab96d06",
+ "c08dc506 c08c1d62 -> c08cf134 00000000 3cd3dadc",
+ "c08579c6 c08437ba -> c084d8c0 00000000 3ca10e58",
+ "c173f891 c15b94b9 -> c167c6a5 00000000 3f431fb4",
+ "41866291 418a87b7 -> 41887524 00000000 3e84a6ea",
+ "40252358 40cd7c44 -> 409006f8 00000000 3ff5d563",
+ "4168db49 416e3d37 -> 416b8c40 00000000 3e2c4179",
+ "c1739fd2 c1739c5e -> c1739e18 00000000 39e49cff",
+ "40aa2983 40aa9dfd -> 40aa63c0 00000000 3be91ea7",
+ "c0f02106 c0f019f2 -> c0f01d7c 00000000 39e64084",
+ "419a5528 419a56e0 -> 419a5604 00000000 39e5a56e",
+ "40b88455 40b8afe3 -> 40b89a1c 00000000 3b2e9458",
+ "40f6f313 41217dba -> 410e7ba2 00000000 3f981113",
+ "c0cdfe51 c0c87c83 -> c0cb3d6a 00000000 3db03cf8",
+ "41585a38 41585af0 -> 41585a94 00000000 38d30b5e",
+ "c163d816 c163b9c6 -> c163c8ee 00000000 3b7363d8",
+ "c18d15d9 c180e221 -> c186fbfd 00000000 3f433c9a",
+ "4197cf46 4197d132 -> 4197d03c 00000000 39ff7d13",
+ "40a49c60 41695544 -> 411dd1ba 00000000 40970731",
+ "3ca6fad8 3da0eb4a -> 3d4aaa00 00000000 3cee5950",
+ "40e906b6 4137e6d1 -> 41163516 00000000 4006c71a",
+ "419d2dfb 419d4c4d -> 419d3d24 00000000 3bf32d4c",
+ "4048bf51 406616ef -> 40576b20 00000000 3e6abdd6",
+ "c0637be9 c0623937 -> c062da90 00000000 3c216738",
+ "c052ad0c bf0b8bd2 -> bff59000 00000000 3fafca32",
+ "4192b1be 4194e366 -> 4193ca92 00000000 3e0c6ea7",
+ "c16b33f9 c16af9d3 -> c16b16e6 00000000 3be90d9a",
+ "40ffe513 41002977 -> 41000e00 00000000 3bdbf615",
+ "40bab098 40bab1f8 -> 40bab148 00000000 38bbab20",
+ "414c8967 414d2e71 -> 414cdbec 00000000 3ca523a6",
+ "c14e81cd c14e0d6f -> c14e479e 00000000 3c68efa0",
+ "4195c5e3 41a94f19 -> 419f8a7e 00000000 3f9c4a59",
+ "407ce2c7 407cfc59 -> 407cef90 00000000 3a4d8cfc"
+ ]
+ },
+ {
+ "glsl": "vec2 cultmath_af_range(vec3)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "4158c790 c095f5c1 3ee73bea -> 410692bd 41957e31",
+ "4187ff2c bf1d78e0 3e1ed5f4 -> 4181d5b0 418e28a8",
+ "41896304 40260a98 3c962126 -> 4168f83e 419e49e9",
+ "c18da13d c0444cc2 3a934ca7 -> c1a62d2c c16a2a9a",
+ "41270838 409ceada 3caabb56 -> 40b07abc 4175d311",
+ "4174b35c c043205a 40b48d39 -> 40d34922 41bfe114",
+ "c184263f bedeef60 3ad295eb -> c187a54f c180a72f",
+ "40bd19e0 c068963f 3d63848c -> 400e0f49 4119960e",
+ "3ff85750 40012d54 3a4457c0 -> bda1c01b 407d6551",
+ "4199a976 bf9fa36e 3ad9881f -> 418fabcf 41a3a71d",
+ "41886cc2 c077275a 3fc02270 -> 413b0b4a 41b353df",
+ "c0c5c820 407bde5c 3c022872 -> c121fc3b c00f2f94",
+ "4111de08 3e8a7d30 3c907749 -> 410d41da 41167a36",
+ "c0e1a408 40254ef8 3bf0c6fe -> c11a43e5 c08ec047",
+ "4198e74c 3fb6a0f4 3abde733 -> 418d7a3b 41a4545d",
+ "c02491a0 c00a63d0 3fb43bf6 -> c0c489c2 3f7fc10e",
+ "c18dad62 c002fafa 3b44f6c9 -> c19e12f3 c17a8fa2",
+ "c1908d49 4039ee20 3a06fa86 -> c1a7cc25 c1729cd9",
+ "419f31a8 c045c560 403e9b9e -> 415d4af6 41cfbdd5",
+ "c14b80f8 bf9e1920 3ef6e4fb -> c166fb52 c130069e",
+ "bfbc3d10 408fb98e 3c0885df -> c0bf0d21 4041dd32",
+ "c13a7ce8 c06c1bff 3982e0b5 -> c17584fd c0fee9a6",
+ "c0a02e28 bf584ee0 399fd698 -> c0bb3a8f c08521c1",
+ "c185312e c05d2aac 3e6032b9 -> c1a296f3 c14f96d2",
+ "3d265400 40288586 3e9e8577 -> c039bcf1 403eef91",
+ "416b7d08 3fd97cb0 3cf17f31 -> 414fd4a2 418392b7",
+ "c0ea9704 c077d0ae 3c49bcd1 -> c1337228 c05c9370",
+ "c0c62ed8 408756d8 39839a6c -> c126c3e9 bffb5775",
+ "418f7eaa 4071f418 3b87836f -> 41626f48 41adc5b0",
+ "40f6f4a4 bfc28ebc 3ea6c151 -> 40bbe4cd 4119023e",
+ "bf175de0 3eeaf800 3a145f69 -> bf867f84 be06f2dd",
+ "410814ca 4066b5a0 3f8e3a1d -> 40728045 41538983",
+ "419c811a 402c4b84 3d14085f -> 4186ad9a 41b2549a",
+ "c15e3e39 c08c86aa 400c7037 -> c1a3ced8 c0e9bd83",
+ "41150ede 409783cc 3a04c6be -> 409295ae 4160d2e5",
+ "40a33820 3ef1f8e0 390f6b11 -> 40941768 40b258d8",
+ "c00ee540 c06d19bb 3d251680 -> c0bf49b6 3fc191da",
+ "c07dba28 4069ca88 3b087282 -> c0f3d375 be9e6b24",
+ "c0e8395e c0747036 390dc884 -> c1313955 c05c0023",
+ "c0fa99ea c0197a3c 3af15922 -> c123b319 c0adcda2",
+ "4123f010 3fe8dd38 39641810 -> 4106d379 41410ca7",
+ "c08758ca 3f7c4e10 3de1f207 -> c0aa6a5f c0488e6b",
+ "3f333c80 4038918a 40511789 -> c0ae6d08 40db3c28",
+ "4178f744 40727ad4 404c0672 -> 410956db 41b44bd6",
+ "419a5668 c0570d49 393ea966 -> 417ee8a8 41b5387b",
+ "3fff09e0 3f8fb36c 40b2d0e2 -> c096fb56 410b4023",
+ "418c7cc8 bfe53d76 3b93b5d3 -> 417c3f57 419ad9e5",
+ "c1027e12 c020cc5f 3aa221a2 -> c12ab646 c0b48bbd",
+ "c14bd88c c08503aa 3e817d9a -> c1893330 c1054ab9",
+ "41779818 bf879d12 3f03ed2c -> 415e6592 4188654f",
+ "4135166c 3fec9e50 3d0fb33f -> 4116f2e2 415339f6",
+ "c11a8370 bf845c98 3c008d09 -> c12b2f31 c109d7af",
+ "41407c40 bfce8978 3bf58502 -> 41268c52 415a6c2e",
+ "3fa5cb10 c07997ba 3f1f70cb -> c04e8e7b 40ba2cc6",
+ "c1706750 3f0d3db0 3aead95f -> c1794292 c1678c0e",
+ "409a12f0 bf506d68 3ea46203 -> 406b7e2e 40be66c9",
+ "c1387889 402c0214 3d0a782f -> c1640394 c10ced7e",
+ "c1877054 bfac8d08 409f10ce -> c1b9fd64 c129c689",
+ "41871d76 becc8ef0 3c700a0c -> 4183cd30 418a6dbc",
+ "415f614c c037d3d9 3d1893f7 -> 4130d3b1 4186f773",
+ "4188f0ee 3fa73760 3c197f6c -> 417cd47e 4193779d",
+ "c15955ec c07c1f27 3a74b181 -> c18c30cd c11a4a3e",
+ "c08aa5dc 400f3040 3f2fddf9 -> c0e839ca bfb447ba",
+ "40dd7130 401f64fc 3b18f772 -> 408dab80 41169b6f",
+ "403ec808 bf6eff48 3a949689 -> 4002f593 407a9a7d",
+ "40381db8 c05216c1 3e965fab -> bf33145f 40ce8044",
+ "4195b374 3f1c77f8 3e5a4a7d -> 418f1b15 419c4bd3",
+ "41995e52 3fe02144 3e09020d -> 418a4a2f 41a87275",
+ "c1289040 4003f714 3b81f288 -> c1499e50 c1078230",
+ "40328500 bfd17cbc 409a204c -> c06a7a1b 4113e107",
+ "418ea48c 40908d7a 39df5331 -> 41550086 41b2c8d5",
+ "4166d93c 3f85af0c 3ccc4b93 -> 4155bd26 4177f552",
+ "c0ad6508 4094774e 3c90320e -> c121364e bf42eb9f",
+ "c18de01b c02da39c 3e9896fe -> c1a5f6f4 c16b9282",
+ "418adb68 3ec676f0 390390f6 -> 4187c141 418df58f",
+ "c12b685c 3cb6ac00 40c6920a -> c1878664 c08f87e0",
+ "41122b80 bfbf9904 3b352617 -> 40f45a05 412a29fe",
+ "411956c4 4073fa60 3e3995f6 -> 40b2e38d 41593bc2",
+ "415f06d4 408f929c 40bfcad9 -> 405d6006 41c35ad3",
+ "412c30b2 40879d2a 3c239595 -> 40d07251 4170283b",
+ "416f95fc 404e0bd4 3c0db4d6 -> 413bef88 41919e38",
+ "4153bd70 40116f80 3f783dbb -> 411fdda4 4183ce9e",
+ "c16170ac 4008d8c6 3f834917 -> c18a0809 c12ed147",
+ "41142c6a c03b460e 3a8f5a8b -> 40caacc0 41430274",
+ "c1238a5c 40839390 3b96865c -> c1656703 c0c35b69",
+ "4196afce c0917d17 39fbebc0 -> 41649f01 41bb101c",
+ "4087248c c09e93f2 3a8931eb -> bf3bc05b 4112e091",
+ "c0b1c740 405a75c0 4108382c -> c18bdca7 40cbe41b",
+ "40bdbd5c c03c0dae 396c220a -> 403f6936 410de30f",
+ "bf83f860 c09c16cc 3e429dbc -> c0c329de 40812dae",
+ "3f741880 3f747320 39267ffe -> baca4d13 3ff44b13",
+ "c1903d9a c04b5632 3c31103a -> c1a9be8d c16d794f",
+ "c0f6746e c07e069e 3f922728 -> c14d00d1 c025ce77",
+ "c131ace9 c084fbd8 3f60036d -> c181158e c0c25d6c",
+ "c15bef5c 409eff8c 3a07e3c7 -> c195b8aa c10c6d63",
+ "c1863adf bd47b800 40e2a536 -> c1bf4814 c11a5b53",
+ "c0e766e0 4071a738 40524366 -> c164ae26 be2e2e8d",
+ "414c494c c0576194 407ce334 -> 40ae700c 41a0ad49",
+ "c1429ff6 3e0799c0 40fff4fe -> c1a25c78 c0810df7",
+ "c07c7e18 c04b213e 3d251931 -> c0e519ec bf3b2161",
+ "41112970 3fde1cc4 3ea4ebe1 -> 40e07cdb 41321473",
+ "c16249a4 c03b151c 3deadcc6 -> c189725b c131ae93",
+ "c154b9a5 c0430f28 3ee1cc33 -> c18645f0 c11ce769",
+ "41883884 3fd133a8 40a49d36 -> 4123fbe0 41be7318",
+ "c0e03b36 bf9581a0 407ed79e -> c14283c2 bfedbb9b",
+ "c0582b50 c03cf444 3fd5970f -> c0fff59e 3f9f2938",
+ "415b9498 3f2d51b0 3eb7db9d -> 414b0091 416c289f",
+ "c17fb2ac c05ccb9c 39f7099a -> c19b73ca c1487dc4",
+ "412192e6 4002f838 3c6ce0ff -> 41009994 41428c38",
+ "c172adf0 406224c4 3e62bc7c -> c1976113 c13699ba",
+ "c03d1600 4081f2a8 408017c7 -> c1304ac3 40a37f86",
+ "c1061dd2 bd359600 3c39bf4d -> c10701e0 c10539c4",
+ "c18438e7 c09cd2dc 3f62080a -> c1b27de9 c12be7ca",
+ "3f9ee310 408421f2 3b4f03a6 -> c0390631 40abf4a1",
+ "c125aa12 bf8848f0 3a9a4084 -> c136b80d c1149c17",
+ "4193897c bd664600 3f4bfa65 -> 418cb67c 419a5c7c",
+ "419fc934 40336adc 3b648142 -> 418954a9 41b63dbf",
+ "c168e099 3f152f88 3df324f2 -> c17419ea c15da748",
+ "41466c00 3fa1b838 3d204e57 -> 4131949d 415b4363",
+ "402b6cb0 bf87b914 3d062565 -> 3fcaef03 407161df",
+ "c14ce136 c09105da 3ba7cde2 -> c18abc97 c104493f",
+ "c18cd970 bb92f000 3f1cacbf -> c191c80e c187ead2",
+ "c1990718 c094ffe5 402f8633 -> c1d437e5 c13bac96",
+ "3ebabbc0 bfdb320c 3a770139 -> bfaca20d 4004fff6",
+ "c18e4ec4 bff08f98 3e406a95 -> c19ed89d c17b89d7",
+ "c0637c58 4065f764 3f244cf6 -> c0f9438d 3f2e39a5",
+ "41868ee8 403a7ff0 3a93826f -> 415e7924 419de13e",
+ "40c23e44 c072405a 397305fd -> 4012383b 411db036",
+ "c0b27b58 c00664e7 3bb3aee0 -> c0f5dac6 c05e37d3",
+ "c0f8df6c be489d00 400e00af -> c1231260 c0ab9a18",
+ "417b1ff4 3e4b3040 3df61bf8 -> 417606eb 41801c7e",
+ "c108de78 bfbe84ce 4009011f -> c142ef66 c09d9b15",
+ "4192921a c04bf732 403cd329 -> 4142f185 41c3ab72",
+ "bfdd3910 408c9094 3ca37487 -> c0c48259 402bcba3",
+ "417b49b4 bdc86e80 3c945c85 -> 41796e99 417d24cf",
+ "c1774395 c0862188 3adf2414 -> c19d2db3 c1342bc4",
+ "41933ce8 bf8169d6 3f2f1fa4 -> 4185ad44 41a0cc8c",
+ "41248120 3fbb7ab8 3dd2ed63 -> 410b6be2 413d965e",
+ "c1049ea9 3e8ffd40 40877170 -> c14cd758 c07197e9",
+ "c113edd2 3fff1598 3a924ae0 -> c133d522 c0e80d03",
+ "c06793a8 400a6188 3d71199e -> c0badcd7 bfb2db45",
+ "c19a1c02 3f956bd8 3f8dd432 -> c1ac500e c187e7f6",
+ "4049ea90 402c40f0 40cc0526 -> c0bd306e 41438d7f",
+ "4138c0ea bef01a50 3e7b6a9f -> 412d5261 41442f73",
+ "416b33dc beb9d860 3fe94ce6 -> 41483b6b 41871626",
+ "41202aa4 4025d570 3e12c5c1 -> 40e8d449 414beb24",
+ "409b6c08 c021fa17 3a91a9fe -> 4014cba6 40ec723d",
+ "c17efa3f bfc5d30c 3986026d -> c18bdadf c1663ec1",
+ "c17e9728 c069612e 4014f431 -> c1af164b c11f01ba",
+ "c19bb65a 409de01a 3fa6df13 -> c1cd9c5f c153a0aa",
+ "418d0d7c 3ff2240c 3cd29ced -> 417b6d14 419c646e",
+ "40ec1328 c090e11d 3aaae573 -> 40364e8a 413e7f86",
+ "4181ee56 406f81b8 401521b0 -> 4122b3bc 41b282ce",
+ "40b69fdc 3eb20e40 3b6d1c67 -> 40ab6148 40c1de70",
+ "c10966ed c052471b 40ab6fd8 -> c189d859 3d62d73b",
+ "c18384f2 40794d48 3a56f771 -> c1a2b053 c148b322",
+ "412044bc 3ed9b5b0 3f332ce7 -> 410e4435 41324543",
+ "c103ce75 3fbcb858 3c95b664 -> c11bb065 c0d7d90b",
+ "c19fe15e bff5d554 3bea0c03 -> c1af4d5f c190755d",
+ "bf8d08a0 40852f92 3cd1187b -> c0a942dd 40457d19",
+ "418b5f28 3f279d58 3f41b7a7 -> 41801477 4196a9d9",
+ "c167c357 405ea5f4 3f290188 -> c194fe7f c12589af",
+ "c1428f69 c04ad5ba 3c460091 -> c1757667 c10fa86b",
+ "40a53e58 405c4df8 402a1022 -> bf6f865c 413436bd",
+ "4124fc7a 4099330c 3eba2f25 -> 40a522d7 41776788",
+ "417e6228 404a6cb0 3a425972 -> 414bc3df 41988039",
+ "c1692344 c09bc6a2 3ade1b3c -> c19b86cd c11b38ef",
+ "40f3fa78 c017b16f 3c931741 -> 40a78e95 4120332e",
+ "c18eb623 3fbbd2d4 39298a7b -> c19a73af c182f897",
+ "c1968372 3feb98a0 3efe9351 -> c1a93754 c183cf90",
+ "41617490 bf2a0908 40c55d29 -> 40e84aac 41a761e4",
+ "c08a20f4 4004919e 40e0bacb -> c1569254 4098e2c1",
+ "3fb7da20 c061a396 3b87e612 -> c005fa8d 409eea56",
+ "c14b9c51 407b8584 3eae6aad -> c187f88c c1074789",
+ "412a713e c0725a72 3e9ec32d -> 40d1c8f3 416bfe03",
+ "4175d680 3eb9a880 3e61cfe4 -> 416c81ec 417f2b14",
+ "4119c0c6 c07e24e6 3ceb5259 -> 40b383ab 4159bfb7",
+ "c1421287 bfd0fba0 405182d7 -> c1884961 c0e72498",
+ "c1293a70 c0233eee 3b55483a -> c152178d c1005d53",
+ "c0e01180 c0852b89 3a84d1f0 -> c132a2b6 c035bb27",
+ "410e34d6 c0558885 3d000f77 -> 40b0a531 41441713",
+ "40e2bd78 40312a9c 3c393422 -> 4089cb7c 411dd7ba",
+ "41889892 bfabe616 3b1575e9 -> 417baaf8 41935ba8",
+ "411b69ac bfb13234 3e623a5e -> 4101ba71 413518e7",
+ "41604aa4 40913c88 39d132df -> 4117aaab 4194754e",
+ "3fc97460 4087c5fe 3a05e9bd -> c02ada41 40ba2751",
+ "4121a0c0 c05342c7 39bb0bd2 -> 40d99d15 415672f5",
+ "c0a28074 c006c7a8 3da4dd6f -> c0e877cd c0391238",
+ "c1218037 3fc70e30 399fe2b4 -> c13a6349 c1089d25",
+ "c18e64ea c05bd60a 3ca7aa28 -> c1aa09a1 c1658067",
+ "40d5835c c038fbfc 395a0f88 -> 4072072e 41190191",
+ "c171a99b bece8940 3edc0b79 -> c17efe51 c16454e5",
+ "c13b3af6 c08376be 3bacf66c -> c17d0c04 c0f2d3d0",
+ "c107e77d 409252b0 3a3ac740 -> c15113cd c07aecb4",
+ "c083bccc 409f2b8c 3f024a40 -> c11998da 3faee06d",
+ "414e9864 bfc4ba58 3c06831a -> 4135df6a 4167515e",
+ "4134ff32 3ffb2e0c 3b836942 -> 411588f6 4154756e",
+ "c159103e 3f395a00 406d9d54 -> c19006a3 c1121337",
+ "c182fbe8 bfc115e0 401b35bb -> c1a27407 c1470791",
+ "4185b660 bf348438 39d3e559 -> 41801161 418b5b5f",
+ "c0ee56a8 406dfaf8 3a91b6ab -> c132aeab c06e9ff4",
+ "414603f0 c087ac00 3a147139 -> 41022b8d 4184ee29",
+ "4086b990 4011f440 3cf25417 -> 3ff3343c 40d0a611",
+ "c08841a8 bfd72d00 3fbfc672 -> c0edfe93 bf8a12f3",
+ "413e2e10 beb3be20 3a979d0d -> 41388b56 4143d0ca",
+ "418cc61e 40984f16 3b3d01eb -> 414d58cb 41b2dfd7",
+ "41597d00 bf406268 3b6669f1 -> 414d6865 4165919b",
+ "4108f26c c011c906 3ca3f6d8 -> 40c85c48 412db6b4",
+ "c165648a 3d747b00 3e1f9f77 -> c168d792 c161f182",
+ "c160383c c095d8e6 39bb1e17 -> c195931b c1154a40",
+ "415fcee8 c006a7b7 3e4b9617 -> 413af692 4182539f",
+ "c1312892 4097a1ec 398c2ab6 -> c17cfab0 c0caace7",
+ "4193a28e 3f6076a8 40816fae -> 415885c3 41bb023b",
+ "40684548 c034c466 3dfcb1b3 -> 3f2e6ce7 40d277ab",
+ "4178bef0 bf8dbff4 3bd9588d -> 4166ebb5 41854915",
+ "bf144660 bfae7c9c 39b4c3d9 -> bff8ab28 3f48c98f",
+ "4100d3dc c05f840e 3bf0a5fa -> 4091a971 4138d300",
+ "40597790 c0870820 38dd365f -> bf526a22 40f3c4d4",
+ "4147bf40 3f7f8900 3dcbf030 -> 41362ec2 41594fbe",
+ "411f5010 3fd6d0f4 3d9114f4 -> 410353bc 413b4c64",
+ "3ef6ab80 bee357e0 3e9b33f1 -> be87e077 3f9d4dde",
+ "c094df28 3ee08220 392aa209 -> c0a2e8a9 c086d5a7",
+ "c14fba16 3f3d5a88 3ce9ab6e -> c15c04a2 c1436f8a",
+ "c16e928e 40992390 3c0f2aa1 -> c19da41a c121dce8",
+ "c0a59bb0 c0209452 3a8e8fc9 -> c0f5eed1 c02a911d",
+ "40f46b60 4050337c 402651c5 -> 3fe4a294 4157d70d",
+ "c1814d4a 3fc7bfb4 3a06e346 -> c18dca5c c169a070",
+ "3f9efa10 bf043060 40229155 -> bfe840ec 40898d43",
+ "4117e2e4 c0168efe 3a95c1d2 -> 40e474d5 413d8b5e",
+ "40c67808 bf639f50 3bf3015c -> 40a9c750 40e328c0",
+ "bf119960 c0380af2 407e5dbe -> c0ed6793 40c9013b",
+ "c0be4df8 c086d205 3f253352 -> c12ce33f bf8b55ce",
+ "41870444 3d4ba100 3fd7e676 -> 41724005 4194e885",
+ "c0e3c766 bff314a0 3f636a54 -> c11e7cf6 c08a94e0",
+ "409513bc 3f3d99a8 3a3e56a8 -> 407ab512 40acccef",
+ "419b2b32 c036d444 3fb297e3 -> 41724e3e 41bd2f45",
+ "413e4bc0 c072766d 3f3ee155 -> 40eb7ffe 41836bc0",
+ "410aad0c 3fc3d548 38f026f9 -> 40e463c2 41232837",
+ "c038e898 4099eb0e 38e3ed6b -> c0f6604d 3ff5ded6",
+ "4149d3c8 3fbb5b10 3b22eaa6 -> 41325e29 41614967",
+ "4153a8ac 3e509e60 3a2afaf5 -> 4150637a 4156edde",
+ "c1751d32 3fb50e10 3f2d5414 -> c18b4a24 c153a61e",
+ "bfa1a580 c099d36e 3a3a755e -> c0c242ae 4062dfdc",
+ "c00beb20 402c2d26 3b82f7bd -> c09c2ceb 3f020e56",
+ "c193fc68 402f491e 3bafe505 -> c1a9f095 c17c1077",
+ "c0bcb5ac 4084aab2 40168d32 -> c1465388 3f19ddbe",
+ "41059d76 40218c80 393b6042 -> 40ba731f 412e015d",
+ "c0963712 4064f044 3b389010 -> c104632b bf8e9f36",
+ "407ecb50 402c395e 3d80632f -> 3f9d1d7c 40d783f1",
+ "4182964a 40878996 39a1726f -> 41416671 41a4795b",
+ "4123057a c07bcb40 3ffb4f24 -> 4089516b 4180b11f",
+ "4029c1f8 bdb18c00 3f636d55 -> 3fd6b469 406829bc",
+ "40a25930 bbb1e000 40934e11 -> 3eede93a 411ae9e6",
+ "c0707518 3e28b140 3a7794a7 -> c07b0fb5 c065da7b",
+ "40cae8b4 bfbd72ec 3bbcd5cf -> 409b5cb4 40fa74b4",
+ "bfeab1b0 3fe54bb4 401f1fa2 -> c0c38f36 401c6cbc"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_add(vec3, vec3)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "40d43ce8 c087efa9 39613e6a c16aec62 c07bc9ac 403cc5ae -> c100cdee c102ea40 403cc980",
+ "c12da602 bf04ef28 3e52a901 416eafe0 3e32ffc0 401334ae -> 408213bc beb05e70 40205f5a",
+ "c13bb855 3f1a7af0 399ddbc6 c188bb12 3ff3ff78 3e522b2e -> c1e6973c 40209e78 3e5281fe",
+ "bfc3dff0 be934a60 3b29878b 400ff980 40107892 3c43020f -> 3f382620 3ffc1e8c 3c6d6ec2",
+ "418d570e bffc8a8c 3ac6433a 416372b0 400f701e 3d0a596e -> 41ff1066 3e8956c0 3d10abb8",
+ "418c1916 c062f6f7 3993b387 40e6d1c4 c024f1e0 3fdf597a -> 41c5cd87 c0c3f46c 3fdf63ba",
+ "c195fd6e 3f9be3b8 411ffb75 4194aff8 bfcfd300 392c8a53 -> be26bb00 becfbd20 411ffc2d",
+ "c16eadd8 40227cbc 410204a5 c18cb723 c04064f0 40c11ba2 -> c2020708 beef41a0 416292a5",
+ "c18039b0 3f5ba9f0 3e4f8fe4 40f2c80c 409d92e4 3a8f8f7d -> c1070f5a 40b90822 3e50b29e",
+ "40773020 c079dfec 3bb7222b 40c1a4c0 c0459a7c 3f85d8af -> 411e9e68 c0dfbd34 3f869061",
+ "40ca3f3c bfa23160 3ed550f9 c15b9017 408b3ed8 3bedb0ff -> c0ece0f2 40456500 3ed9091a",
+ "4134ba24 3e86f640 3b7f2baa c121ac83 c092bda4 39679e62 -> 3f986d08 c08a4e40 3b86feeb",
+ "40cff3f0 bcedf700 39f4164e c126d9ec bf354f20 40e76b14 -> c07b7fd0 bf3cbed8 40e76efc",
+ "c02b2300 40741c60 39ac403a c10ceaec 4023e60e 3a00dc23 -> c137b3ac 40cc0137 3a5b731f",
+ "415c62ec c02131da 3a188197 4174845c c0853193 39f197d6 -> 41e873a4 c0d5ca80 3a8d1e63",
+ "bd35a200 bf999a7c 3c68e268 c1427d2d bff77f5c 40d446dc -> c14332cf c0488cec 40d4bb79",
+ "c0e7495e 40967120 3f9ed448 408ca048 c00e286b 3e6d5e06 -> c035522c 401eb9d5 3fbc803f",
+ "40b0b778 40613920 3d57e1b7 406ce3b0 c0974af9 3cf57942 -> 411394a8 bf9ab9a4 3da9546e",
+ "c1883885 bfb6b418 3e8131bb c09ca770 c03464df 3b680d8b -> c1af6261 c087df76 3e830524",
+ "41005bee bf9beaee 3df9a294 405b39e0 bfefe608 3e8b6aa6 -> 41372a66 c045e87b 3ec9d529",
+ "c133bc4f 40801ae6 3c85c395 c1495d70 401f091e 3e4fb998 -> c1be8ce0 40cf9f75 3e6079ad",
+ "40b10314 beac46d0 3a6adb4b c153aefe 40866562 3ca1aa3e -> c0f65ae8 407741ea 3ca91842",
+ "c15e0335 404ee720 3dd554cc c0327270 3fb572b0 40545d57 -> c1854fe8 4094d03c 405b0860",
+ "40707f70 c01ed5fd 3aa6c604 40c9c314 4044f564 3edbafeb -> 41210166 3f187d9c 3edc5814",
+ "bff42e80 c07261e9 3a28fcd5 c172bccc bd364700 408c6a78 -> c188a14e c0753b05 408c6ff3",
+ "c0c3a420 40158cd8 3e46a2db c16bb081 bf8be71c 3bfd0bde -> c1a6c148 3f9f3294 3e4e90cd",
+ "c12c85a6 bef236a0 39ac72e6 417513d0 40915bb0 3d828091 -> 40911c54 40823846 3d83315a",
+ "c0f9c412 40819efa 3c7ba656 c132561c c0305084 3c1a67e2 -> c1979c12 3fa5dae0 3ccb2fa7",
+ "41040458 c0130774 3ef6488c 41085452 409d574e 39530ecd -> 41862c55 4027a728 3ef6656a",
+ "bfada460 3f1d8898 39983863 410a4b08 40152860 3e0c14b3 -> 40e92cf8 403c8a86 3e0c6367",
+ "bc8b5800 3e33e540 40e4a528 c118520b 404e2310 3a5feeb0 -> c11897b7 40596164 40e4ac4f",
+ "4140f4b4 c099295a 3c6e6b9a c12f5d00 c04016f6 3a672177 -> 3f8cbda0 c0f934d5 3c7d014d",
+ "41407ce8 40070c0a 3b49894a 40cce260 bfbc78dc 4050bb94 -> 4193770c 3f233e70 4050ee4f",
+ "c106e449 c02c2fb4 4042fec1 412ae39e bf5b0490 3aaf5b82 -> 400ffd54 c062f0d8 404314cf",
+ "c1451b66 3fabb33c 3f0343b1 4077c928 3fd40818 3fb312e4 -> c107291c 403fddaa 3ff4b527",
+ "c1099e9a 3e12f540 3ecaf927 bf73b040 bf954d06 3c79eb8e -> c118d99e bf82ee5e 3ed2c9e3",
+ "40668a98 c09247ff 39884958 c11f62ba bf4d2b40 3a87e4fa -> c0cb8028 c0abed67 3aab6ec8",
+ "4193ecac be49ea80 396bd992 3ff28820 4083ebb4 3b25e98f -> 41a3152e 407b38c0 3b362c2c",
+ "41287054 4043da44 3a9103bf c146770c bf3b42c0 3d04b260 -> bff035c0 40150994 3d093ebb",
+ "41137c6c 4014d6b4 39abdc8e 411d21e8 c0899b52 3a642e9d -> 41984f2a bffcbfe0 3a9faee8",
+ "c00e8148 c03cfd96 3bc4cffc 408460c0 408d20ce 3e89076b -> 3ff48070 3fba880c 3e8c1b20",
+ "bf9c84f0 bfe09024 3b8e7751 4166f998 c08998bb 3b683910 -> 415368fa c0c1bcc4 3c019706",
+ "414c9c90 c093c0c8 3f917426 40f7d8d4 40430a48 4095f582 -> 41a4447d bfc8ee90 40ba52c4",
+ "c15ce12a 3fb92730 3ed04fa5 bfc622b0 405581f4 3ffe4ed9 -> c175a580 40990ac6 401931bb",
+ "409a176c c08193c7 398f927d c134c749 401d4890 3e37c6e7 -> c0cf7726 bfcbbdfc 3e3810c0",
+ "c0d50cdc 405c80bc 40ea3685 417cd170 40443d98 3a9c0e1a -> 41124b02 40d05f2a 40ea4074",
+ "415e58f0 bfb4ae0e 3d4b892d c0935466 c0870f2f 3db1be07 -> 4114aebd c0b43ab2 3e0bc513",
+ "4190f802 4080bb60 3ef51586 417f4b04 bfa62738 3c0fa76d -> 42084ec2 402e6324 3ef9976a",
+ "40f479ec c09437ff 408b615c c153de0c 3f680c50 3c5b4fb0 -> c0b3422c c06e6cea 408bcf1f",
+ "bfadc600 409a9202 3beaed49 be202280 409a9254 3fd942cb -> bfc1ca50 411a922b 3fda2e1f",
+ "407ae6c0 c01ec955 3da07483 40e25f8c 3e8c0040 3aafbedc -> 412fe976 c00d494d 3da33a22",
+ "c0d0a62e 4087e590 3abcaf85 4075a160 405d9378 3c8af860 -> c02baafc 40f6af4c 3c96d82a",
+ "c086846c 402cc908 3d8b999e c16a1d46 3da97480 40912003 -> c196afbe 403214ac 40934e9d",
+ "c170e1ef 400dc0b0 3ed79b31 40fe9e48 3e87de00 3eb3756a -> c0e32596 401ebc70 3f4588f4",
+ "410eb658 c056a862 3af3c399 3ff38710 bf35d748 3fa7f302 -> 412d273a c0820f1a 3fa83075",
+ "415c3250 bfbe4d0a 3bf80550 40f76d28 40379c1c 3facc0f7 -> 41abf472 3fb0eb2e 3fadb9be",
+ "c19d27f2 c00f3fc2 3bf590ac 3ed7bd00 3f1e7870 3c8a58a9 -> c199c8fe bfcf434c 3cc7e690",
+ "c15b8ff8 c08195b1 3a6b441d bf394dc0 402f642a 3fa2625f -> c16724d4 bfa78e70 3fa28050",
+ "416583d0 bfd736f4 3cc1b901 c01a2b08 bfa33d36 3b051cb7 -> 413ef90e c03d3a15 3cd27a6e",
+ "c17282e4 407f6a8c 3ed8cdee 416cb6d0 40913cb6 3bd56500 -> beb98280 410878fe 3edc24ac",
+ "4196e814 40393c0a 3cf69113 c06b62f0 40213608 3cf43d53 -> 4172f76c 40ad3909 3d757bdc",
+ "c1899183 40010736 4103b0b0 411a0700 c06fcd62 3abdad44 -> c0f2380c bfdd8c58 4103b6af",
+ "401051f8 3f90c050 3a249d89 c10d3537 3ed6f8e0 3c6b6e69 -> c0d24172 3fc67e88 3c75d8cd",
+ "3f3bc040 c025b4c9 3c12f286 c02af188 3ff1da20 39a05bfa -> bff802f0 bf331ee4 3c17fffc",
+ "c0c17d98 bf750bb8 40fadd5a c176dfa4 3f38e5e0 402fdecc -> c1abcf38 be709760 41296680",
+ "c17f8ff4 c06706b6 3b85f69d c19c18d9 3ec76e10 3f3a7832 -> c20df06a c04e18f4 3f3b8696",
+ "418ff028 401f48c2 3baa4e07 40fa8518 bf61c760 397170fb -> 41ce916e 3fcdadd4 3bb2b506",
+ "41580d20 c074832d 3a8d5887 c124b308 407560c0 3f206182 -> 404d6860 3c5d9300 3f20a86c",
+ "c17ebea1 405ab254 3bc7f729 c103ec38 bfbe0a62 3ebb93c1 -> c1c1556c 3ff75a46 3ebeb6ed",
+ "41971a7c 3ec46450 39a6b792 c081c96e c08d0cf8 3bb34612 -> 416d5041 c080c6b3 3bbe4871",
+ "3f241e80 4091de50 39e886fc c1818253 3fb32de0 4108a229 -> c178c2be 40bea9c8 4108a418",
+ "4183224c 3ee23190 397631ca c0907ef8 bfda2b14 3f6c76e5 -> 413e051c bfa19eb0 3f6c8729",
+ "c183bbba 404e7978 3fb34f54 c0e8d304 3f74d9f0 3d92a978 -> c1bdf07b 4085d7fa 3fbc7ad7",
+ "4179f3c0 c07c0bc3 3d24b7b1 c1338928 c09c1081 3ee60e13 -> 408cd530 c10d0b31 3efaa6c0",
+ "3f9d3120 40445c44 3f5da9cb 408c3138 c0933354 38d32724 -> 40b37d80 bfc414c8 3f5db0e4",
+ "40dc2634 3f031430 3e8fbedc 419e92d0 c04cff5e 3c9c08f7 -> 41d59c5d c02c3a52 3e998321",
+ "418dc79c 401b11c6 3cc90297 c133076b bfd5ef3c 3ba2c4f9 -> 40d10f9a 3f4068a0 3cf1c276",
+ "40ed1db4 400980dc 3d14fc8b 4023d450 c03c74c5 3d34b070 -> 411f83ee bf4bcfa4 3da4dbea",
+ "41757128 3fc53cf4 40a577c0 3f96f5f0 3da4f100 40ba5b0a -> 418427f3 3fcf8c04 412fe982",
+ "41511ca4 c00234ee 40a70d3d c08172c8 3f2554d8 3fbb86e0 -> 41106340 bfb1bf70 40d5ef17",
+ "c140c528 bfffa80c 3d07e9a0 c188776a 4009ad6c 3f47878a -> c1e8d9fe 3e1d9660 3f500805",
+ "c17dcc58 c0824e89 3e27d9f8 c0a228fa bf9ff16e 3fec9147 -> c1a7706a c0aa4ae4 4000c6b4",
+ "c1823ad3 3fd9f658 3f3c489d c14bbe3b 3eaf4000 3b493f05 -> c1e819f0 4002e32c 3f3d13d9",
+ "c13440b9 40955888 3dcfd49d c11a82dc 4010a772 3c0b4ccb -> c1a761ca 40ddac41 3de14c31",
+ "c18d7a6a c064cba4 392c52c8 411770de c053f705 4026ad73 -> c10383f6 c0dc6154 4026b06b",
+ "3efe7d80 3ee244c0 3a4ad175 40b95668 c0992122 39189b8c -> 40c93e40 c08afcd6 3a73a0dd",
+ "41566db4 3f8efb58 411f7ff0 4115a272 bec9f4b0 39bfffda -> 41b60813 3f38fc58 411f8191",
+ "41770880 3dd0b4c0 3b22d2fb c1836754 bf22ae78 3fc5b9cb -> bf7c6280 bf0897e0 3fc60b4d",
+ "c14cfa08 3fb9b5bc 3f25e773 40bafef8 c04c78aa 3dc7dad5 -> c0def518 bfdf3b98 3f3ee365",
+ "c12b965c 408cdeda 3d98406c c1744e06 c09afd00 3d956aaa -> c1cff231 bee1e260 3e16dc30",
+ "411687e8 bfaa7a6e 408560a5 41264346 4066f798 3fb695f1 -> 419e6597 4011ba61 40b30658",
+ "40e0d048 bf048368 3e339f89 411a0f74 bfc457de 4083267c -> 41853bcc c0034cc9 4088c3a6",
+ "c101754f be1e32a0 3d0b07e1 beeae880 bfa316bc 3a9d4709 -> c108cc93 bfb6dd10 3d0ffc1d",
+ "c17b9c51 4095ecea 3ead98db c13c8ed8 3f11ab98 3d2a32b4 -> c1dc1594 40a8225d 3ec2e357",
+ "c172ad82 406a746c 3bd7b2eb 404c61a0 bf5ef9c0 39859ac1 -> c13f951a 4032b5fc 3be082c6",
+ "bfd54100 400abbbc 3dc3addd c03a9678 409f8d44 399a44d2 -> c0929b7c 40e4eb22 3dc44e0c",
+ "c14731a6 c06f3ac5 3e34a4be c0049e00 bf5cdb30 410bb34e -> c1685926 c09338c8 410e85fd",
+ "c1471115 bf1c25f0 3b4ba548 415978c0 bfc21666 3e9a8e09 -> 3f933d58 c00814af 3e9c25c7",
+ "c182a5bf 401bc0e8 3d8d171e c0b53a8c c09c58db 39346f97 -> c1aff462 c01cf0ce 3d8d7d98",
+ "416a9914 3e98b610 3f8f78d6 c07f50a8 3fb1e190 41164530 -> 412ac4ea 3fd80f14 41283462",
+ "bfa814a0 c0815822 391d8053 402cf5a0 c00b486d 3e105efd -> 3fb1d6a0 c0c6fc58 3e10884d",
+ "c0de1ab4 406d304c 3cdc5e1c c0603bf0 c000259f 3adf937c -> c1271c56 3fda155a 3cea6faf",
+ "402a4f08 3fcb1660 3d73642c 410b6abe c09abee2 39cbbb61 -> 4135fe80 c04ff294 3d750a52",
+ "c12fd8b2 c00c2643 3d1f4a97 40d6ad88 bdf38300 3e640588 -> c08903dc c013c25b 3e85ecf2",
+ "3f0b6fa0 c080056c 3eac34a1 3ffa5c00 3f1b0540 3cb4d2d1 -> 402009e8 c0594988 3eb78296",
+ "c10a5940 4038a284 3cdfa554 40c615c0 4099ed8a 3b7ec187 -> c01d3980 40f63ecc 3cff91e3",
+ "4190ebd4 3f9b630c 3a1f1d70 40d7dcf0 3e0861a0 3cc889fe -> 41c6e310 3fac6f40 3ccdb761",
+ "c13997ce 3fe586fc 3c8751fa c0e4ccac 403acef8 3bbe33e5 -> c195ff12 4096c93b 3cb70deb",
+ "be9c8e80 c060d1a9 3d172502 40f5c700 c04ffb78 3bc9efdb -> 40ebfe18 c0d86690 3d30712b",
+ "bf6fc740 403fa6a8 3ddfc1ca c0abc622 c08ebcc9 3a56270c -> c0c9bf0a bfbba5d4 3de17209",
+ "4187d572 4031a724 3b68abcb c19a80bc c06db5bc 3d137c88 -> c0155a50 bf703a60 3d220a95",
+ "4125daf4 4083c470 3e7a509b c12868d8 40299318 3c1ab7b0 -> be237900 40d88dfc 3e81fef1",
+ "41939ab8 3f10e350 3f307e78 c1932270 bed88b70 3f8da25b -> 3d709000 3e127660 3fe5e1a7",
+ "c12f65e1 c044e2b1 3b635b53 c0bcab58 c08de806 3c3bc166 -> c186ddc6 c0f0595e 3c74f9c4",
+ "4191b7a0 3f6b0cf8 3def23b4 c16d4298 c04df8ad 3a5406c2 -> 4058b2a0 c013356f 3df0cea9",
+ "41068da4 3f5eeae0 3d8ccb22 4197be44 401c4394 3ef45081 -> 41db0516 4053fe4c 3f0bc399",
+ "c154aa82 c0449657 3d684e2d 418a5754 3f1efad0 4020f96c -> 4080084c c01cd7a3 40249ac9",
+ "40e02608 c01c7b9c 3c07e673 c1743c34 4013ae14 3dfd363a -> c1042930 be0cd880 3e071ba6",
+ "40670da0 bf22de50 3ba7918e 413f4b66 c0667d31 40020a1a -> 41790ece c0879a62 40025e3a",
+ "416f9c3c 3f380248 3ece4938 417edc08 c08c385c 3d45c609 -> 41f73c22 c06a7026 3ee7065a",
+ "417e99e0 3fa63b18 3eee6394 be211500 3e884c20 3a4b3707 -> 417c158c 3fc84e20 3eeecb69",
+ "4151a5a0 409bdc74 3f93b35d c195c5a9 406e65a0 3b0a4ef5 -> c0b3cb64 410987a2 3f93f8ff",
+ "c11ad8cd c004148b 3e1115f3 c0387f98 3fe32ea0 3f818d6e -> c148f8b3 be93e9d8 3f93b09c",
+ "c1970424 4057ab74 40014654 419e6924 3ec7cff0 3f02f9cc -> 3f6ca000 4070a572 402204e4",
+ "41597c58 4083a120 3c8d14f2 4103c1f8 c0800fda 3a3e8742 -> 41ae9f28 3de45180 3c933516",
+ "c19b4c1d c013868a 39ecf54b c19b86e7 c094f59c 4092a983 -> c21b6982 c0deb8e1 4092ad9c",
+ "c1623b78 c04d68a8 3ee1c245 c13c3d22 c005e1d5 3f05dcd4 -> c1cf3c4d c0a9a53e 3f76bff9",
+ "4143d670 3f153ae0 3d872138 c187666a 3ed12190 3fd9f7a9 -> c095ecc8 3f7dcba8 3fe269f8",
+ "c12bf57d bf090f78 403dbb8b 418665d0 406ce450 3aae7116 -> 40c1ac46 404aa072 403dd18a",
+ "40e0e3b4 4080e3cc 3995342e 419d6154 3fc7fea0 3df43005 -> 41d59a41 40b2e374 3df4d56d",
+ "4113a078 c0721c57 402ec640 40b36488 c09a798c 3dd401bf -> 416d52bc c109c3dc 403566b7",
+ "c16a5576 c023caff 3b017295 40fd7ae8 c00be46d 3cfe6f57 -> c0d73004 c097d7b6 3d075a56",
+ "c188e7a8 404e34d8 3d5c6950 c174dffe c0470426 41002b59 -> c201abd4 3de61640 410107eb",
+ "c14e23e4 4028492e 3be94ed1 40814118 be824450 3e3d3f37 -> c10d8358 401800a4 3e448c88",
+ "c10e2641 c081b1ec 3c229d46 4181fb44 bfceff50 39eee0ad -> 40eba08e c0b571c0 3c2a4878",
+ "415a7d9c c05cfe22 3d28699a c1774c62 be7dd9c0 3a37af8d -> bfe67630 c06cdbbe 3d2b4de3",
+ "41641c90 c055dbd5 3d4fba2a 41937b4e 408dc450 3b47aefe -> 4202c4cb 3f8b5996 3d5c56f0",
+ "405f02b0 3eaa6870 3a2f49c0 c0852d70 405e9aec 39361bb4 -> bf2d60c0 4073e7fa 3a5deffb",
+ "40e4ad1c 3f154760 3ebdaa52 c17987b8 4048e690 403b5c0f -> c107312a 406e3868 40531197",
+ "c12356c8 c06d0014 3e303512 c12a4b90 bfb04ef6 408335ad -> c1a6d12c c0a293c8 4088b792",
+ "c13da8f9 c02e4c01 40585641 c16e7682 40643fdc 39e182b2 -> c1d60fbe 3f57cf6c 40585dc9",
+ "419833fa 4092be8a 3bb1fcad c09d5a76 c018fc8e 3908f2cf -> 4161bab9 400c8086 3bb6c6bc",
+ "c01a5a30 c0351a82 3fa100f7 c1886894 c09b9010 40a2c01f -> c19bb3da c0f61d51 40cb00a0",
+ "beef8c80 40747078 3ae0dd8a c0be34a4 c02e6003 3f4b47e8 -> c0cd2d6c 3f8c20ea 3f4bb8dc",
+ "c051fa40 40140552 3ba5bb98 40a5c3c4 406c0a64 3baf02b6 -> 3ff31a90 40c007db 3c2a7ecb",
+ "3f60e500 3f9cd03c 3f856575 4097a224 40249f96 3ec13a8f -> 40b3bec4 407307b4 3fb5b470",
+ "c08b8aec bece4690 3e77774f c193bc92 bf4bfab0 4032d09d -> c1b69f4d bf998efc 4042487e",
+ "41009d00 bffdf870 3b490617 40f3e820 3fda1da8 3dc593d4 -> 417a9110 be8f6b20 3dcbe40a",
+ "c1888534 c05285a2 39c6eadf 4103c1ce 401d30d4 3cce8a17 -> c10d489a bf555338 3cd1b923",
+ "40e0df08 40617158 38d202a0 c16f79d7 4006080c 39de006a -> c0fe14a6 40b3bcb2 3a0ca434",
+ "4136fe64 bfc4f3da 39935c5c c19f8801 40634474 3e1f6b41 -> c108119e 4000ca87 3e1fb79a",
+ "c13373f6 404d9860 3ca3143a c17d1417 3fe9e89c 3d719ec1 -> c1d84406 40a14657 3da1a482",
+ "c116a2cf bf000d00 3ca6855f c0b63940 3fc0915c 40886eaf -> c171bf6f 3f808adc 4089155d",
+ "bf31fe60 40118d60 395358fa 411c1a42 3f0fb120 3e9dc69c -> 4110fa5c 403579a8 3e9de28e",
+ "c12cfd94 404a4c80 401b1fcb c0e238d0 408db0c8 40564da7 -> c18f0cfe 40f2d708 40b8b6f7",
+ "4109c0a0 c0164b9f 3f106fd8 40034ab0 c01e7789 39765913 -> 412a934c c09a6194 3f10803f",
+ "413fab2e 3fff5a04 3c8be434 40cb6628 be94bfe0 3fe16e1b -> 4192af21 3fda2a0c 3fe39e5b",
+ "c16844d6 409604d8 3ce27463 401ddd68 bf166d90 3b451339 -> c140cd7c 40833726 3cfb3727",
+ "c19a038a bfe8e7b6 3a85d543 c188441a 3fb74c20 41020d0d -> c21123d2 bec66e58 41021169",
+ "c18b5dfb c0928def 3f6429cc c08a3ab6 402ded90 39244fa3 -> c1adeca8 bfee5c9c 3f643599",
+ "41276408 407da870 401def58 400c5ea8 bf8da970 3c4896f0 -> 414a7bb2 4036d3b8 401eb837",
+ "41427990 40088a84 3a7ef47b c090183e 3f14e0c8 40b5eda4 -> 40f4dae2 402dc2b6 40b5f5bc",
+ "bf5231c0 404f2d04 3afb217f c1387ff4 3f88be2c 3db0fbc7 -> c145a310 4089c60d 3db4f0ac",
+ "c139f609 3fd71628 3bf54f3d 40500ce0 bffa2aa8 3e082503 -> c105f2d1 be8c5200 3e0fd1af",
+ "41020594 3fb491a8 3e03dc18 412bb474 be0715c0 3a93b4e2 -> 4196dd04 3fa3aef0 3e050893",
+ "c10a1e89 bf6cdde0 408b40d1 c06ce288 407e4f0c 3d98e27a -> c145572b 40431794 408da483",
+ "41969fd0 3f528e08 3da1b646 c1895cee 4024fdc8 3edf38fc -> 3fd42e20 4059a14a 3f03d3a0",
+ "c180a01a 3fa80a18 3f2150cf c11f7300 3f726ba8 3fa0325b -> c1d0599a 40109ff6 3ff0dbb3",
+ "4110554e 4061c3fc 3c75abf7 c13e48cf c04b2752 39ad0fca -> c037ce04 3eb4e550 3c7b216b",
+ "40d2201c c04c9f2d 3dba507b c11d9e95 40611214 3f0d197f -> c0523a1c 3ea39738 3f2463d2",
+ "413d319a c0949d72 3ab1e889 419be7fa c07ded97 3a14935e -> 41fa80c7 c109ca1f 3b0097f0",
+ "c19891e4 c088f53d 4089106d 40e8cb90 c025bf92 390b28c5 -> c13cbe00 c0dbd506 408911b1",
+ "c19d7de7 c0673c2c 4063b3ac 40bc1b9c be2bc960 3e6e0ed1 -> c15cee00 c071f8c2 407294ef",
+ "41698178 bef43b60 3932d79d 41419548 c092506e 3e178c01 -> 41d58b60 c0a19424 3e17c0b0",
+ "41301f48 c085eadd 3aae96d5 414f5cf4 401bb750 3ec51711 -> 41bfbe1e bfe03cd4 3ec5c8eb",
+ "419a80e6 400ade32 3ee638a3 4153fbf4 c00feb78 3ed11c1e -> 42023f70 bda1a8c0 3f5bac78",
+ "3d5e3a00 c0791028 3d32e2dc 408bc890 c02e4f38 3d28312a -> 408d8504 c0d3afb0 3dad8f93",
+ "417b9b10 c092083d 3dea70bd c064da30 c0434d00 392dc64b -> 41426484 c0f3aebd 3dead191",
+ "c1442aca c09a7edf 3e9c8296 4185ec12 bf8e4018 3c22aa07 -> 408f5ab4 c0be0ee5 3ea1993e",
+ "41013486 409dce28 411349e6 406cc4d8 c0384f55 3906a997 -> 413c65bc 40034cfb 41134a84",
+ "41883fe8 c04080bc 3b9031ed c13a103e 3ffec7fc 3d2ad296 -> 40acdf24 bf82397c 3d3cdf4b",
+ "c103d5d7 c04ef7c4 40050df5 c147ab64 c062d06e 3bee701b -> c1a5c09e c0d8e419 400585a3",
+ "c1630d02 c01c62d0 3aae1930 3f7288a0 4082fd1c 411e628e -> c153e478 3fd32ed0 411e6818",
+ "c198dc74 bfad5458 402d954c c14c2500 3fa70f7c 3edaac56 -> c1feeef4 bd489b80 4048eb63",
+ "c1999798 c08b6b2d 3b8f39cf c0d81026 c06d3892 3b286bff -> c1cf9ba2 c10103bb 3be47ffa",
+ "4112d2b6 4082d682 4047a976 3e815000 3feac8f0 3911751c -> 4116dd36 40bd88be 4047ac06",
+ "c143d8d4 3feb5698 3bad2a08 c183ef56 c07560b4 39015841 -> c1e5dbc0 bfff6ad0 3bb22aa8",
+ "c14c9a72 c09e3fb2 4011f073 c0e06c54 402ee528 39f3091f -> c19e684e c00d9a3c 4011f86c",
+ "c1502e4c c04df403 3989966e 419dfb2c 3f33a880 3fdcfb72 -> 40d79018 c02109e3 3fdd0463",
+ "c1698f24 401ca4d0 3d8ed4a8 40835250 c046e10e 3e18bda9 -> c127e5fc bf28f0f8 3e602ad5",
+ "c1429c03 4094191e 3934b29c 4050dc60 bed3f0d0 3ac811da -> c10e64eb 4086da11 3ae04be0",
+ "bf875cd0 3fb1d100 3d94be26 c14269b8 bfd9fd44 3aafc265 -> c1535552 bea0b110 3d9783fc",
+ "40c5c82c 408b12e2 3ae3bf97 416bcc84 c09fc547 3e089ef9 -> 41a7584d bf259328 3e0a6be5",
+ "4162e25c 3ffa0df0 3b3aefdc c1434486 c05bd9c7 40b655c5 -> 3ffceeb0 bfbda59e 40b66d35",
+ "c14129e4 4016dc5c 3ba1c513 c18f8dd5 bfa4ccb8 409df144 -> c1f022c7 3f88ec00 409e19fd",
+ "bfce3010 3f69f810 3cf37527 41065132 407abd58 3a19fd82 -> 40d91660 409a9dae 3cf85c5e",
+ "4196b4fc 3f7cb9e0 3d5e2cdb 40aca044 4060b570 39f63b31 -> 41c1dd0d 408ff1f4 3d60361a",
+ "401c2840 40991db6 3fdfba8d 4165532c bfcddb78 3e1a3ab9 -> 41862e9e 404b4db0 3ff30293",
+ "407e9138 c0155ba6 3f066940 418df834 401ec6ca 3cf1797e -> 41adca5b 3e16b240 3f0df673",
+ "c0c81450 c09fabbe 3f89aa7e c1813d52 bf953e0c 3ed2b735 -> c1b34266 c0c4fb41 3fbe593b",
+ "417ebfa8 bf473fc0 3b0ed4d9 40aaf218 40175c4a 3efba3aa -> 41aa1c5a 3fcb18b4 3efcc43f",
+ "4113c290 408e4972 392bae87 c181db44 407e628c 3c27a5e6 -> c0dfe7f0 4106bd5c 3c2a9257",
+ "c186fbca c0336dc5 3fd5089a c15bb82b 3fab62d4 3a4b7a6a -> c1f4d7e0 bfbb78b6 3fd52317",
+ "c17e4f2e bfccfa24 3c1d73e4 4101fe88 bef5ffc0 39aedb23 -> c0f8a14c c0053d0a 3c23122f",
+ "c1436fb3 3e249980 3fd2bc6f c19fc5cd bfab494c 4035f1f8 -> c200bed3 bf96b61c 408fa864",
+ "c0c33dea 406fe498 3a9c592e 414f592c 4017907a 3c649edb -> 40db746e 40c3ba89 3c785df6",
+ "416aadd0 4088c880 3ad48ab5 c17978ba c06e6f60 3c19d5f0 -> bf6caea0 3f0c8680 3c346d37",
+ "406d6fc0 3d56b580 3be5b98d c0ca2f3a 4069e7f8 3d33b783 -> c026eeb4 406d42ce 3d507513",
+ "40bf8cdc c04851fc 3be072ad 40a44270 409dea46 392d1b53 -> 4131e7a6 3fe70520 3be642fb",
+ "c0de4924 c0433ee2 40e31aac c157a670 bf1c5d00 3aa5d283 -> c1a36581 c06a5622 40e32547",
+ "417ccc20 40134e2a 3d9fd3aa c15eac68 401de870 39081670 -> 3ff0fdc0 40989b4d 3da01b12",
+ "c1488683 c01d50c1 3cd49268 c058cf60 c00665fb 3eae628a -> c17eba5b c091db5e 3ebbae4b",
+ "418b85d4 409d94c6 3a9736c8 c19f5aa3 c0795d65 40ad436b -> c01ea678 3f83984e 40ad4cf0",
+ "4116b37e 4061a7e8 3e37596b c0ecfaac bfbea410 3a4e476b -> 4000d8a0 400255e0 3e3828c1",
+ "3f71dbc0 400c3fd4 40234672 c1521090 bcc12100 3d51cdc4 -> c142f2d4 400abd92 40268ded",
+ "bfd35540 40025440 3ce2ffdb c19919c8 c03644db 3c1eca44 -> c1a64f1c bf4fc26c 3d194821",
+ "414a47d8 bf17dea0 3f1ec780 c0c4784c c05c911a 3de935f5 -> 40d01764 c0814461 3f3beef3",
+ "c1916699 c02a05bc 40438224 40cdad60 3ff62b18 38d44017 -> c13bf682 bf3bc0c0 4043840b",
+ "4153ebc0 bfe0de94 398acbb2 c1987a94 bf3967b8 3daefbac -> c0ba12d0 c01ec938 3daf8aa9",
+ "4032c440 3f4d25d8 3c00ce23 c080eb9c 3fa46bb8 39101093 -> bf9e25f0 40057f52 3c031bb6",
+ "c165921b c09b3af9 3f1b3d2f 418d1930 40921b68 3daf0b37 -> 40528114 be91f910 3f311eda",
+ "c13487da 40849f9e 3f44fad7 4149afd8 c048fd20 3e646eb4 -> 3fa93ff0 3f808438 3f7e16b9",
+ "c1478d36 bf8e20b8 3e9cd065 c1936b8d c013b024 39c8fdfb -> c1f73228 c05ac080 3e9d06f8",
+ "c10b66a8 4068470c 390ecaa8 4173650c bfcbf8a0 3a40d185 -> 40cffcc8 40024abc 3a66a682",
+ "bfda7920 bf25d600 3b1d52f8 4180b3b6 bef72500 3e19560b -> 41661848 bf90b440 3e1bcf41",
+ "c19a2ede bf550960 3f935710 4113c9cc c03caa0c 3a041469 -> c12093f0 c071ec64 3f93680b",
+ "41630738 c07cff94 3b206b65 c0f26390 bf1285d8 3f466c67 -> 40d3aae0 c090d085 3f470d91",
+ "c130c367 c09ae20c 3a00ef29 c059ef00 40569810 39238e68 -> c1673f27 bfbe5810 3a2dcef6",
+ "417907d0 3e9c4150 3b6af2b6 c1181382 c0750f27 3f2c1fa5 -> 40c1e89c c06186fd 3f2d0b3c",
+ "c19fc0d7 c018f729 3e70c30d 405511e8 be27e7a0 3d25a562 -> c1851e9a c02375a3 3e8d18a2",
+ "c0f2d0ca bfebde8c 3ca8a632 c1650349 403e0d94 3f338403 -> c1af35d7 3f903c9c 3f38cab1",
+ "4164c7c8 bedab820 3a596aa3 401150b0 c049de51 3a2e4aac -> 41848dfa c0653555 3ac65f87",
+ "4158f040 4096e590 3c4eaa0a c120ac0a 3fc850ec 3b89a304 -> 406110d8 40c8f9cb 3c89d167",
+ "c194d066 c09269b2 3dcc9aea c1280842 c09bd033 40812ecd -> c1e8d487 c1171cf2 4084618e",
+ "c0e10fd4 4023b5c6 3b4e7fb3 c1910e2b 40134b7c 40a85d93 -> c1c95220 409b80a1 40a877aa",
+ "bfad0c20 c0123d43 3e028996 41241724 c09fe4b1 39e25679 -> 410e75a0 c0e90352 3e02fed5",
+ "c0ec9b16 c085e00f 3aa32ebc c0a76ecc 3f12f1d8 3bfe6c93 -> c14a04f1 c06703a8 3c13dd1c",
+ "41631cc0 bfd698b6 3bafd95b c16255d6 bf440f08 3a0c0a5b -> 3d46ea00 c01c501d 3bc16ea0",
+ "c0c5f360 40212a5c 3dd7ad27 c0c082d8 3ef72a40 3c838e00 -> c1433b1c 40400fa4 3df89851",
+ "4186dcf0 c088b012 3b55a5c4 3fd48540 404b84a0 39286c92 -> 41942544 bf8bb708 3b61665c",
+ "bf9c3ca0 4046e420 3edd46e3 c126b36d c0830527 406b469a -> c13a3b01 bf7c98b8 408377dc",
+ "3fde8450 c0859371 40e5be8d c1046550 408ad0c0 3d995366 -> c0d1298c 3e27a9e0 40e823f7",
+ "c17c668c 3fd42d30 3cda1daf c131fca0 bf964a00 3e81b45f -> c1d73196 3ef78cc0 3e8f59af",
+ "4040b2e8 c04e3214 3b967089 c15d58eb 4000dd5c 40f95625 -> c12d2c31 bf9aa970 40f97be9",
+ "c0cd2686 c0756019 3ed38ba1 c14cd605 40565d44 408adb00 -> c199b4a4 bef816a8 409813eb",
+ "414f9cb0 402f21cc 3b085cc0 c14e2976 407fd030 3f0a7c53 -> 3db99d00 40d778fe 3f0b0526",
+ "40c12320 3f93a058 3ad40bff c02be1d8 3f83b340 3ba5d2e5 -> 40566468 400ba9cc 3bdb0234",
+ "c1506eca c08f4a30 3f9d840b c196841a c023dae1 40257a1b -> c1febb7f c0e137a0 40743ccb",
+ "4191f262 3fff6d00 3e90bd93 409c0a54 409531f8 3e22a01a -> 41b8f4f7 40d50d38 3ee21167",
+ "41059e42 bfec5d54 39b8c74a 411f3c64 407fdfd8 40ed1cec -> 41926d53 4009b12e 40ed2007",
+ "c1467e86 bfaeb2e2 3ae2cfae c192011f bea01000 3a25b22f -> c1f54062 bfd6b6e2 3b1cd9c4",
+ "c0f1a556 4088e176 3f2d2fb3 411897d0 3f35c740 3f2f97e2 -> 3ffe2928 409f9a5e 3fae640d",
+ "c01c47f8 c064dad2 3d9973bc 419d4b34 40998af0 3e3448d4 -> 4189c235 3f9c761c 3e8083af",
+ "c15967be bff3161e 4013ac5d 415a0ec8 c030bac9 39f9312b -> 3d270a00 c09522ec 4013b443",
+ "c1282e1b c03e6878 3f8b65b8 409e0918 be9e3dc0 3dab1186 -> c0b2531e c0523030 3f961720",
+ "40afa324 4080aa96 3ec19aec c11497d8 c02479f0 3ace3e64 -> c0731918 3fb9b678 3ec269de"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_sub(vec3, vec3)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "c1822c5d c06c6c8c 3da954e2 40ca1250 400bca78 3b79ce30 -> c1b4b0f1 c0bc1b82 3db1319b",
+ "c17577bb c034b30b 39e64c6a 41875d04 c04ae8d8 3fa86375 -> c2010c71 3eb1ae68 3fa872e9",
+ "c18b1ecb 400b07d6 3b9bf8c7 bfcb57b0 3f629090 3db5ee20 -> c17cd2a0 3fa4c764 3dbfb643",
+ "c17f24fc bfc11a9e 3a02dd69 c1782aea 40442bdc 3b0c849d -> bedf4240 c0925c96 3b2d8c2a",
+ "c0bc7c56 3ff05194 3ca0f276 c14bb870 c07f39c4 3e626cc0 -> 40daf48a 40bbb147 3e768e4c",
+ "c18f72c0 c0527a26 40490343 c0d27d8a 407eef24 3fe19eb9 -> c135a6bb c0e8b4a5 409ce97f",
+ "c18afdf3 3cc78d00 3dba0fda 40106250 400f8684 38e13d31 -> c19d0a3d c00df76a 3dba5321",
+ "c19dcef6 bfedd046 39034d06 419abf8e 3f150888 3f131283 -> c21c4742 c01c2a45 3f131d59",
+ "c120bc9e c04ec377 3b7250f4 c16f7a8f c05572db 403c9754 -> 409d7be2 3dd5ec80 403cd408",
+ "c1801724 4099e918 3b88b5a5 c0e9f1ae bff97158 39154507 -> c10b3571 40d8456e 3b8ddb82",
+ "4164d790 408b205a 39c85b9f bfcebfa0 406d9f88 38f04c84 -> 417eaf84 3f2284b0 3a065ac7",
+ "4187cfd2 40130130 3f9f1db2 bf0c6f40 bf86de20 398d3893 -> 418c334c 40567040 3f9f2737",
+ "419f6034 3ee61380 3e085ccb c16a96e9 c07c8cfe 3ced1a79 -> 420a55d4 408ca7b7 3e2609e3",
+ "c12219e9 bfa77a90 39e8ef41 41045a32 408a8218 4085d368 -> c1933a0e c0b460bc 4085d744",
+ "c0b928ca 40884a88 38dd3af9 c19e3a20 c029107d 40772c4b -> 415fdfdb 40dcd2c6 40772e68",
+ "3f80d690 401efcf0 3a7e28ac 401c2338 3ffe8200 3f62d21b -> bfb76fe0 3efddf80 3f6311d2",
+ "41797188 3ef1d050 3c8646c0 c19d8877 c08d1043 3fb1c0cb -> 420d209e 409c2d48 3fb3db33",
+ "418a8be0 40280a58 3f50cc52 c12e63ff c06e3af8 3e033c11 -> 41e1bde0 40cb22a8 3f719d8e",
+ "c113d8cc 40953450 4018c94a 41545398 c0896f77 409919de -> c1b41632 410f51e4 40e57ed0",
+ "41805d82 c05f82a2 38d66e9a c14502f9 c07d4390 40aa9ef9 -> 41e2defe 3eee0770 40aaa013",
+ "c19db3b3 408609f2 3cf15e1c 41807dde 40938f1c 3e2e5537 -> c20f18c8 bed852a0 3e4c8a13",
+ "4178cd44 bf212190 3fd9a1c5 4156a65c c0240871 3d7d0609 -> 40089ba0 3ff7801a 3fe18a24",
+ "c190322a c02708fc 3b687a9a c0feb49a 402f4274 3a3a2c0d -> c1210a07 c0ab25b8 3b8bfe26",
+ "c16521e6 c06e3066 3f7a9704 c095a400 4017648c 3b11ff6e -> c11a4fe6 c0c2ca79 3f7b2a0e",
+ "c192a11c 3ff78e78 3e7b15f2 c118bcd6 3fcc9b8c 3d61455d -> c10c8562 3eabcbb0 3e99b4d2",
+ "41380948 3ffce900 3c86537d bdc91400 c09fd4c3 3a03d879 -> 41399b70 40df0f03 3c8a976e",
+ "c0d3a16c c095f1ff 3f822432 c168e869 bfce6286 3e917afd -> 40fe2f66 c044b2bb 3fa68354",
+ "41304944 bf29fca0 3ed1f0b1 c0e9b394 4034b7ea 3fb7f7e6 -> 41929187 c05f3712 3fec74cf",
+ "40a142bc 3f802aa4 3bfb393b 415442b0 c08ff08a 40f3fe48 -> c103a152 40affb33 40f43d41",
+ "c161c58b 3f9ed530 3a55dd9a c1307537 40663df4 3b0ee9c0 -> c0454150 c016d35c 3b44b837",
+ "4195dc12 3fa31434 3f44ea9f c1014234 c090b175 3d5c40cf -> 41d67d2c 40b97682 3f52b0c3",
+ "c17644a2 3f04b750 3acc2198 c153685a 40953b36 3f03eea3 -> c00b7120 c084a44c 3f045521",
+ "c0a7e48e c09e1cbe 3f61b979 c17b3d64 3f89c974 3b56687f -> 41274b1d c0c08f1b 3f6290f7",
+ "3ff0ae70 400f9792 4065cabc 415db1d0 3fad439c 39508b4c -> c13f9c02 3f63d710 4065ce40",
+ "c1527746 4091e34c 3e30b86a bfab79e0 bfbf993a 3bf9d506 -> c13d080a 40c1c99a 3e388b95",
+ "41928e20 c0795b7f 3a3d2e79 3faca900 c054a08c 3eb88613 -> 4187c390 bf12ebcc 3eb8e6e7",
+ "418451cc be674880 3c0b12e4 c14f11fc c03e9528 3aba4722 -> 41ebdaca 403020a0 3c22dcc2",
+ "406e2610 bedfb250 3e1714eb 40ac28f0 bebe5840 392e99ff -> bfd457a0 bd856840 3e174109",
+ "c1481407 c0934413 38fd6b6b 4172cba4 3fe2e9f0 39f92f7d -> c1dd6fd6 c0cbfe8f 3a24c8b2",
+ "c0b770ac c071f9aa 4111fe63 410b3160 c06ecaee 39971781 -> c166e9b6 bd4baf00 4111ffa9",
+ "417f2d7c 3fbe5538 3a85662c 4167b4a8 c0388499 3ff3cf9e -> 3fbbc6a0 408bd79a 3ff3f136",
+ "403521a0 40567898 3fc68b14 c18721e4 c043e0fa 39ead170 -> 419dc618 40cd2cc9 3fc69a9e",
+ "41857ffa bfa5b06a 3d2725c9 40e70a7c c01dd7b4 3a4df89f -> 41177ab6 3f95fefe 3d2a6859",
+ "c03d99c8 3ebba210 3cef34a2 4083fa54 c00d5b36 3b69ed03 -> c0e2c738 4024cf78 3d0642d3",
+ "c0b333f8 c086d7b2 3c6fd8a5 c194642b c04eb288 3931c797 -> 414f2e5a bf7bf370 3c72d78e",
+ "410c5c58 c0428dca 3bb963df c103f2bf c00e3f76 3d6fda69 -> 4188278c bf513950 3d838c65",
+ "c196b82e 4013d4da 3adb1482 4131ccfe c08b99f8 3e0ce244 -> c1ef9ead 40d58465 3e0ea19e",
+ "c13c0ea6 c079d040 3fd90303 41772c98 4093e5d8 3b5fea8c -> c1d99d9f c10866fc 3fd97423",
+ "4090f354 3fe184d8 400ce4f9 41485034 c005682e 3db70826 -> c0ffad14 40762a9a 40129d73",
+ "407d1388 c002cfb1 3be6d34c 417a3ee8 3ca75300 39f2a062 -> c13afa06 c0041e57 3bf66b62",
+ "c0457678 3eb085f0 3e47d69c 413b0df2 bfb5403e 411c3b48 -> c16c6b90 3fe161ba 411f5abc",
+ "413302de 3f9de564 3998a2f1 4195f63e 3fc1eb34 3d279a51 -> c0f1d33c be901740 3d28d378",
+ "418b04e4 3fbd9920 3cbda048 4169d53c bf83e85e 3a38715a -> 4030d230 4020c0bf 3cc36e6c",
+ "bfb4ea50 be8634c0 39c85525 c16f1da7 bf450800 3d02cc76 -> 4158805d 3f01eda0 3d046b32",
+ "c14e84ec 40820612 40550b51 41269596 3ff990c0 41023f89 -> c1ba8d41 400743c4 41378282",
+ "c14a4593 c067af45 3ab6e835 c1789c7b bfb9aac8 3d356d45 -> 40395ba0 c00ad9e1 3d3b29a4",
+ "419648a0 bf5c7260 3f1213e2 415eac04 c07bd642 3ba20571 -> 409bca78 4044b9aa 3f135875",
+ "c1371a11 3fb91a58 390b53f5 c0c4eacc 4072466c 3e28d390 -> c0a94956 c015b940 3e28f858",
+ "c174e764 40156fa2 404749c1 c13fef39 bf3c8f38 39112b2f -> c053e0ac 40449370 40474c2c",
+ "c19aad12 c0023ff7 39bd23b7 c15b5fea 3f9325b8 3c953241 -> c0b3f474 c04bd2d3 3c983877",
+ "c18216ca c099c95d 408c4d83 c17928fc 40363210 3d17517e -> bf304980 c0f4e265 408d7c40",
+ "c10432c2 404ea640 3b3f9593 418df670 407d4400 4103a5fe -> c1d00fd1 bf3a7700 4103b21a",
+ "c0516b58 3f956d68 3be0d5ff 4131abf0 4083fe36 3f47b07f -> c16606c6 c03d45b8 3f49734d",
+ "bf741ca0 4053f07c 39105c18 c118f0df 3fb6f9f4 40cd5fbe -> 4109af15 3ff0e704 40cd6101",
+ "c1854a21 409ad4d4 3eb9254f c13f8f08 c081a12c 394d8c7d -> c0960a74 410e3b00 3eb940bf",
+ "c0525da8 4047f128 3f7cdce6 c10083dd 4022d998 398ee472 -> 4097d8e6 3f145e40 3f7cef28",
+ "c0654550 c07df114 3fff30e7 3ee4fe80 c08f2152 39470877 -> c080f290 3f014640 3fff3753",
+ "c0bfad62 c050d444 3fc5b759 4184fe0a 40346b9e 3f8ef703 -> c1b4e962 c0c29ff1 402a57ab",
+ "40ce0b20 c0270613 3c084950 c0d5bc2e 3fe7c3c0 3f547363 -> 4151e3a7 c08d73fa 3f5695ae",
+ "c041c7e8 4054c34c 3bf9e8e6 419568ca c0974a5e 3f813ba2 -> c1ada1c7 4100d602 3f823681",
+ "41413054 c08251dd 3edf733d c129c8a0 3e842250 3988d2c5 -> 41b57c7a c08a9402 3edf98e0",
+ "c14a2820 c073d6f8 40031a91 c10caccc bfaa057a 3f8e6746 -> c075ed50 c01ed43b 404a4e5a",
+ "4185eadc 4094cb20 3f47b8bf 419712c6 408372e8 3cb5cf85 -> c0093f50 3f0ac1c0 3f4d6773",
+ "c170d2e8 c0549055 3a8608be 4180a786 3ecb5b40 3ff3917e -> c1f910fa c06dfbbd 3ff3b426",
+ "40df4dec c084dca9 39edd73b c19b28ed 406fee1c 408260da -> 41d2fc68 c0fcd3b7 408264de",
+ "4106cc2c bf108ba0 397b8850 c18d16a6 4005f7a0 40c9d4b3 -> 41d07cbc c02a1a88 40c9d6f0",
+ "c0dc90e0 c0760e10 3e31bd6b 4122d8d0 40142434 3e534465 -> c18890a0 c0c51922 3ec283dc",
+ "418f2430 bf989b46 40125ed6 403f5880 bf5acf38 3ec2d9e1 -> 416e7240 beaccea8 402aba5a",
+ "c19e485e bef4bc40 4081dbdf 41824f88 405ba47c 3ffd7bf8 -> c2104bf3 c07a3c04 40c13b39",
+ "407d2988 407fe14c 3d6e84e3 416e24e0 3f1a41b0 3c8356e5 -> c12eda7e 405950e0 3d981f5e",
+ "4190a1c6 c053d646 3ad9ccd3 418ce36a 3f321c20 4084d641 -> 3eef9700 c0802ea7 4084e3ef",
+ "411549d8 40660300 3af8c3ba 414bd208 3fb8dbfc 3f72581f -> c05a20c0 40099502 3f72d4e9",
+ "414da9c8 bfa75770 3c791ef9 3fc7dba0 40918356 3a236624 -> 4134ae54 c0bb5932 3c81cd01",
+ "419ae388 c0801796 3e65fb66 c058f158 c09ce08f 3c54c079 -> 41b601b3 3f6647c8 3e734d67",
+ "c19fe398 40422d1c 3dcd9dcd c13557f3 becbbd70 3f8ed003 -> c10a6f3d 405ba4ca 3f9baa4a",
+ "c06e3f20 bee36a80 3d74c750 c13b9629 40419544 3d84f112 -> 41000661 c05e0294 3dff5a86",
+ "c04fe150 c09dbf38 3f919e9c 418f6e40 405a8c48 3d745c48 -> c1a96a6a c10582ae 3f994274",
+ "bfca9810 c04862c5 3f8bfe07 c16f1668 c084855e 3cbfe0ba -> 4155c366 3f814fee 3f8efe06",
+ "c0453f70 c08cd889 40aa0c53 c0879056 40785dd0 3ca47abe -> 3f93c278 c10483b8 40aab0ec",
+ "412d4320 3ebbff00 3a23f8cb 414db548 408cc700 3f2d6c8a -> c001c8a0 c0810710 3f2d95f4",
+ "c0e230ea 3e2a1cc0 3c224ff6 c009ded0 bf6278b8 3a668858 -> c09d4182 3f867ff4 3c30d063",
+ "c1266da2 3f927fe8 3d8bba70 416f50fc c0730c38 40af38a1 -> c1cadf4f 409e2616 40b167d3",
+ "c0c2e494 c0948ab9 3b00200d c1764eb5 40918b56 3fa68a38 -> 4114dc6b c1130b08 3fa6cae6",
+ "4093164c 406f4f38 3ec61cc7 c16f1796 403bf7ea 3c248088 -> 419c515e 3f4d5d38 3ecb4363",
+ "41693bb4 c09be3cf 3d8ce3ea c181af09 bf236530 3b0bb83b -> 41f64ce3 c0877729 3d915338",
+ "c077c178 3f794988 396311a2 c191974c 3f9fe9f0 3b89f906 -> 41653e3a be8d14b0 3b918670",
+ "c15c3180 c09b6da7 3f40c6a6 40983e60 40775738 3cba6acb -> c1942858 c10b8ca2 3f469bbc",
+ "41824898 3efaf940 409fad80 419f2ac4 c0912af1 3fe9a2cc -> c0671160 40a0da85 40da1652",
+ "c13e84f8 3fc723ac 3da642d4 c0d16da0 c03bd5e0 396033e4 -> c0ab9c50 408fb3db 3da6b7e6",
+ "c1906ef6 c04200de 3ed2c7ad 419fa0a6 3f513258 3c216367 -> c21807ce c0764d74 3ed7d811",
+ "409b4cd8 c0630f8f 3a4c24b3 c0feacba be95f530 3d2885fd -> 414cfcc9 c05050e9 3d2bc6ac",
+ "41739190 bffc8764 3c39b0ca 418aad08 4092f166 40a1610c -> c0072200 c0d2133f 40a1bdff",
+ "c190cce0 409eb5fc 410a79f7 c1227d79 c033a8c5 3adb3db8 -> c0fe388e 40f88a5e 410a80e9",
+ "bfc90e00 406ae630 40d9942c 4109c1a2 407b26e4 3f4cbf9f -> c122e362 be8205a0 40f32c44",
+ "40eb585c c08a9cc7 3c137e64 c19fa59e 409ed7aa 3c625377 -> 41da7bb5 c114ba38 3cbb3230",
+ "40828134 c05b72cc 3c6e60a6 c09ddc10 409f3c62 3f022ad3 -> 41102ea2 c1067ae4 3f05e575",
+ "c10463ee 3f87cf18 39812726 c0551900 c0753c07 3f05cb21 -> c09e3b5c 409c91ca 3f05dbec",
+ "c0160960 c013df0b 3e9b4d0e 40b4ee74 c0071d0f 3a93f998 -> c0fff324 be4c1fc0 3e9be218",
+ "c186dc9c 40419f8c 40f738c1 bf5eee20 3ec31860 3ebfbcd0 -> c17fca56 40293c80 41019a62",
+ "c02d9358 4081f264 3af0b2c8 c082f740 3f95faec 3c2b50ad -> 3fb0b650 4038e752 3c497827",
+ "c16b86de 4072dcc8 3b5ee874 419a7fe2 bfd7cd0c 3f831c11 -> c20821a8 40af61a7 3f838cc9",
+ "3ea33bc0 3fdaa88c 411d018f c1226ec8 4090f33a 3dee5cd5 -> 412788a6 c034922e 411ede60",
+ "c155850a c091edc0 3f104e4e c1315f8c c010bc06 3e062c91 -> c01095f8 c0131f7a 3f31d9c6",
+ "c1850d16 c0926586 3f469b78 c14c95e8 408736fe 3a7436ec -> c0761110 c10cce42 3f46d95d",
+ "bffd9090 c070d086 3dfee5e5 410b71b8 408e3b66 39966329 -> c12b23ca c10351d4 3dff85cc",
+ "beec5880 407d17b4 410cda31 40df45c8 c009bf62 3ac97d59 -> c0ee0b50 40c36b8b 410ce093",
+ "c0207ca0 bed410e0 409be95e 417c5970 c06aa2a4 3dfc20ca -> c1923c4c 40502088 409fda16",
+ "c1383507 4054b590 3fe27d0c c0ad8f92 bff0d3ae 3cf2214c -> c0c2da7c 40a68fb4 3fe645fa",
+ "4194a218 c03a0548 3e146873 40a58738 bfeec2e6 3d98fb0b -> 41568094 bf8547aa 3e60e9a3",
+ "40a12ed0 40908784 40c2e2e2 c17802cf 3ea58ea0 3a8f2fa8 -> 41a44d1c 40862e9a 40c2ec13",
+ "c14ad490 4039a828 3edb4b83 41822f98 4024f3fa 394b4f78 -> c1e799e0 3ea5a170 3edb68a3",
+ "409f0b2c bda4fdc0 3f200cea 3f03b060 4036bf9c 3f989acb -> 408e9520 c03be78a 3fe8a18a",
+ "40edfcec c04673a0 4060d030 c159ab2a 4095cf90 399415b1 -> 41a854d0 c0f90960 4060d552",
+ "c0c752a4 c0847524 3f92bfd6 c1701464 40222d88 3ef29f6d -> 410c6b12 c0d58be8 3fcf683a",
+ "bfd06690 4065d9a4 3da67285 c05b79a8 c0907a42 3b97b6c4 -> 3fe68cc0 4101b38a 3daff2f0",
+ "c10c879b bfe038b4 4088e44e 41131d7c 40072e04 3baa936b -> c18fd28c c0774a5e 40890f27",
+ "417ab134 bff92874 3977918b 413aea58 4019b2a0 3fa0f9d0 -> 407f1b70 c08b236d 3fa101da",
+ "41165aaa bef7b6b0 3c577b6f 414adab8 408de292 39d96d1f -> c0520038 c09d5dfd 3c5e67b2",
+ "40d3e1d8 beadeb70 41044fc8 416ab664 402ba682 3c8b8bb9 -> c100c578 c04163f0 410495a1",
+ "c0855ea0 c08d6016 391ff77b 419d30b2 bf064ff0 4047255b -> c1be885a c0792c30 40472856",
+ "bf7aa660 c0399bfe 3c8712e0 c03d36c8 c02b3d60 3ca4cec8 -> 3ffd1a60 be65e9e0 3d15f311",
+ "4178fa08 4091f07c 3ccab81b 40288990 c0145c5c 3e530a87 -> 414ed7a4 40dc1eaa 3e6c668c",
+ "c19b0497 3f05b158 3bafcea1 419d6d9e bf8cde1c 3b538b75 -> c21c391a 3fcfb6c8 3c0d6cee",
+ "c0f17e0c 3fb630ec 40729f4a bfd4c840 401f30ac 3da76207 -> c0bc4bfc bf88306c 4077da85",
+ "c0c07cac bf5cf7f0 3d7895e4 bf4d0100 bfd46668 3e3c87c8 -> c0a6dc8c 3f4bd4e0 3e7aaed1",
+ "c0f78ad4 408027e8 3ff909af c14f58be bfead686 3d37507f -> 40a726a8 40badd8a 3ffec49b",
+ "c09e1d00 bff4af4a 3aa375de 41942f94 4088f058 410a489b -> c1bbb6d4 c0c61c2a 410a4ddd",
+ "40b9679c c08018bc 3a7fb86a c0e586de 4060bf90 3a9d8c09 -> 414f773d c0f07884 3b0ffbdb",
+ "c17fc6fa bf762a30 3e60af69 41165642 3fe640d4 3f87e4a6 -> c1cb0e9e c030aaf6 3fa3fb7e",
+ "419a82ec c09a88af 3ca5d29f 416703ac c08787ae 3f9ed8ca -> 409c0458 bf180808 3fa1704a",
+ "41814f68 bf68d7a0 3e03e9ff 41507030 c01a1834 3be1ea52 -> 4048ba80 3fbfc498 3e0afa83",
+ "41433398 40594f90 3ac5ae44 414a147c 3f93d378 3985626f -> bedc1c80 400f65d4 3ae75c63",
+ "c1859116 bfc23c58 3ebf1c49 4189182a 4048b328 3e341649 -> c20754a0 c094e8aa 3f0c9628",
+ "c093ac0c c096bd73 3d85042b c0cbfa10 bf9a122e 408f4d60 -> 3fe13810 c06071cf 40916185",
+ "419b1fa6 3f379150 3aa62838 c18f29e6 c0445e97 3b4df027 -> 421524c6 407242eb 3b91cabd",
+ "c189f25c 3e1edd00 3abe44b3 c07ee848 c08d1fd6 3d20fd7e -> c1542aa6 409216be 3d270182",
+ "c0ac600a 404c43a0 3fcbf809 41534b1c 3e208fa0 38efbcb7 -> c194bd90 40423aa6 3fcbfc82",
+ "4199b14a c009db74 3f5fdfc5 405f1928 3fc2f0dc 3b95253a -> 417b9c4a c06b53e2 3f610b54",
+ "c182f21c c08e953d 3a88714a 4147d130 be7264c0 39353dba -> c1e6dab4 c0870217 3aa33b78",
+ "c11c01d6 3f226f68 39131e8f 40f579b0 405a30e4 3e8c3dc4 -> c18b5f57 c031950a 3e8c52b7",
+ "c161db92 40218764 3e2ea74c 418b98c0 401df930 39a5bf30 -> c1fc8689 3d638d00 3e2f021f",
+ "415f30dc 3fe92fcc 3b37273f c142ded0 3f218160 41161021 -> 41d107d6 3f986f1c 41161bb8",
+ "41457b68 3f0b7b78 3d16e2ba 400249d0 bfb2bf38 399c94ce -> 4124e8f4 3ff87cf4 3d18282d",
+ "c1653460 bf830dfc 407d0f49 4178f0d0 4093c836 3a017f6c -> c1ef1298 c0b48bb5 407d17ff",
+ "c1814aae c01bb5e8 3924a2fd c149b3d2 c063b83d 3cf612f6 -> c0638628 3f9004aa 3cf765a8",
+ "bed79300 3fde264c 40f915b4 c15e1cbd 3fea4d58 3f27c326 -> 41576025 bdc270c0 41070722",
+ "c0ac7c52 c091e775 3d481209 40f11fa0 4018956c 40e2db62 -> c14ecdf9 c0de322b 40e46bbc",
+ "c1927175 407cfa98 3cea78d5 c13a3412 c09ed51d 4082207e -> c0d55db0 410ea934 40830b1e",
+ "3faf7b40 40036bb6 3a87d489 418b0068 3eff89c0 3c86e092 -> c18008b4 3fc6f4fc 3c8f8102",
+ "412b9792 c01acc62 3f65a980 3e9c48c0 4059c6d8 3ce73b1d -> 4126b54c c0ba499d 3f6ce46c",
+ "c18c8c1b 3fd1c960 3d48969c 413bfd02 4003ddc8 40336929 -> c1ea8a9c bed7c8c0 40368c05",
+ "c19ad19b 3fc73050 4011aaf2 411ffa8a c0492f63 3b7a0920 -> c1eacee0 409663c6 4011ea05",
+ "40129c08 beee2180 3e4a7203 418fc5b0 405dd3b8 3961940b -> c17ae45e c07b97e8 3e4aaf5c",
+ "40bcad6c 40779eb8 3af16c3c c174e6b6 3fc0b988 3c801dd6 -> 41a99eb6 401741f4 3c8f63c5",
+ "c104d6fa 3f0d0a50 39d9aac2 3fb2d710 bf93689c 3c5a491e -> c11b31dc 3fd9edc4 3c61441e",
+ "4197454e 4064df94 3a88e443 c190c1df 3fa35008 39774681 -> 42140396 40133790 3aacb6d6",
+ "c02dbe68 c020dfed 3a6798aa 40824ff8 c04490dc 3bb42405 -> c0d92f2c 3f0ec3bc 3bd151e9",
+ "c18fdeae 4035f4dc 3d227f08 41778c28 bf9d4c60 399f196b -> c205d261 40824d86 3d23e2cc",
+ "4135d448 404c0c34 3c3b1530 410f6126 40668b90 40bb1176 -> 4019cc88 bed3fae0 40bb6f12",
+ "c1284539 408de740 38f47fd4 c18045f5 3c53fe00 3a1507ea -> 40b08d62 408d7d41 3a361404",
+ "412a2b46 be3fe160 3b1409f0 c008eb80 40316ff0 3b8f17d3 -> 414c6626 c03d6e06 3bd99ab9",
+ "c177faec 3dc55800 3fac7903 4058cb68 3e2faf80 3dc8128f -> c19716e3 bd9a0700 3fb8facf",
+ "41717904 c09168a2 3e972c0a 41819b58 c08a94ac 40093d0e -> bf8ded60 be5a7ec0 401c229e",
+ "4186207a bf718c88 3a4b7302 c19749bd 40208698 3d8a7b50 -> 420eb51c c05ce9ba 3d8c25cf",
+ "c19bb66a c020d688 411b4280 c11fbdea 4046c17c 3e86e31b -> c117aeea c0b3cc02 411f79b2",
+ "c18c6b97 bfd5c762 3f0b9dd2 c193bf31 4056fcb4 3eb90cfc -> 3f6a7340 c0a0f032 3f6824be",
+ "c187476a 3f84fb08 38e379fe c14555f3 402f8714 400b2c2f -> c09271c2 bfda1320 400b2e18",
+ "c112de67 c0405e91 3b5342b3 4148ac3c 405de820 3f977ae3 -> c1adc552 c0cf2358 3f97e56f",
+ "c11a076c bfd6f7d4 401a6f2a c161dffd c04cccde 399db19f -> 408fb122 3fc2a1e8 401a743a",
+ "41975938 4018bec0 3ee5dd2d 41030cf8 bf2b3830 3d33f177 -> 412ba578 40438ccc 3efc5d25",
+ "c0d8c5ec 4067c300 3ea033e6 c16545b6 3e70a0a0 3a5a7911 -> 40f1c580 4058b8f6 3ea0a28b",
+ "41606790 4058f768 3a928667 419a612a 4051c584 3ca9482b -> c0a8b588 3de63c80 3cb27b61",
+ "4165e2f8 401196e6 3e12f720 c0f28c94 40244aec 3d6a12fc -> 41af94a1 be95a030 3e4d817b",
+ "c116d1bf c0401912 3c2794e4 c14b08d0 409d24c2 3cca4004 -> 4050dc44 c0fd314b 3d0f1071",
+ "4144e1ac 40848468 3a1891d7 40c229ec c08b1868 39a0a220 -> 40c7996c 4107ce68 3a6c9162",
+ "4199f8f4 bfa33796 3a3b3e7e bf5c1880 40670d04 4068babc -> 41a0d9b8 c09c5468 4068c6e3",
+ "c1543a35 c06d98b0 3e756d03 c174cd6e 40942256 38e534c7 -> 40024ce4 c1057757 3e758c52",
+ "40865590 c00ec9c1 3d0814fe c05d8530 c007c2f7 3c95f54f -> 40f51828 bde0d940 3d531778",
+ "bfb6f560 3fcff16c 4101fd02 c14d69d6 bf188528 3ac03f7a -> 41368b2a 400e1a00 4102031a",
+ "c16efae0 c0615a27 40110700 c132d421 bfd44ec4 3de42961 -> c0709afc bfee658a 4018286b",
+ "c1960541 c040ad63 3f3d1583 c1780beb c09f97ca 3c9acf32 -> c04ffa5c 3ffd0462 3f41ec5d",
+ "c104f269 bf98b6fc 4009910e 410c51b6 c0650c14 3e0d45d6 -> c188a210 4018b096 401265c2",
+ "41704dc4 c0620450 3ac88423 c0875ec8 3f473198 3ebe9ee9 -> 4199fe94 c089e85b 3ebf6a6b",
+ "4197bf6a bf877a10 3e0a859a 41004cf0 c0480c61 3c2958db -> 412f31e4 40044f59 3e151e72",
+ "c17635df 40415bc0 4092609e 418c0044 bfbd8d52 3ebc545f -> c2038d9a 40901134 409e2639",
+ "c192dab4 408f4cf6 3f70a08f c18ab4ea c0846176 3f2917f5 -> bf825ca0 4109d736 3fccdc9c",
+ "c12a377b bd992980 3b1c86b4 c190515f c0726ee4 405bd425 -> 40ecd686 406da598 405bfb81",
+ "405c4968 401ccfa0 3d23b525 c0badf98 bffb6f32 3b40765f -> 41148226 408d439c 3d2fca48",
+ "419ed462 4014b484 3d911dc4 c15b99c6 c02252f6 40a055e2 -> 420650a2 409b83bd 40a29ab0",
+ "419a9aba bfd8aee6 38ef7369 c0a55c88 409f14fa 3a81cb85 -> 41c3f1dc c0d540b4 3a94a7cd",
+ "3f6dbd20 bfb9e5e2 39120c48 c15ddd48 3fe40e40 3a757dd5 -> 416cb91a c04efa11 3a8f416c",
+ "415554f0 4045b798 395284ef bf8a7e60 c05977e9 398bf682 -> 4166a4bc 40cf97c0 39ffac8e",
+ "c01d4a38 408810ca 3b17cdc9 410c3340 c076c568 3c857ba8 -> c13385ce 4101b9bf 3c989c12",
+ "4174d1b0 402739ec 3cfec80c 40b144f0 408d2be4 3e00437e -> 411c2f38 bfe63bb8 3e201f6e",
+ "c1647248 4075e460 3ea4a051 4162f908 c0854fa4 3f198933 -> c1e3b5a8 410020ea 3f6bdbb2",
+ "41219310 406876c8 3cf5a9fd c187876e 3e840b80 3f2df027 -> 41d850f6 4057f558 3f359f69",
+ "41722d5c bf2c4178 39626208 c0deaa6a 3e53b480 3cf388a8 -> 41b0c148 bf612e98 3cf57b6e",
+ "c12adb94 3e6f8900 3d949d48 bf1bc3e0 400bb8c8 3b843615 -> c1211f56 bff98070 3d9ce6b5",
+ "40d5c794 c016fdcb 3a9e1f14 4030ebf0 bdeffe80 3ac6053e -> 407aa338 c00f7dd7 3b3274bc",
+ "41006154 40763958 3c3fa001 c06866a0 c09cb580 3f6ecf09 -> 413a7afc 410be916 3f71cedf",
+ "be925c40 40992df0 3ed93b06 c0f9abd8 400d1d24 3b4829a3 -> 40f08614 40253ebc 3edaccaa",
+ "406623c8 bfb08764 3c22bd70 3e85b9c0 405a05e4 3e83296b -> 40556c90 c09924cb 3e884062",
+ "c09f48fe 3f109b90 3ad1371e c19ebebc bf7207d0 3c4907f7 -> 416dd8f9 3fc151b0 3c63706a",
+ "c190d3cd 3fca93ec 3a31024c c0993d28 c047eac0 3f9fe603 -> c1550906 40969a5b 3f9ffcbd",
+ "3fc93480 c04aa7ed 3bf590be c119e348 bf9ee062 3e244b97 -> 413309d8 bff66f78 3e2bfb6f",
+ "c0bc6278 be9dc7f0 3c541c1f c1115a40 40553dac 3d520a46 -> 404ca410 c068f6aa 3d838c1a",
+ "412c39f4 4088fd2c 3f845927 c10fe4e1 407cbad0 3bc5f77a -> 419e0f6a 3ea9fc40 3f851fc7",
+ "4186f5ac c0594a04 3c56888d 3fb11800 c0442084 4091ec09 -> 4177c858 bea94c00 40925776",
+ "419e78b2 3ffbbd9c 3ccc0c1a 419eab08 bfb0e41a 3bbc9acc -> bcc95800 405650db 3cfb399c",
+ "40a3ee50 c077f44e 3f66f38c 4181fc2e 402a0384 3d46a33d -> c1320134 c0d0fbe9 3f735eea",
+ "41870d4a bfd9278e 410882a5 4125580a c05da0f6 3bebf5b3 -> 40d18514 3fe21a5e 4108a035",
+ "c11a0fab c07e4a40 3ed3b85d 40fe3e7c c029b76b 3cc7a0d3 -> c18c9774 bfa925aa 3ee034d5",
+ "4093079c 402e3d46 3f27ec19 41462f20 bed44f50 390f5302 -> c0f956a4 4048c730 3f27f5c7",
+ "c0853b98 c09e7e38 410e4507 c01189b0 c016d4ad 3e7edfef -> bff1db00 c02627c3 41124095",
+ "c1587334 bfb70e98 39b47efa c1897834 3fb95d30 3ecd490a -> 4069f4d0 c03835e4 3ecd7708",
+ "412098c4 40684198 3a2a1f29 c115e9a7 bfbbfee4 3d882845 -> 419b4136 40a32085 3d8988cc",
+ "c0a6600c c0576cb6 38e2be20 c18f614a c00fcd54 399544c5 -> 414b928e bf8f3ec4 39d4e02d",
+ "c13a900c c0022ddb 3ca6fa9d c19f6435 bf985b78 3db5985f -> 4104385e bf58007c 3ddf5ba2",
+ "4062ef98 404bc808 3e3ec2f0 4128e75e 3dd2c500 3f234703 -> c0e056f0 404531e0 3f52f86e",
+ "3ff263d0 be583000 39603c6f c0f70904 3f772d00 3f768228 -> 4119d0fc bf969c80 3f7690e8",
+ "c116fa2c c0471f42 3c9f778e c19f2463 408f433e 3bed2886 -> 41274e9a c0f2d2df 3cdae5d5",
+ "c0ece638 bfc12516 3c4c2f40 c140bf74 bf1a8360 3b43f3e3 -> 409498b0 bf67c6cc 3c7d427b",
+ "c1997bd7 bfc7b670 3ee320a6 417f4ed8 c029d260 40dcb41a -> c20c91a2 3f8bee50 40eae67b",
+ "c134e537 c059aaca 40f2ca05 3f368620 be3ac500 3fad7a8d -> c1404d99 c04dfe7a 410f146c",
+ "c18ab1d0 409bd8b2 3bbde2f7 c07c2488 400bc9de 40167256 -> c1565a7e 402be786 4016d191",
+ "bd724e00 c08bd5c2 3d8bd125 c1398f65 40383798 398dd39d -> 41389d17 c0e7f18e 3d8c6866",
+ "40aa4528 c03c4747 3bb5f29b c1833863 3fef5564 3917549c -> 41adc9ad c099f8fc 3bbb8194",
+ "c152ec0c bf8d094c 3c004e3e c0b49a5e 401bdf0c 3a31e10b -> c0f13dba c06263b2 3c0b98a6",
+ "c195e878 3fbdfb40 3ada1d05 c1808c24 c0834fa6 3c79de12 -> c02ae2a0 40b2ce76 3c8aa166",
+ "414d3fe8 401d9d74 3eafb8a6 40a84130 408b8d6e 40cb7ba4 -> 40f23ea0 bff2fad0 40d6774e",
+ "c199d239 40844b04 3e11ca63 3fe5c950 400032dc 3bfa5f94 -> c1a82ece 4008632c 3e19a333",
+ "41121abe 404697b4 3d77315c 40b6fdec c015d3bc 391225d8 -> 405a6f20 40ae35b8 3d77cc6d",
+ "40981b08 c06e7471 3cbda82b 418e20d0 bfc35726 39971c7f -> c150341c c00cc8de 3cc02316",
+ "c0060948 4004e98e 3ad83497 c148c5ef bfa67066 396abcdc -> 4127439d 405821c1 3af746d9",
+ "40a66860 bf7f6818 40eb7c48 c16cadfd bf8d9e98 3929360c -> 419ff116 3ddea8c0 40eb7dd1",
+ "c09a7640 c09f7f01 3b123bd8 c08f12dc c089662a 3f3cd30b -> beb63640 bf30c6b8 3f3d6564",
+ "c07cfb18 3fa0b594 3e8f7b30 c19f50e5 3fa73024 40946289 -> 417f6304 bd4f5200 409d5a66",
+ "408d085c bf8e9fcc 3c05fc64 c1362588 be525cc0 40cf2d5f -> 417ca9b6 bf68a868 40cf708b",
+ "419465c2 4070fe48 3c21bf34 4093696c c04a5d17 3ab5d1ac -> 415f16ce 40ddadb0 3c38ccf1",
+ "410b02c0 4055217c 3d559847 401b5d68 4084c27c 3b4f6e3c -> 40c856cc bf518df0 3d62964d",
+ "c077a470 3f7b22f0 3c508273 3f1530c0 c01745eb 3b096e29 -> c08e7850 40560ea7 3c72fd3c",
+ "4125d70a c02c690f 39499e8b 40ff2bb0 3edc0330 3ed02f82 -> 401904c8 c047e975 3ed04973",
+ "c079c0a0 bf0b8220 397e9fb6 c0f2ea00 3f42d788 41012652 -> 406c1360 bfa72cd4 4101275e",
+ "40eff5c0 bf5a9920 4080893e c19c70af c0557982 3d161b32 -> 41d86e1f 401ed33a 4081b5b7",
+ "40b6a23c 4029102a 3f9d0dd3 c192c9b8 3fdae7a8 3aca1970 -> 41c07247 3f6e7158 3f9d412b",
+ "c12cb990 4059e9e0 3eb717a5 c08d88c0 3f7d1d40 391877af -> c0cbea60 401aa290 3eb72bd9"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_neg(vec3)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "3efc0ac0 c081676f 39dcef73 -> befc0ac0 4081676f 39dcef73",
+ "c17458ea bedfe490 3ae60300 -> 417458ea 3edfe490 3ae60300",
+ "4181bea0 c016ca53 3b988793 -> c181bea0 4016ca53 3b988793",
+ "40e29ec4 c037db20 3efba417 -> c0e29ec4 4037db20 3efba417",
+ "c15f2030 bf6e2100 3afc5f9a -> 415f2030 3f6e2100 3afc5f9a",
+ "401eda20 406edc78 3d01ebd0 -> c01eda20 c06edc78 3d01ebd0",
+ "c09a7dcc bf8a0f7a 3c6be155 -> 409a7dcc 3f8a0f7a 3c6be155",
+ "41829a4a 406e01f0 3d00bee8 -> c1829a4a c06e01f0 3d00bee8",
+ "c008d338 400b6a78 3d809c4e -> 4008d338 c00b6a78 3d809c4e",
+ "414c45b4 be9d84c0 3ea699b5 -> c14c45b4 3e9d84c0 3ea699b5",
+ "c19c6e18 c09bd5e4 3fdaf64f -> 419c6e18 409bd5e4 3fdaf64f",
+ "c191beec 403eaaaa 3ccef4d8 -> 4191beec c03eaaaa 3ccef4d8",
+ "416421b0 3f314f30 40c6150f -> c16421b0 bf314f30 40c6150f",
+ "40dc1108 c07c5ea0 404f3bad -> c0dc1108 407c5ea0 404f3bad",
+ "c14d4b76 409500de 3d6a2cd1 -> 414d4b76 c09500de 3d6a2cd1",
+ "c186922e 40798cc0 3b08fc23 -> 4186922e c0798cc0 3b08fc23",
+ "4199d34a 3fd71fd0 40db8808 -> c199d34a bfd71fd0 40db8808",
+ "c139556f c09cc2be 3a8da2bd -> 4139556f 409cc2be 3a8da2bd",
+ "40811a2c 3f855780 3aac3dd7 -> c0811a2c bf855780 3aac3dd7",
+ "40a09834 3fdbb7c8 3efc058f -> c0a09834 bfdbb7c8 3efc058f",
+ "40f24048 c0846439 3f721cc9 -> c0f24048 40846439 3f721cc9",
+ "40a7cebc 3fd45724 3a82a2fd -> c0a7cebc bfd45724 3a82a2fd",
+ "417aab4c c07ba257 3de353b4 -> c17aab4c 407ba257 3de353b4",
+ "4130e6d8 400394d8 3b58e883 -> c130e6d8 c00394d8 3b58e883",
+ "3fd6a7c0 4004b898 3b315857 -> bfd6a7c0 c004b898 3b315857",
+ "3f978b60 4012800c 40597cfb -> bf978b60 c012800c 40597cfb",
+ "418f5f50 bfaa20e2 3fb08496 -> c18f5f50 3faa20e2 3fb08496",
+ "c102d8f6 40589f20 3f81bbed -> 4102d8f6 c0589f20 3f81bbed",
+ "4116891c 40407940 38d8d03d -> c116891c c0407940 38d8d03d",
+ "40b31230 bf102bc0 3a73ece7 -> c0b31230 3f102bc0 3a73ece7",
+ "c11baa72 c02c2a6c 4044e2bf -> 411baa72 402c2a6c 4044e2bf",
+ "c13342ac 409a742e 390317c6 -> 413342ac c09a742e 390317c6",
+ "c17b9572 3ef66960 3b4ea273 -> 417b9572 bef66960 3b4ea273",
+ "c0bdcaba c047cfa8 3f52bc88 -> 40bdcaba 4047cfa8 3f52bc88",
+ "40c65e00 c03d4043 40cfbae4 -> c0c65e00 403d4043 40cfbae4",
+ "40d10974 3fd7ab38 3b55e65c -> c0d10974 bfd7ab38 3b55e65c",
+ "41867c16 c089322a 40183c16 -> c1867c16 4089322a 40183c16",
+ "c0e9a1fe 3fe31af8 3b5a6eb3 -> 40e9a1fe bfe31af8 3b5a6eb3",
+ "41835da0 bf880dc6 3ae3446e -> c1835da0 3f880dc6 3ae3446e",
+ "419e1362 407d5e40 40077fa0 -> c19e1362 c07d5e40 40077fa0",
+ "c142090c c01eddcc 3e53d510 -> 4142090c 401eddcc 3e53d510",
+ "c058c758 3e491480 3cc161a2 -> 4058c758 be491480 3cc161a2",
+ "c06fbce8 bfe3d0b8 3ed72f65 -> 406fbce8 3fe3d0b8 3ed72f65",
+ "c11512ed bf45e480 3a521ad5 -> 411512ed 3f45e480 3a521ad5",
+ "40885414 3f768ff8 3a4e89ca -> c0885414 bf768ff8 3a4e89ca",
+ "c191a8b0 3fb3f014 3e17c487 -> 4191a8b0 bfb3f014 3e17c487",
+ "4158c470 c088fdd0 39f0554f -> c158c470 4088fdd0 39f0554f",
+ "410017c8 400c90ec 3bee8913 -> c10017c8 c00c90ec 3bee8913",
+ "c0e85992 408c9346 3d6ffc55 -> 40e85992 c08c9346 3d6ffc55",
+ "406e2e50 bff3fbd6 3db45b36 -> c06e2e50 3ff3fbd6 3db45b36",
+ "412dd162 c077bc38 3e3ada16 -> c12dd162 4077bc38 3e3ada16",
+ "c02770a8 c05cdc50 40993420 -> 402770a8 405cdc50 40993420",
+ "c1733982 c0269f2a 3e87b1cd -> 41733982 40269f2a 3e87b1cd",
+ "bef886c0 c01b8c0b 3bb0eef3 -> 3ef886c0 401b8c0b 3bb0eef3",
+ "4047c6c8 3fc41630 3e331c67 -> c047c6c8 bfc41630 3e331c67",
+ "40f8f1ac 400704f8 3985649c -> c0f8f1ac c00704f8 3985649c",
+ "c16fd2e3 406a0ca0 3f153e8d -> 416fd2e3 c06a0ca0 3f153e8d",
+ "40917218 c05c9daa 3fa8b5b4 -> c0917218 405c9daa 3fa8b5b4",
+ "41150eae bd083500 3d3b84ad -> c1150eae 3d083500 3d3b84ad",
+ "c105f0cb c0810286 3da35083 -> 4105f0cb 40810286 3da35083",
+ "4186bb96 40488534 38f28adc -> c186bb96 c0488534 38f28adc",
+ "c1691f07 bd391380 3b67f446 -> 41691f07 3d391380 3b67f446",
+ "3f921f90 c051f9cd 3c83f4d7 -> bf921f90 4051f9cd 3c83f4d7",
+ "c1244eec 4087f412 3c25970f -> 41244eec c087f412 3c25970f",
+ "418fd878 bfbeeeb8 3f9807bb -> c18fd878 3fbeeeb8 3f9807bb",
+ "4136e5ae c071d9ea 39615327 -> c136e5ae 4071d9ea 39615327",
+ "410f4498 3f9eb4c0 3ab59e4a -> c10f4498 bf9eb4c0 3ab59e4a",
+ "bf8d0b20 bea50c50 3c87765c -> 3f8d0b20 3ea50c50 3c87765c",
+ "4156ee2c c05ae7ae 40c4766a -> c156ee2c 405ae7ae 40c4766a",
+ "4152150c 40011528 3e4831f0 -> c152150c c0011528 3e4831f0",
+ "c0760c98 4052b74c 3a07b3be -> 40760c98 c052b74c 3a07b3be",
+ "c17d3c4a 3f2b1280 3c876602 -> 417d3c4a bf2b1280 3c876602",
+ "c0d4af2c bf13bd18 3a21199f -> 40d4af2c 3f13bd18 3a21199f",
+ "c0ce5c96 c055cb1d 3d4b109b -> 40ce5c96 4055cb1d 3d4b109b",
+ "40b2d260 40747c08 40a1f3e9 -> c0b2d260 c0747c08 40a1f3e9",
+ "c0bd2c44 3fd21040 3f86bc07 -> 40bd2c44 bfd21040 3f86bc07",
+ "c19d1b45 408f1480 3bf48100 -> 419d1b45 c08f1480 3bf48100",
+ "bfafa460 3f2b2a70 3cbd8640 -> 3fafa460 bf2b2a70 3cbd8640",
+ "c0bd6db0 bf039dc0 3baf102b -> 40bd6db0 3f039dc0 3baf102b",
+ "40308058 c0000d36 3b9f9b7c -> c0308058 40000d36 3b9f9b7c",
+ "c0bd3cb4 40002ee8 3cb7dd1f -> 40bd3cb4 c0002ee8 3cb7dd1f",
+ "41353bca 4059343c 399d9fce -> c1353bca c059343c 399d9fce",
+ "c11aceae 405ced38 3f54f414 -> 411aceae c05ced38 3f54f414",
+ "c0a4bcac bef615e0 3e8056d5 -> 40a4bcac 3ef615e0 3e8056d5",
+ "4182cb38 bf931a3c 3c9fceab -> c182cb38 3f931a3c 3c9fceab",
+ "40f245a0 4054f56c 3dadd37d -> c0f245a0 c054f56c 3dadd37d",
+ "3de87e00 be27bb00 3cf157c5 -> bde87e00 3e27bb00 3cf157c5",
+ "c15df840 404c4b94 3f17baeb -> 415df840 c04c4b94 3f17baeb",
+ "c10a7494 408c38b4 3b0665ac -> 410a7494 c08c38b4 3b0665ac",
+ "40d98aa0 40217a8e 39cc87d7 -> c0d98aa0 c0217a8e 39cc87d7",
+ "c1809bfe 40298852 3a07048f -> 41809bfe c0298852 3a07048f",
+ "414cec08 409bb808 3cae75e9 -> c14cec08 c09bb808 3cae75e9",
+ "c189f923 40642d68 392b49e8 -> 4189f923 c0642d68 392b49e8",
+ "415cf3a4 c081e3ba 3f9f2401 -> c15cf3a4 4081e3ba 3f9f2401",
+ "c199752a 3fb04f9c 3cf5184a -> 4199752a bfb04f9c 3cf5184a",
+ "40f94778 3f11d420 3a548d8e -> c0f94778 bf11d420 3a548d8e",
+ "c19b4276 3fd04cb0 3df5c4e7 -> 419b4276 bfd04cb0 3df5c4e7",
+ "41264450 c08ad872 3f9a6bce -> c1264450 408ad872 3f9a6bce",
+ "415bf32c c040a61b 4022c343 -> c15bf32c 4040a61b 4022c343",
+ "410a04e4 bb9f4000 404d2cf2 -> c10a04e4 3b9f4000 404d2cf2",
+ "4155442c 3f61b010 3998c251 -> c155442c bf61b010 3998c251",
+ "40d42fec c011265a 3e8b7831 -> c0d42fec 4011265a 3e8b7831",
+ "3fbfbb60 c083aacc 3c20f371 -> bfbfbb60 4083aacc 3c20f371",
+ "419d8fc2 3f9a2a2c 40f35cea -> c19d8fc2 bf9a2a2c 40f35cea",
+ "3fdcd500 3fc9baac 3c1139e1 -> bfdcd500 bfc9baac 3c1139e1",
+ "40dfea98 c06b0ded 3a53c74c -> c0dfea98 406b0ded 3a53c74c",
+ "c119ff97 3f639ec8 3c03fedd -> 4119ff97 bf639ec8 3c03fedd",
+ "c1863586 3fc69470 39930bb8 -> 41863586 bfc69470 39930bb8",
+ "3dc47600 bfcef89a 3e9fa9ab -> bdc47600 3fcef89a 3e9fa9ab",
+ "c0dea116 40987c6c 3f5e0854 -> 40dea116 c0987c6c 3f5e0854",
+ "40588aa8 bfbbee54 3bc7c364 -> c0588aa8 3fbbee54 3bc7c364",
+ "c1657b07 c09c2844 3d0ab028 -> 41657b07 409c2844 3d0ab028",
+ "4110a83a bfba0494 3bd9d851 -> c110a83a 3fba0494 3bd9d851",
+ "414536d0 c05b53b2 3cb4194b -> c14536d0 405b53b2 3cb4194b",
+ "413554e8 c098d237 392aa221 -> c13554e8 4098d237 392aa221",
+ "40b2b63c c035564f 3c34b2ca -> c0b2b63c 4035564f 3c34b2ca",
+ "c03b7528 c0540222 3960d9a6 -> 403b7528 40540222 3960d9a6",
+ "40ff7f18 bedfdc30 4064a773 -> c0ff7f18 3edfdc30 4064a773",
+ "3f4c6760 4021af38 4093fe72 -> bf4c6760 c021af38 4093fe72",
+ "c19ef0c6 c05770f5 40973bc8 -> 419ef0c6 405770f5 40973bc8",
+ "419c3ddc c038b809 39be6763 -> c19c3ddc 4038b809 39be6763",
+ "408dd94c bf6c0c98 3b0e2a1f -> c08dd94c 3f6c0c98 3b0e2a1f",
+ "40989600 bf7ba960 3e2d1611 -> c0989600 3f7ba960 3e2d1611",
+ "41757f3c 408fa68a 3f46d7bd -> c1757f3c c08fa68a 3f46d7bd",
+ "414ad5a4 bef9b330 3c6bc43c -> c14ad5a4 3ef9b330 3c6bc43c",
+ "418418e0 c001bff5 3e1538dc -> c18418e0 4001bff5 3e1538dc",
+ "c190de85 40682dcc 39d4b575 -> 4190de85 c0682dcc 39d4b575",
+ "c106388d 407f8cc0 3f8bff54 -> 4106388d c07f8cc0 3f8bff54",
+ "410dae5a 40766320 40434b1b -> c10dae5a c0766320 40434b1b",
+ "c0092ea0 3f9b7d08 3b01d381 -> 40092ea0 bf9b7d08 3b01d381",
+ "403aab00 400e89c6 3a6d2917 -> c03aab00 c00e89c6 3a6d2917",
+ "c0341f30 404cbb14 40abb3a6 -> 40341f30 c04cbb14 40abb3a6",
+ "c0b7cdde c05197bf 3df26676 -> 40b7cdde 405197bf 3df26676",
+ "41300500 c09977f1 3f9811a6 -> c1300500 409977f1 3f9811a6",
+ "412843e4 3edd1bd0 3aa4af7c -> c12843e4 bedd1bd0 3aa4af7c",
+ "c1078c8a 4074e9e8 38de42ee -> 41078c8a c074e9e8 38de42ee",
+ "bf572b40 3f892968 3c9af5d5 -> 3f572b40 bf892968 3c9af5d5",
+ "c0ff99be 4091edbe 3b50a9fc -> 40ff99be c091edbe 3b50a9fc",
+ "41487bf0 3ffd6888 3b6e2aa8 -> c1487bf0 bffd6888 3b6e2aa8",
+ "c0fa92e0 40793e4c 3d286ec9 -> 40fa92e0 c0793e4c 3d286ec9",
+ "c0a5f032 c0516959 3f4bdcb4 -> 40a5f032 40516959 3f4bdcb4",
+ "c091a4bc bff25706 3ab133d9 -> 4091a4bc 3ff25706 3ab133d9",
+ "405e16c0 bf904522 3e12e3e7 -> c05e16c0 3f904522 3e12e3e7",
+ "bf128f40 3f1062c0 39dc7772 -> 3f128f40 bf1062c0 39dc7772",
+ "c19a3807 c011c20a 3fd07989 -> 419a3807 4011c20a 3fd07989",
+ "c0f77410 3e8c1c80 3bc5b323 -> 40f77410 be8c1c80 3bc5b323",
+ "406128c8 bf2b1478 38d7592b -> c06128c8 3f2b1478 38d7592b",
+ "417ac978 40959388 38f74bf8 -> c17ac978 c0959388 38f74bf8",
+ "41429110 c0118863 3f2e7486 -> c1429110 40118863 3f2e7486",
+ "417a0d6c 3f94f880 39d5612b -> c17a0d6c bf94f880 39d5612b",
+ "40ab5240 c08f4ec0 3b2a89e3 -> c0ab5240 408f4ec0 3b2a89e3",
+ "c1829d82 bf740b98 3fdd7551 -> 41829d82 3f740b98 3fdd7551",
+ "c194e18c bf9dd37c 3abe9466 -> 4194e18c 3f9dd37c 3abe9466",
+ "419df6c0 4000edc6 3cf5a8d0 -> c19df6c0 c000edc6 3cf5a8d0",
+ "c0a1a748 409ddb20 393c1922 -> 40a1a748 c09ddb20 393c1922",
+ "c0d8d13a c00b5cd0 3e8651dc -> 40d8d13a 400b5cd0 3e8651dc",
+ "bfd5e390 3d86bf40 3a3ae422 -> 3fd5e390 bd86bf40 3a3ae422",
+ "4191e8fa 400a6c5e 3c9c9534 -> c191e8fa c00a6c5e 3c9c9534",
+ "3f520880 be5c1920 3a8b6dd1 -> bf520880 3e5c1920 3a8b6dd1",
+ "412a2d52 3f527250 392287bf -> c12a2d52 bf527250 392287bf",
+ "bfcf57f0 3ffaf088 3f372230 -> 3fcf57f0 bffaf088 3f372230",
+ "3ec0f680 40612dec 3d080075 -> bec0f680 c0612dec 3d080075",
+ "415aadd8 4088657c 400b58c4 -> c15aadd8 c088657c 400b58c4",
+ "419e521c c011f6f0 3a148d10 -> c19e521c 4011f6f0 3a148d10",
+ "c170e5b8 3f7172c8 3ee9471d -> 4170e5b8 bf7172c8 3ee9471d",
+ "3e8d9740 3e39d1e0 40ed9054 -> be8d9740 be39d1e0 40ed9054",
+ "419456e6 be8832a0 410f30e2 -> c19456e6 3e8832a0 410f30e2",
+ "c185779f bf2cd888 39b99adc -> 4185779f 3f2cd888 39b99adc",
+ "41906b0e 3fe3ae58 3b9c9db7 -> c1906b0e bfe3ae58 3b9c9db7",
+ "41512688 3f3691d0 4088c358 -> c1512688 bf3691d0 4088c358",
+ "40b613bc c013f06b 3f7045b1 -> c0b613bc 4013f06b 3f7045b1",
+ "c1438de3 3eaec3f0 38df2dd8 -> 41438de3 beaec3f0 38df2dd8",
+ "410fab4e 406924a8 3a059b16 -> c10fab4e c06924a8 3a059b16",
+ "3fee2eb0 bde2ce80 3bc57694 -> bfee2eb0 3de2ce80 3bc57694",
+ "414a5cac bebb0550 3ac352f8 -> c14a5cac 3ebb0550 3ac352f8",
+ "c1999e4c 4054b7ac 39d5832f -> 41999e4c c054b7ac 39d5832f",
+ "410fb64e c09ba619 40cabe72 -> c10fb64e 409ba619 40cabe72",
+ "c12c0135 40417f88 39b77c79 -> 412c0135 c0417f88 39b77c79",
+ "c190bbc6 bf9df77e 3b083d3e -> 4190bbc6 3f9df77e 3b083d3e",
+ "40ce35d0 3f14c660 3a424194 -> c0ce35d0 bf14c660 3a424194",
+ "c1543ff3 c09b3c58 3bc30338 -> 41543ff3 409b3c58 3bc30338",
+ "418d4118 bfbccb4a 38d94c4d -> c18d4118 3fbccb4a 38d94c4d",
+ "c0b818c2 40895416 3951a833 -> 40b818c2 c0895416 3951a833",
+ "4110d79c 4034c16c 3e3e5efd -> c110d79c c034c16c 3e3e5efd",
+ "4154e87c bf546028 4105cf3e -> c154e87c 3f546028 4105cf3e",
+ "40abf864 c0154be8 40dff963 -> c0abf864 40154be8 40dff963",
+ "41701958 408a095a 3fd823aa -> c1701958 c08a095a 3fd823aa",
+ "c137198b c07e8fc5 3d7bbdb2 -> 4137198b 407e8fc5 3d7bbdb2",
+ "41950eae bf63d3b8 3cb02956 -> c1950eae 3f63d3b8 3cb02956",
+ "40edad98 c0621656 3a20cafa -> c0edad98 40621656 3a20cafa",
+ "411ac71e c08bb7cc 3b5e80ab -> c11ac71e 408bb7cc 3b5e80ab",
+ "419598ca bf9bf470 3cc01f08 -> c19598ca 3f9bf470 3cc01f08",
+ "c19fa724 406fda78 39bc1be6 -> 419fa724 c06fda78 39bc1be6",
+ "c12bcc8f 3fd19f94 40520744 -> 412bcc8f bfd19f94 40520744",
+ "c18c3a44 409f6f58 3abba5e9 -> 418c3a44 c09f6f58 3abba5e9",
+ "c0f7ae4c bf81d362 3c0a54cc -> 40f7ae4c 3f81d362 3c0a54cc",
+ "c1706d3d bf5dcf00 39b9bbde -> 41706d3d 3f5dcf00 39b9bbde",
+ "c1037c23 4037018a 3e0b5558 -> 41037c23 c037018a 3e0b5558",
+ "c0db917e 40916ccc 406a173c -> 40db917e c0916ccc 406a173c",
+ "413e35dc 4098326a 40a32c38 -> c13e35dc c098326a 40a32c38",
+ "3fbb4b70 3fda39a4 3f511369 -> bfbb4b70 bfda39a4 3f511369",
+ "4180d7fc 409b0840 3ec99c9a -> c180d7fc c09b0840 3ec99c9a",
+ "c0c2f534 4069b6e8 39240f54 -> 40c2f534 c069b6e8 39240f54",
+ "3ed5bc80 3faa94f0 3c1557ea -> bed5bc80 bfaa94f0 3c1557ea",
+ "4165258c 3fb7cbd8 3b0eb630 -> c165258c bfb7cbd8 3b0eb630",
+ "418d8800 c05ea503 39ada273 -> c18d8800 405ea503 39ada273",
+ "c0de0376 3fcbe908 38f1fbf6 -> 40de0376 bfcbe908 38f1fbf6",
+ "c18603c2 3f1d1020 3eedc8ca -> 418603c2 bf1d1020 3eedc8ca",
+ "c190bdf6 bf06f300 3b1fd3e7 -> 4190bdf6 3f06f300 3b1fd3e7",
+ "40e5a858 3fb1f4a0 3c57419f -> c0e5a858 bfb1f4a0 3c57419f",
+ "401d2ca0 c03d8422 40486d79 -> c01d2ca0 403d8422 40486d79",
+ "c1538a4d 3ff99408 41141678 -> 41538a4d bff99408 41141678",
+ "c172af00 c05a2480 38f5b5b6 -> 4172af00 405a2480 38f5b5b6",
+ "3ef82c00 4092d1ba 3d3e4106 -> bef82c00 c092d1ba 3d3e4106",
+ "c0c4953c 3f91c9bc 3f4b8e6f -> 40c4953c bf91c9bc 3f4b8e6f",
+ "410b768a bf2286c0 3a06fef1 -> c10b768a 3f2286c0 3a06fef1",
+ "c0b4480c bf91b17c 3f837ce7 -> 40b4480c 3f91b17c 3f837ce7",
+ "4145858c be964360 3b7a0d9f -> c145858c 3e964360 3b7a0d9f",
+ "41894d42 bee47880 39b82ebd -> c1894d42 3ee47880 39b82ebd",
+ "c1904f74 40632be4 3d46c079 -> 41904f74 c0632be4 3d46c079",
+ "c0157768 3fd76274 3ab11e7c -> 40157768 bfd76274 3ab11e7c",
+ "40936bfc 408fb15e 3c65ccd1 -> c0936bfc c08fb15e 3c65ccd1",
+ "be9380c0 3ff15fb4 40b11687 -> 3e9380c0 bff15fb4 40b11687",
+ "c110700c 404dbf00 41138d90 -> 4110700c c04dbf00 41138d90",
+ "c1831e55 40493ce8 3ea2d561 -> 41831e55 c0493ce8 3ea2d561",
+ "bf56aa20 4016431a 40aec135 -> 3f56aa20 c016431a 40aec135",
+ "41910dd2 bfd9e4ec 38ed67e1 -> c1910dd2 3fd9e4ec 38ed67e1",
+ "c1698cc3 bfe60f9c 3af0dbee -> 41698cc3 3fe60f9c 3af0dbee",
+ "409b5b2c 4021c59c 3eed5d61 -> c09b5b2c c021c59c 3eed5d61",
+ "40541550 c02624d2 3acecb9f -> c0541550 402624d2 3acecb9f",
+ "4175da2c c089080c 3b59809f -> c175da2c 4089080c 3b59809f",
+ "bf6ff0e0 c0897064 3b39dbfd -> 3f6ff0e0 40897064 3b39dbfd",
+ "c0f6ba64 4013ff64 3e581088 -> 40f6ba64 c013ff64 3e581088",
+ "c0bf19ac c02fed6f 3f0c95c5 -> 40bf19ac 402fed6f 3f0c95c5",
+ "c1440046 c084d9fe 3d886735 -> 41440046 4084d9fe 3d886735",
+ "4145ff20 400bc234 3e439bc3 -> c145ff20 c00bc234 3e439bc3",
+ "40943e80 beffd6c0 3ecd39b9 -> c0943e80 3effd6c0 3ecd39b9",
+ "c1588660 c0815d46 3d2d1878 -> 41588660 40815d46 3d2d1878",
+ "3f874290 bff7a22e 3bb41522 -> bf874290 3ff7a22e 3bb41522",
+ "419774c6 409e0434 3a7b211e -> c19774c6 c09e0434 3a7b211e",
+ "40fb14a4 40832f52 3c8ea506 -> c0fb14a4 c0832f52 3c8ea506",
+ "4105c2d2 bf8c946e 3f0f772b -> c105c2d2 3f8c946e 3f0f772b",
+ "40f19fc4 3f9184cc 3f063e8c -> c0f19fc4 bf9184cc 3f063e8c",
+ "c06684a0 c0520d70 38da6f3d -> 406684a0 40520d70 38da6f3d",
+ "c10b22f7 3f8350f4 39aeed08 -> 410b22f7 bf8350f4 39aeed08",
+ "c117c988 408d39c2 3ac5141e -> 4117c988 c08d39c2 3ac5141e",
+ "40f0d594 4047ae78 391bcdd9 -> c0f0d594 c047ae78 391bcdd9",
+ "c1875b32 4095730a 3f65218c -> 41875b32 c095730a 3f65218c",
+ "3f42b3e0 400e608c 40f2db8f -> bf42b3e0 c00e608c 40f2db8f",
+ "41329144 40900c50 3f2912a2 -> c1329144 c0900c50 3f2912a2",
+ "418d9c98 bfd48d7c 3ef92b62 -> c18d9c98 3fd48d7c 3ef92b62",
+ "bfa0d7f0 3fc5d1b0 3b76c3ca -> 3fa0d7f0 bfc5d1b0 3b76c3ca",
+ "c1002637 be1c3180 3e984442 -> 41002637 3e1c3180 3e984442",
+ "41499930 c072d0c4 39aefc40 -> c1499930 4072d0c4 39aefc40",
+ "4183ee7e c03c3f97 3b215064 -> c183ee7e 403c3f97 3b215064",
+ "410aea1e 40729c98 3cef6591 -> c10aea1e c0729c98 3cef6591"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_scale(vec3, float)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "c04b7280 c0174e26 3bdb8610 c0465c1e -> 411da3c4 40ea79c6 3caa3b15",
+ "c109813e c04ba610 3a29032c 3f740248 -> c1031069 c0421c18 3a23e6ef",
+ "418dbc48 3fc9fd4c 3a699a57 3fabbb98 -> 41be2942 40078036 3a9ff1b6",
+ "412f24a4 40831f50 3e54cdf3 4075bde8 -> 42281ffe 417bbc79 3f4c4a9f",
+ "bfa6d2d0 40583950 3b0c439a 4020c66c -> c0518a1f 4107cb6a 3bb08c11",
+ "418f5fd0 4039470e 40d128f4 beb1d5b8 -> c0c731e1 bf80b4ce 40114c14",
+ "3fd0af80 406ed19c 3e92a609 405c02e0 -> 40b3592a 414d3ed1 3f7c11e2",
+ "c1569360 402725ac 3d14f0a7 401a9a7e -> c2019626 40c9e311 3db3f8b3",
+ "415bc3f4 be2f2880 3bcb2c4b 3fbf0ad8 -> 41a40082 be82b6a3 3c17f1b6",
+ "c081962e 40532c58 3937e56c 3ee3ed20 -> bfe6c066 3fbc03ec 38aa45e0",
+ "c0f7696a c094abef 3bee0858 3f915e9c -> c10c7e25 c0a8d8a8 3c0762f5",
+ "c1035aae c0975f81 3928c3b8 c0140c4e -> 4197ed7a 412f14fa 39d22a12",
+ "c016a7d0 408a57cc 3efc0dbe bef42b00 -> 3f8fb140 c003f2eb 3e70684a",
+ "bffb14d0 c08b2db8 3d59b415 3f862d50 -> c0039956 c091e522 3d643c43",
+ "c0ff55b0 4082c264 3d940e76 bf343c54 -> 40b3c46c c0381efe 3d5082aa",
+ "bec4a980 c02b69e2 3c9947dd c022f0e2 -> 3f7a589f 40da3497 3d432741",
+ "c162c4c9 bf8f5310 3fa95e3b bfd64152 -> 41bdca5d 3fefe803 400dc06b",
+ "400342f0 4098a180 3da4f2fc 3f8cc214 -> 4010583c 40a7d811 3db567a9",
+ "4138fed0 4006afae 3d0ce3ec 40534600 -> 4218ac9b 40de4f41 3de8a361",
+ "c053d138 bfe4fce6 3a28e98d 3de21840 -> bebb12c4 be4a3cf4 38964e6a",
+ "41545d14 be471620 3ce3157d c0090262 -> c1e34f93 3ed51963 3d732e1e",
+ "c198ba8d c0890aec 3bba6676 400e7f82 -> c22a0719 c11890a2 3c505392",
+ "418c180e 4011918e 3c0b85d4 bda196a0 -> bfb0db1d be37c461 3a308679",
+ "c11aca90 3faf1ab4 395e403c c059d575 -> 4203b6c5 c094ffa4 3a46833b",
+ "404f5028 c046178a 3cf837c0 40503f16 -> 4128a437 c12123f1 3dc9f4d2",
+ "c13e504d 40205d5c 3e4b4e18 be92b940 -> 405a2707 bf37d294 3d690f7f",
+ "c0be91bc c07f5e8a 3e38e9b1 3ff64924 -> c137567d c0f5adce 3eb1e7d4",
+ "4013df50 3fa98bb0 3a999848 40757616 -> 410dc8ed 40a290e4 3b93b528",
+ "411df382 c08d6f06 3da30245 c07af655 -> c21ad7c9 418aa684 3e9fd41d",
+ "411be890 c031e8ee 3a239224 c05a258e -> c204daea 41179a74 3b0e0d81",
+ "c19426a1 c091470c 3bbeaf11 4025cc22 -> c23fe610 c13c2d45 3c77ecc7",
+ "4068c580 c082dbd2 3c0120ea c0320ba2 -> c121e3e7 41360595 3cb3c88a",
+ "40b9daa8 bf2c21c8 3b953249 c00be3d0 -> c14b1e3a 3fbc1f0b 3c2346d8",
+ "414fe1a0 c01cbd91 3b6bab82 c05666a0 -> c22e19f2 4103454d 3c462ed0",
+ "414d6eb8 c09832c0 40232889 4057edf4 -> 422d46f0 c1806017 41099ef7",
+ "c04bc148 3f8d6c08 3aa610c8 bfc755fa -> 409ea7ad bfdc3cf2 3b01b9b5",
+ "3f0c0f00 bf6f07f0 3f0554e9 c0198a04 -> bfa800f3 400f5c9c 3f9fef68",
+ "c18de15c c08e44de 3b93f4ac bf906b3e -> 41a01467 40a084ac 3ba7b778",
+ "c195efc5 bf46c490 400ec9ed c02fce90 -> 424defc6 400880c0 40c41ef7",
+ "c0831366 4056e0b8 4014beb9 bff5b528 -> 40fb9ca4 c0ce3d1f 408ec3ef",
+ "410ddd98 bc16fe00 399d16a1 c03fffc7 -> c1d4cc25 3ce27cbd 3a7249e1",
+ "c0fefb3a 409bd6b2 3a1b6f6b bd87e4a0 -> 3f075a33 bea572c9 38286d7d",
+ "411dfcb4 bc2fa400 3a6690e6 3fe07ce8 -> 418a8a33 bc9a0533 3acc5a17",
+ "c0cbdda0 c0282171 3e3da2bc bf1670dc -> 406f9b78 3fc59b6f 3ddee49c",
+ "41504a5c c090c19a 3b68eb97 c021a3b6 -> c20383f7 4136cca8 3c13c25e",
+ "c0c2e880 c04d4f9c 399da94a 3f37e368 -> c08c0157 c0137a4a 39692e24",
+ "c17ed510 4097433e 3a786b98 bf47c3f0 -> 4146daab c06c1216 3a45e14f",
+ "c092b35c c05d188c 3e86214e 4078719a -> c18e5edb c15691e4 3f822ccb",
+ "c15f472f 3f9b2e38 3a832e5f 4057b88a -> c23c25bc 4082c3ae 3b60470b",
+ "3f1b5a00 c0816c5d 38dcf80a 3e5a93c0 -> 3e04a44d bf5d01f3 37c49c25",
+ "c11eb3f7 c01ef476 3c974152 3eec52b0 -> c092812a bf92bcb4 3c0bb802",
+ "416a98e8 3f8efd18 39015aa2 40169b20 -> 420a03c0 40283de2 39aac3f7",
+ "412c0d7c bf118278 3b945c28 bf99a400 -> c14e848f 3f2ea863 3bb28101",
+ "3f8313e0 3ff1dca4 40693c76 3eadee20 -> 3eb21cb6 3f245314 3f9e76e1",
+ "c0772cb0 3d625480 3908ed09 bfb0068e -> 40a9f50d bd9b9fe4 3941b017",
+ "413aaa9c 40215f36 39b24c72 3f3d10c8 -> 4109dc32 3fee5bbe 3988eb66",
+ "4149c6f0 c03db0a5 3d8dd901 3fe0c350 -> 41b12804 c0a68b49 3df921ef",
+ "c19416a5 40149ab4 4066b1c5 3feb6b50 -> c2082edd 4088a84e 40d4263e",
+ "c192358a 40356ab2 4092b9c2 c04ecca2 -> 426c37e8 c1128cdf 416d0dd9",
+ "4110999c 3ec23a20 3ed38e3f bda1f620 -> bf36f742 bcf5c295 3d05d8a2",
+ "41916d5a bf7cfc88 3e16cf56 40626bf4 -> 42809fdd c05fc19f 3f0566e7",
+ "414ef404 bfd4e02a 3ca2c6ed be9af010 -> c07a81b8 3f00d679 3bc52c01",
+ "4105b414 3fc9bd48 3d1f231f c07b0fc2 -> c2031fca c0c5d901 3e1c1b02",
+ "c188d708 3fe1d7f4 3ef24be8 ba756000 -> 3c83291b bad8785d 39e83fd2",
+ "c162ff36 40670188 3f03ed8b 3fa6dc14 -> c193f4a2 40969196 3f2bfc63",
+ "c1920b59 c000ce4a 3f1be9d3 c06d3dc6 -> 428757bf 40eebc1f 40107e4e",
+ "3fa2c240 3f81a0c0 3b6048d7 3ff7f2dc -> 401da3d3 3ffb1a25 3bd95e81",
+ "41244700 404a62d0 3f9ad306 403b2474 -> 41f02e83 4113f300 40625d0d",
+ "4134ab2a 3ea947a0 3bf1e884 bf604734 -> c11e4805 be944dc1 3bd4403e",
+ "c1742612 c056fc30 3f330ff4 be16d960 -> 400fdd9e 3efd5ca1 3dd30835",
+ "411c23d6 c07c353e 38ece3e6 bf768c94 -> c116602e 4072e5a9 38fe8856",
+ "c136d725 40808d66 3e46941e bf888b48 -> 41430b8c c089221e 3e53d9a0",
+ "c1907f1e bf2d1608 40b59155 403ae012 -> c252f5aa bffcb303 41848aa8",
+ "413d2144 c08cb5b2 3c8bedae 3f9f74c8 -> 416b9be0 c0af4a14 3cae795b",
+ "40b8a358 3f784a00 3c38c46b c00e49e2 -> c14d3fc9 c00a00b4 3ccd8292",
+ "c1976a55 400b33bc 3eac7901 40490dce -> c26dd54e 40daa641 3f87766a",
+ "415a4b0c 3fc30890 3ab39510 3ea10640 -> 40894e87 3ef55a4b 39e44ce2",
+ "c0fc6a74 bfc701a2 3c043463 407663fa -> c1f2f0df c0bf894a 3cfec4b6",
+ "c1828fda c0191106 407bd08f 40601870 -> c26494ab c105fd82 415c6ed6",
+ "c1079448 bf9d09c0 3fa5843b 3f852f28 -> c10d1206 bfa365fc 3fac38bc",
+ "418dff9e 408cddd0 3e968fe2 bfb3ec00 -> c1c79946 c0c601ea 3ed3a6c1",
+ "4169e368 40907dc2 396abd17 3fe35748 -> 41cfb463 410050c6 39e1738d",
+ "c1844d10 400b7838 3f09dc91 3e305f20 -> c0364c48 3ec02cf3 3dbdf765",
+ "41225526 3eefecb0 3c99e16a c072731e -> c219bd7d bfe339a2 3d91d06c",
+ "c07ee2f0 c0748b44 3d49d85d 3efdb6e0 -> bffc9c5c bff25c53 3cc812cc",
+ "40df3350 c07457d6 395ab73b 3fd0d0ec -> 41360fd8 c0c74ec6 39bb3523",
+ "c18fac34 4096413a 3f3b98a0 3e8e0eb0 -> c09f7386 3fa6c19a 3e503477",
+ "c165911a 3db49140 3be18eb3 bfeea8ba -> 41d60434 be28560c 3c52b30c",
+ "412fc890 40337130 3b218428 c053a6a3 -> c21154bb c1145b18 3c063f84",
+ "c1986126 bf981204 390f78a8 404772d4 -> c26d6fbc c06cf46e 39ff1638",
+ "4052dff0 3d5aa600 3c965e4d 3f2dd500 -> 400f30ca 3d14781a 3c4c3ed2",
+ "407b9c70 40664b78 3ab41230 3eb8de10 -> 3fb5b2b2 3fa64e02 3a02b74e",
+ "4143e34c 407b359c 3d46e453 c028d403 -> c2012f64 c125ab3a 3e033540",
+ "4158d21c c0195aa6 40c02050 4026ac0e -> 420d29f7 c0c7afb2 417a2c61",
+ "4170dd74 409cb9ba 3b18596f 404ab3f6 -> 423eb810 41783172 3bf33ced",
+ "c14dbc48 3eb4d010 3da403e0 3f1f3778 -> c0ffe909 3e60e8cf 3d4c0c28",
+ "c0bf8a1a be53e780 3f0adc72 40724ffa -> c1b54c63 bf48930a 4003702b",
+ "c11426d4 bfa8c80e 38d83727 c076262d -> 420e7368 40a24969 39e43cde",
+ "c182fc90 3fbeb2fc 40fced52 c02973f2 -> 422d681d c07c750e 41a76b5b",
+ "40d3ca20 be574620 39b0e8f1 c01e1cb2 -> c182ce7d 3f04f569 3a5ebef1",
+ "411adaa0 c02e2ae9 3ee1105c c0009ef8 -> c19b9af2 40af0337 3f62297d",
+ "4196e6a2 c041b9b8 3c628f02 3de9ebc0 -> 4009e2e0 beb1046f 3acf54db",
+ "414fcd60 bef19530 3a9384e1 c06e9164 -> c241a6f4 3fe121e6 3b8b0aba",
+ "c17aedea c06bf316 3eb7c9d1 c067e804 -> 4263501a 4155be31 3fa67fe9",
+ "4187e17a 407001c0 3ac30824 c0431524 -> c24f17f1 c136e527 3b9698fb",
+ "c177b368 c01d3c25 3b1e5655 befe3788 -> 40f5f9bc 3f9c23c8 3a9e590e",
+ "41798338 3e387000 39831367 c01ed2b6 -> c21acc5c bee4d9de 3a2c6d24",
+ "c10c473e 403774c0 3a25895c bf522d50 -> 40e6568a c0169e3e 3a0a4b4e",
+ "4175d7f8 c085bb9d 3a1a438f 4066bee6 -> 425d975c c1711491 3b0f7336",
+ "41444b00 bfd72348 3ddbe538 c031a2ab -> c2083496 40954819 3e989a16",
+ "c18fa175 c02b2457 3a11042f 4021a310 -> c235600f c0d81dbb 3abda32b",
+ "c15af646 4095f410 40668cd2 406b2e5e -> c24927bb 4189c234 4153cd58",
+ "418c26d6 408a6750 3ada8df0 4014b5d8 -> 4222d403 4120cc14 3b808b64",
+ "c1238bfe 409bbaf2 3981060a bdca85e0 -> 3f8161fd bef665e7 37d8143e",
+ "419065c8 c005f854 3bcc34cc bebe3e50 -> c0d69d60 3f471dd5 3b1838ae",
+ "c174a9d5 c027742b 3ac0ac51 c06c85e6 -> 42620c88 411ab6ad 3bb41521",
+ "c104a4a6 40484068 3a1345bf c072c55a -> 41fb93cd c13de742 3b0e5e8f",
+ "4198c34a 40269d32 3ad09309 3f3ddb78 -> 41629649 3ff721c9 3a9cb25c",
+ "c113f251 c085ee87 3964f13a 4042c0c0 -> c1e11a0c c14bc733 3a386327",
+ "c17c52be bec81260 3b24bd40 4057af44 -> c254963d bfa89068 3c0ba59d",
+ "40889198 c07309d9 3aee07dd bf9b562a -> c0a5bc3d 409378c4 3b110b85",
+ "3fd84500 bfa6e298 3a1872be 404b81a8 -> 40abec40 c084aa34 3af3910b",
+ "c19ec362 3fd4df20 411ef560 3e035dc0 -> c022f03e 3e5a7844 3fa323ad",
+ "41975c24 c05e5230 391d82ea 40202768 -> 423d61c6 c10b1597 39e11914",
+ "419fb89a c0794208 3d28b3bf bf9ebde2 -> c1c614cf 409a8fa3 3d5155c7",
+ "414bf5d8 4076b4e4 4101fbfc c0250c6c -> c2037f5a c11f0e90 41a79b90",
+ "40f5f744 3fc22f14 3d26209e c02c8bf4 -> c1a5c899 c082e1ca 3ddffdee",
+ "418606b6 c0416166 3c050302 bd9e9d00 -> bfa614ad 3e6fa16b 3a2534eb",
+ "c19c9af6 bf1f9400 3fdb8979 407eb336 -> c29bcf61 c01ec48e 40da6cc3",
+ "419bb072 40768050 3cf6d3e2 4058a3b8 -> 4283c071 415099e8 3dd10823",
+ "40ccc520 c01e6fc8 39070a7e bfc174c2 -> c11abe02 406f7511 395982c1",
+ "4126fa22 400f8fa6 3e0079b0 c044801a -> c2002b10 c0dc63a3 3ec53fd3",
+ "c1913dc6 c01cc8c4 40231678 407d8c3c -> c28fd99d c11b484c 412186e7",
+ "418c269c 408b3a24 39aac672 3fe28644 -> 41f8072e 40f664b2 3a20c9ce",
+ "c1677d39 c08842c4 3e4370f3 4047f410 -> c234cf09 c154db9d 3f18aad3",
+ "415eb918 409cc664 40fa3db3 401caee8 -> 420850f6 413fe804 419928b3",
+ "c109f9f4 3dbaa640 3d09e0fd 3e90bb70 -> c01c033e 3cd30c5a 3c1bf0e8",
+ "c0f89f4e c093e0c2 3fad355d c045a5ad -> 41bff37e 41645752 4085ba7e",
+ "4092dbf0 3f7f8f50 3e883b83 3f07aba0 -> 401ba8e1 3f076fe8 3e106635",
+ "4168a4d0 3fdab8b0 3c46a8de 406f8996 -> 4259aee7 40cca7f9 3d3a1f49",
+ "c195c261 bf722910 39c9581d 3fa7bd18 -> c1c440d8 bf9eaba8 3a0a5e99",
+ "c0eac23e bf910b8e 3d6ca53f c05954f6 -> 41c74c90 407645dd 3e48edd9",
+ "c0d31478 c06f9674 3ffcf19c 40531ebc -> c1ae1336 c14595c5 40d099d3",
+ "c12d6e35 3f86bdd8 3978ffa5 3fae22dc -> c16bf10b 3fb74ec4 39b1768c",
+ "c110c470 c035ca8f 390e89bc bffe2b4a -> 418fbb62 40b47db7 39995279",
+ "c133e99a c085007f 3f905bba c07bc806 -> 4230f29d 4182cf68 408dfb3c",
+ "c0366490 402b0ed2 3c02dbef bfa5bdc4 -> 406c2c09 c05d7eb5 3c298e28",
+ "c11ff27b 3eb9fcc0 3ff8bf1c be857078 -> 4026be7e bdc1e40b 3f01a8c5",
+ "40c98840 3ff10510 3ffb1cde beeb1dc8 -> c0391785 bf5d5bb0 3f66a101",
+ "416ec02c bfed030c 3ce55d4d 404ba30e -> 423dea74 c0bc8860 3db68dce",
+ "41922a46 bf337230 3a836fbc c023c75c -> c23b057c 3fe59ae6 3b2b35d4",
+ "c14d9ec2 408474fa 402a32fe c07b272a -> 4249ba1d c181f2f5 4126fa56",
+ "3f7d0440 c09b3785 3b3dfa25 3f971898 -> 3f9555d0 c0b73952 3b60afed",
+ "40b896b8 c0566e9a 3f0e3eef 40653030 -> 41a54191 c13ff94d 3ffeb33a",
+ "407318d8 c07a795c 3ac43cd1 3eca0060 -> 3fbfd1f6 bfc5a421 3a1b9b0c",
+ "c19e038d c036e8c0 3fab8f56 4018f824 -> c23cd68b c0da96fa 404d07b1",
+ "c1148591 bf8a9260 3af699bf 3ea6c820 -> c041856e beb48e7c 3a21809a",
+ "411de914 3fa9a070 3f775434 406afdaa -> 4210f384 409bb4bb 406308bd",
+ "4110f9ae c06d7ad6 3b43b313 4013f58e -> 41a794dd c1094153 3be3235a",
+ "4175d77c 3fa6d174 3fb3cf86 3df2e440 -> 3fe940e5 3e1e46bc 3e2a9b07",
+ "4174afb4 bfa51b74 3f956940 c0079c5a -> c2019e19 402eeca2 401e4c19",
+ "c123ea7a c0398042 3fa7368c bd75db00 -> 3f1d6ba0 3e322670 3da096af",
+ "418c9678 40837cce 3fdd83f2 40076138 -> 4214b17a 410b117f 406a4a2e",
+ "c186786c 408cd5da 40379082 3ff86214 -> c202782d 4108a520 40b21aaf",
+ "4085b654 bf7c3a98 4068dd6a 4012eebe -> 41197d5d c010c4a4 4105a785",
+ "40cb8f50 bfc76050 3b06f07a 4048ccd8 -> 419faad8 c09c62c7 3bd47683",
+ "c13484aa bfd52606 4080ea48 3dfa3840 -> bfb07138 be5055f7 3efc027e",
+ "416cc100 40933152 3959d5bc 406de462 -> 425c01e4 4188c7f9 3a5c73a0",
+ "c10d5e16 400cf26a 3e5d72ab 3f8a7100 -> c118e63d 401871c8 3e6f862b",
+ "c07e0780 3f672ee0 3d73aa55 c0626aa6 -> 4160ac73 c04c77b1 3e57863f",
+ "402f6ef8 4027ef92 3dd0154a 402bf2c6 -> 40ebaafc 40e19892 3e8bc563",
+ "41365314 c09591f3 401f431e 4012a4ca -> 41d0e17d c12b5b08 40b675ed",
+ "c1280dc2 3f064c60 3a5b59f6 be0e17d0 -> 3fba8e87 bd9515b6 38f6902b",
+ "410b9c5c c09262da 3ff35221 3e9bff20 -> 402a259c bfb2677a 3f144581",
+ "c17ab3b1 4086cc8a 38ffa031 4052206e -> c24dc729 415d49b9 39f2750a",
+ "c106f5f1 bff5d648 3e04c8ad 40756ea2 -> c20163b3 c0ebb051 3efe9fe7",
+ "415e54dc 40751fa8 3cdab8bb bf8fd202 -> c179cf94 c089b5c5 3cf5e920",
+ "c11134a6 c01bf3b5 3ba7a6f1 c078c071 -> 420d1828 41178953 3ca34148",
+ "415dd0b4 4062d1ac 3aa216ed 404b1344 -> 422ff530 4133ed55 3b824e4a",
+ "411b6d84 bf3b2600 39b457b9 c0211a36 -> c1c39f94 3feb8c1f 3a698e16",
+ "bfea0780 c069d84d 3b209b0f bfbae9c2 -> 402adf25 40aabcaf 3b6b06c4",
+ "41304ade 3f4efa68 3adfdacb c006e04e -> c1b9c34f bfda18d9 3b6d702c",
+ "41693d28 c06d7f85 3d309599 be27bf60 -> c018d541 3f1b9fbb 3be78337",
+ "403b2a08 3fb8f038 3f3273ab bff52830 -> c0b33c9b c0311aee 3faae504",
+ "c1668227 3f9c3014 410c1151 404dc2be -> c2394593 407b12a1 41e128fd",
+ "3ff223e0 3e491300 3d16f465 40765190 -> 40e8fb9f 3f417852 3e1140fc",
+ "c1392c12 c052f7ac 3e1b1c55 403a3bc0 -> c206b53d c1197930 3ee1b30a",
+ "414f6b9c 4092ee96 3f72517b 3fb9bc80 -> 41967d7e 40d53536 3fafd026",
+ "4148ec1c 405461fc 3c9c4c36 c030e482 -> c20ad5ac c112c0f0 3d582bc0",
+ "c1965f8c bff9785e 3a89187a bfef0f92 -> 420c6c59 4068f68c 3b027228",
+ "40aebd10 c020d001 3cf4e2bf c0362a80 -> c178aed8 40e4dd26 3dae4d3f",
+ "4112d1fa 4067da20 3c83683b c01885ee -> c1aef2f8 c10a22cf 3d1cb3cf",
+ "c1848f7a 409283e6 3f1baf14 c0422207 -> 42490cb2 c15e36dc 3fec20cd",
+ "c01d9068 c03c8674 3e1eb280 405e8b1a -> c108f8d8 c123e309 3f09f63b",
+ "409b4a24 c00211fd 39b34b3e 3f573b58 -> 40828f44 bfdab685 3999a2be",
+ "418e5494 bf961320 3c3d257b 404f7ffa -> 4266bb15 c07348fa 3d198d62",
+ "c0d4e3c2 405d2484 3e59e04a 3ff70da0 -> c14d7315 40d56a00 3ed2457d",
+ "c147715e 3f921c88 3aba3964 402b61a0 -> c20584c8 4043a18e 3b7b9dbf",
+ "c0519d80 400e0454 3b0b1680 bfce459c -> 40a8e5bc c064dc33 3b60b192",
+ "c1982735 bfa7907c 3aeda598 bf9b3d1c -> 41b8881e 3fcb38f6 3b11a67d",
+ "4112c360 bf290c98 3f46b16a 403b830c -> 41d6ffb0 bff7a579 401189cb",
+ "c13e7d10 3fdf39c8 3ad6ddb3 3f5e3b60 -> c1255ca2 3fc1c7e1 3abc014e",
+ "c143f8c4 3e5bb9c0 3d3dcc73 3feeeb08 -> c1b6e532 3ecd106b 3db12e01",
+ "c1411628 3f7cf380 3b851f1f bffc2640 -> 41be2ea9 bff9257d 3c03856f",
+ "415733fc 3f65fe78 3f907e11 40448ac6 -> 42253875 40309381 405dde6f",
+ "c1421ed1 3fffb8dc 38f5a2ff be68a940 -> 40306c44 bee86898 37f8ed56",
+ "411181d4 4087101a 3ea70cb4 3fddbf50 -> 417c13a3 40e9fbab 3f10b448",
+ "418cd254 bfcd737c 40636e14 bffdb782 -> c20b90cf 404b9e67 40e1672b",
+ "c19192fc 4025602a 40192157 3db13b40 -> bfc990a3 3e64fb87 3e54077c",
+ "40861998 3eecc1a0 3ea76d90 3fa31b94 -> 40aae17c 3f16d8ca 3ed55a63",
+ "40835530 c08dbccf 3d5fb82e 3faaeb3c -> 40af5e80 c0bd433e 3d95639d",
+ "c1861784 bce67600 3e1bc099 40237c98 -> c22b4478 bd932d4c 3ec6f447",
+ "c07fa318 c09c4999 3ca7da58 bf05c680 -> 400595f3 402356d7 3c2f7fc7",
+ "4015ec08 bfa932fc 3a1659a5 c070e0d7 -> c10d10f4 409f3467 3b0e54cb",
+ "c04c3470 bff7d246 3a01b2ee bfe0fba0 -> 40b37699 4059cb93 3a6638de",
+ "4196f006 3e8712c0 3e612cf0 4035672e -> 4255e914 3f3f6d65 3f1f92f5",
+ "408e7ea0 c00c3003 3e8d6724 bef62870 -> c0090430 3f86cc48 3e07f848",
+ "410ebdb6 404700cc 3e34001e bfd706be -> c16fca2c c0a726e9 3e973367",
+ "4177a298 c05f347c 3b2709f7 c038842a -> c2327cb6 4120e0f5 3bf28045",
+ "c15e84db bfc41222 3c131881 c00a2768 -> 41f02bbd 40539fe9 3c9f0666",
+ "c1092ffa 40756118 3b7a55c6 405b5fe2 -> c1eb1eda 415245f7 3c572f51",
+ "417165c0 be7b5ae0 3e9685d0 3fb585a4 -> 41ab2af5 beb23a78 3ed57925",
+ "40888f14 405d9838 3994c343 bfce7682 -> c0dc44b3 c0b2b712 39f62ff9",
+ "c06d2720 bf4616d0 3e8c6064 c058f966 -> 4149000d 4027e43b 3f6df52e",
+ "c08e8f0a 3ff740a0 3946dbdf 40199a62 -> c12b12eb 40945abb 39f64cba",
+ "4145ba38 c042397f 399ed699 3f36ae28 -> 410d18e7 c00a9902 396dad40",
+ "c0afdcfc c051bb47 3d6071fb bf3dce70 -> 408263f7 401b8064 3d266fb0",
+ "c1844e2e c09c2116 401bb2a7 c05a69a3 -> 4261c257 4185349a 4104d6b3",
+ "41850a88 4082c99e 41166f3c c052cda4 -> c25b1b04 c15764e6 41f7c05f",
+ "c1399e00 4019960e 40f5e4b1 c03a6f33 -> 42072d6c c0dfb37a 41b31318",
+ "405f76c0 c09c7d55 3fbba006 4040eacc -> 41286605 c16bdb0e 408d6455",
+ "410d0760 bfbf3548 4025be41 be923160 -> c02112d0 3eda6288 3f3d4d2c",
+ "bfba2d60 c03cc562 3f119c63 bea75440 -> 3ef361be 3f76c5c6 3e3e5a49",
+ "c1059cc5 3f680350 3c512d72 c0525ec9 -> 41db9824 c03ea89f 3d2c0332",
+ "4137c30e 401169ec 3d8a3cbd 3fd1ce70 -> 41969a6e 406e5979 3de2a174",
+ "4188dd78 c008bd31 3db80d31 3f41b8b0 -> 414f2369 bfcef290 3d8b4e0b",
+ "41961634 c09a8144 3c0621ce bc30d000 -> be4f526c 3d556cd0 38b9cad4",
+ "c03861a0 3f7e48f0 400938f7 3f983714 -> c05b4345 3f973204 40232ece",
+ "410a4514 40864f5a 3a97bc47 401890b4 -> 41a4ce58 41201611 3b36c4dc",
+ "c0aef744 c0338776 400d616b c079dcb0 -> 41aac556 412f3986 4109fdcb",
+ "c106a0d7 c0854c73 40a75403 40435406 -> c1cd7167 c14b69f8 417f580a",
+ "c118e47e bf51bc20 3f508580 bfb312d4 -> 4155e606 3f92b5f7 3f91dd2c",
+ "bf0014a0 4081c498 3b51ff55 be0d3230 -> 3d8d48f0 bf0f2571 39e7f610",
+ "c150904b c011c5cb 3a8ffe76 bfcbd4fe -> 41a60ff2 40682241 3ae85989",
+ "c04c2a30 c0274796 405d535d 3fd00fd8 -> c0a5eeea c087f484 40b3e18c",
+ "4195c23e bf947ad8 391f511e 403a867a -> 425a3b98 c0585e80 3a0290bf",
+ "c0ce5746 c07e801b 3f04f7df bf83925c -> 40d41941 4082cd0e 3f08ae6d",
+ "c09c44f0 3f9dbf48 3ed9f02d 3f0a8810 -> c0292070 3f2ab9e9 3e6bdf7e",
+ "41655ae0 3f09e8d0 3c4346a6 40304312 -> 421dea91 3fbde861 3d069cba",
+ "c0c964b4 4005e6dc 3b985c98 3ed0afa0 -> c0242bfc 3f5a4edf 3af8d4f3",
+ "c1299b43 c08d99ae 38ee76f8 3e37eb80 -> bff3b406 bf4b763d 37c0e967",
+ "c10129a6 bf9523a6 3cc135f3 bee620d8 -> 406837fb 3f061129 3c2dbfe9",
+ "410764a4 4083c434 3bfd92dc c04029a4 -> c1cb4302 c145d12c 3cbea2fb",
+ "c0f1011a c055fadb 392e011e 404fb076 -> c1c38604 c12d9956 3a15fd76",
+ "c190eccc c0869977 3d53c72e c02eb6b6 -> 4245d0c4 4137b8bf 3e1097cc",
+ "40dff668 bf64af30 40ae4238 403a7f42 -> 41a3285d c02698f7 417de5a0"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_add_iv(vec3, vec2)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "c14cfbf6 4015715c 3e079ba3 40762a88 40b8c0bc -> c1000676 4015715c 3f8c4aed",
+ "c0ae338e 4092a69c 3eb7d309 41819edf 4181ab55 -> 412c306d 4092a69c 3eb965c7",
+ "bfa2d6b0 40835bec 3befb189 3f057a33 3f16cf4d -> bf3788a0 40835bec 3d28a475",
+ "4191b318 3fa39a5c 3b4d8b6a 40cc680d 40cd177b -> 41c4e309 3fa39a5c 3c63521b",
+ "c122dfc9 3f817268 3af98ae6 40f61a4f 40f73c91 -> c01e2844 3f817268 3ca0d023",
+ "3ec4a940 403e2d6e 3b07cd20 c1556f56 c1556c46 -> c14f4884 403e2d6e 3b22216d",
+ "4170a038 404f908c 39baa597 c1620566 c161f036 -> 3f6a56a0 404f908c 3b41f94e",
+ "402593f0 4025d0f8 3fef1dd0 405e1d4a 405e76f6 -> 40c1ef08 4025d0f8 3fef77ec",
+ "41911d98 3fd561a4 3aa42457 4190566b 4192cb65 -> 42115740 3fd561a4 3e1e94e9",
+ "c16a9032 3ea7f220 3d3de3b7 3ef9464e 3f12c759 -> c16214de 3ea7f220 3db78a33",
+ "3f9e7370 bf9f1f5c 3f112411 bf51c87b bf320485 -> 3ef600c0 bf9f1f5c 3f21063f",
+ "40492b58 be659b40 4091bdad c1796839 c17951df -> c1471236 be659b40 4091d448",
+ "402ae328 3ff99948 3d5839ae 411343a6 4113ab8a -> 413e3062 3ff99948 3d862167",
+ "40b82940 404021e8 3ab0ad97 c1527845 c15277db -> c0ecc6e0 404021e8 3aba3f6b",
+ "c1426ac6 402f0ff8 3ebade69 c0f0d2ed c0efa73b -> c19d44a8 402f0ff8 3ec43fc3",
+ "4049bd98 bf979118 3b51b905 419e7313 419e82ad -> 41b7b293 bf979118 3be70c3f",
+ "41989384 c01716ad 3f100333 404542ea 404fdaf6 -> 41b1e562 c01716ad 3f253513",
+ "3c3fa000 c08871e4 3e0f5c36 3f4bac8b 3fba8f1a -> 3f91b1f0 c08871e4 3ef120af",
+ "c18420a8 40518978 3f063644 c12d2c21 c12054e9 -> c1d780ea 40518978 3f6cf2a3",
+ "c11a9175 c071cb96 3ce490f7 bf84e009 bf84d9f7 -> c12b2d15 c071cb96 3ce5724c",
+ "c0d56436 bff735b4 3bd3c710 3eef823e 3ef42242 -> c0c64712 bff735b4 3c34063e",
+ "4124be76 3fd0efe8 3c7eeb31 4195e3ac 4195e400 -> 41e84311 3fd0efe8 3c80806f",
+ "c141ec9e c04f02f9 4099eee6 4115b19d 4115cecf -> c030b1a0 c04f02f9 409a0c41",
+ "c0fc6112 408e63b2 40d6d1fd c1a43fff c148992a -> c1c35e8e 408e63b2 412b5ca5",
+ "4033e1a8 c052926e 3e9dce6a c0b2bd99 bfed82fb -> bf68f2c0 c052926e 400b16d7",
+ "c0a7e880 c0968525 3cbdd936 3fa0c00e 3fa0fd32 -> c07f61b0 c0968525 3cc591aa",
+ "bfde2820 407b2d4c 3faea1e6 418d5507 418d555d -> 417ee560 407b2d4c 3faea5cd",
+ "40d983c0 40809694 3acb881b c15d54dd c1321629 -> c0b5e746 40809694 3fad2e79",
+ "4157b7f4 3fad12b8 3e4e4072 bf015747 bedf9973 -> 41502ed4 3fad12b8 3e715953",
+ "418360d4 407a37c0 38eb199c 416be125 416c45c3 -> 41f96a8e 407a37c0 3c4bd9a9",
+ "c0eeb1b2 c05ba444 3c28971b be8bd2ce be7cec64 -> c0f703fa c05ba444 3cbf4753",
+ "c1581fad 3f8ba4bc 40bed57a 407980f1 4079830f -> c119bf2d 3f8ba4bc 40bed62a",
+ "4111c8be c04640ed 405b4fe3 41087344 4109c554 -> 418d7285 c04640ed 405df486",
+ "c0fa33d8 bfc08fbc 4116a717 40ef3dc8 40f96fb8 -> be3ba300 bfc08fbc 411933a6",
+ "c07d76c0 400450b2 3f456b95 c13fd35f c13fd13b -> c17f2ffd 400450b2 3f457ea2",
+ "418b3786 3dd01d00 3a924c21 41597c11 41597c7f -> 41f7f5aa 3dd01d00 3a9ec23b",
+ "bf62bfc0 c099b22a 3dd6c8ee c1a31fec c17574d5 -> c1960329 c099b22a 40284d08",
+ "c10020c0 bdcd2dc0 3b985c1a c03bbf6c becc27a0 -> c11ac94c bdcd2dc0 3fa2d343",
+ "c18c8840 408ef4b2 3e23b860 c1560445 c15601bb -> c1f789c0 408ef4b2 3e2415dc",
+ "40bbf1c0 40121256 40ad0299 41818f17 4181934d -> 41b08da2 40121256 40ad0b61",
+ "401c2618 407d9064 3b8102a0 c1545735 c1545637 -> c12d4d30 407d9064 3b85db2d",
+ "4088ace8 bf9a64ec 3a867094 c0c0df2c c0bf1b9c -> bfdd41f0 bf9a64ec 3cea4104",
+ "40c2bed8 bf809316 39c5aeec 406e1ffb 407180b5 -> 411d5382 bf809316 3cdb6282",
+ "41052d14 3f5c6690 3fed4f9d 412f12b6 412f1d6e -> 419a2293 3f5c6690 3fed7b85",
+ "41494f80 c09adaf2 3d45023d 414532f6 4147baba -> 41c7e32c c09adaf2 3e0243ab",
+ "bfea38a0 c08ae2c0 3deaaa3a c192c6cc c192887a -> c1a14b2d c08ae2c0 3e04f45b",
+ "c13ba348 3f22c218 3b5aa28b 404512cd 40461ef3 -> c10a3d10 3f22c218 3c3ced2b",
+ "40510e78 40006d00 3c77bc88 41986420 41986db0 -> 41b28ab7 40006d00 3c8f550e",
+ "418688da c007d278 41044828 4183385b 41833b35 -> 4204e151 c007d278 41044b3e",
+ "40ce7218 405421ec 39344ef0 409abdcc 409b504c -> 4134bc92 405421ec 3c159f21",
+ "c18c9061 406fc0f8 3a401aff 409b1310 409ba190 -> c14b739a 406fc0f8 3c1ad707",
+ "3fe5fb50 bfb37efc 3d0f8f46 3f89224c 3f99c7b4 -> 403bb828 bfb37efc 3dccf5b5",
+ "3fd0dfa0 402b3c58 3a265b42 41621a30 41622f10 -> 417c4094 402b3c58 3b52a01d",
+ "c183a88c c081a188 3d48d46a c189ca49 c12b490a -> c1f35ff3 c081a188 4053bb3e",
+ "c19d9ff7 c05fe282 401be9f7 c01a8c5a c01a2136 -> c1b0ead0 c05fe282 401c2003",
+ "3f890fd0 c095914f 3e0aaee1 bf258410 40e53782 -> 408a8774 c095914f 408149a2",
+ "409d2e00 c099f3ce 410fc49b 4069076f 4069ff31 -> 4108f7d4 c099f3ce 410fe3ad",
+ "c0d6c884 bf8c0f94 3e858e4e c18307fe c154b0ab -> c1ac624b bf8c0f94 3fe6e21e",
+ "c131fce3 c0454ad4 405ca620 c0ca5871 c0accbff -> c187e300 c0454ad4 407a330b",
+ "c15e2aa4 c06e8ac7 39ea88f2 402fad6c 402fb5a4 -> c1323e42 c06e8ac7 3a3b6bbd",
+ "4029f070 c0043f58 4041b741 40ca5814 40cade94 -> 410fc9c6 c0043f58 40423e12",
+ "418360e0 409f20b6 3eed86e4 c13b0c2c c0f4c124 -> 40d816c2 409f20b6 401f0879",
+ "3efc4140 4015642e 408ad953 3fff667c 3fff69c4 -> 401f3c38 4015642e 408ad9d2",
+ "3f603900 40312eac 3d8fcc0c c0536431 c053625f -> c01b5508 40312eac 3d8fed75",
+ "40fd6d60 bf623db8 3c35b701 c1221fd0 c11a04bc -> bffadcb0 bf623db8 3e87609f",
+ "414a0ae8 c024b008 3d2a840e 40bbac60 40bbb598 -> 4193f1b3 c024b008 3d2ced08",
+ "c080a67e 4080caa4 394bc8f6 c0166ffe c015b392 -> c0cbaf62 4080caa4 3bc33041",
+ "c0da534c c0717886 3b968206 c16185bd c160d849 -> c1a72c54 c0717886 3cd36216",
+ "c0d34b5e 3fc95468 3c5a86b9 c13b1640 c13af390 -> c192554c 3fc95468 3c903283",
+ "beec2240 c016e0e7 3bc92a16 c0bba35c c0bb90c4 -> c0ca5c34 c016e0e7 3beece81",
+ "c09eb2a2 3f1476e8 3ebb66ef 40177ed2 401888ce -> c0256174 3f1476e8 3ebf8f9c",
+ "c15cf475 4075ff10 3e285a0a 41850120 418619cc -> 403899dc 4075ff10 3e6e8af9",
+ "40d6e390 be8839d0 398e2e84 c190cbe7 c19078a3 -> c135d2c2 be8839d0 3ca8fc3a",
+ "408c9980 3fe0e87c 3cdcbe33 c169a619 c1660add -> c1218bbb 3fe0e87c 3e0f05ed",
+ "c08107d4 bf0e4550 3c50f8b4 41790999 417ccd5f -> 413a6792 bf0e4550 3e058f54",
+ "c192f9c3 409bb6ea 3a84e9be 416b2889 416b3007 -> c06b1cf8 409bb6ea 3affb173",
+ "4003af38 40766f78 3a3a8965 c0b725af c087b159 -> c03b27d0 40766f78 3f3e00ce",
+ "415a8f08 c0468ba1 3cfe2194 419fc40a 419fc802 -> 420686c5 c0468ba1 3d034187",
+ "c00ca2d8 be51bb60 3c42e19f be0d5fe8 3fe66cdd -> bfaee540 be51bb60 3f7b24a6",
+ "4167618c 3f34d2c8 3bfb7125 40e1edb1 40fa1f67 -> 41af3269 3f34d2c8 3ec57f4f",
+ "41482ab0 40320492 3aa4c7c0 40c564eb 41075852 -> 419e980a 40320492 3f92c1a6",
+ "418a1c02 c06868c5 3fa254dd 41765b09 417684a7 -> 4202a9f7 c06868c5 3fa2fcfd",
+ "c154624a 3fea7128 3f41956b 40d30d41 40d30f37 -> c0d5b658 3fea7128 3f419e41",
+ "41350250 bffc39d8 3eb831f2 c1393067 c13527a7 -> be0a6dc0 bffc39d8 3ef8bfb7",
+ "c04c9e78 c04e7aba 3cde8c8e 41736ad1 4173704f -> 414045f2 c04e7aba 3ce44787",
+ "41864be8 c0969b34 404b37f3 c19991ab c1904cc1 -> bfea34e0 c0969b34 40704c11",
+ "bf9941c0 3f8c4d1c 3d1a64d5 c182b45f c1829405 -> c18c384e 3f8c4d1c 3d3ae1d7",
+ "412ee73c 3fd36cf8 3ce096a0 bfbedd0a 3fe25e4a -> 41311f50 3fd36cf8 3fd42085",
+ "4102f7cc bfa7821c 3dee9f21 407aa1c6 407aa65a -> 4141a0d0 bfa7821c 3deef119",
+ "41279eb6 40026d62 3f104346 c00d363f c00d3261 -> 410451a2 40026d62 3f104bd3",
+ "4015f9e0 4066096c 3a2b9dcb c19e38e8 c19e2c9e -> c18b7387 4066096c 3b72145d",
+ "40ad4ad4 c00589e8 3ba3544e c09307e4 3f97114e -> 406d5218 c00589e8 40391e17",
+ "4180b736 c028a337 3f5a09d7 c19b03e0 c16d77b4 -> bf828a70 c028a337 4047a2f7",
+ "4015dca8 c0548aa7 3e86a387 c12fe8af c12fdb55 -> c10a6ad8 c0548aa7 3e877c0f",
+ "c174b42c 4049d2c8 3a8f4754 c13553c3 c0718ceb -> c1b6c7d6 4049d2c8 4071f39d",
+ "c18fb348 3f241890 40321b95 413a26ba 413a7bee -> c0ca2a78 3f241890 4032c653",
+ "c135d595 c00d545f 3c9b39c0 41932b13 41932ee5 -> 40e108c6 c00d545f 3ca31511",
+ "408d9cb8 bf093308 3d10b403 410eb2e0 411f83b8 -> 415de9a8 bf093308 3f0f938f",
+ "bf38edc0 bfdf29e0 3914983f 4002f60d 4002f7b3 -> 3fa976e0 bfdf29e0 394e756c",
+ "bfa327e0 3f54ac68 3d4faf22 40d4831a 40d5f3f6 -> 40ac7190 3f54ac68 3d95f98e",
+ "4070a578 c099a8f4 3d2cb9fc c18ae188 c1343ae1 -> c128d59a c099a8f4 4045c3d5",
+ "411babb0 3fc22c78 3fe909c9 c1966eae c19667d8 -> c1112ad6 3fc22c78 3fe94172",
+ "c189305c bf79bd80 3d62227c 419c0f3e 419fe84a -> 40265b40 bf79bd80 3e9768cb",
+ "409d8598 4033d544 3facef50 414b86f4 414b9764 -> 418d28fc 4033d544 3fad3224",
+ "c1783c15 3fca9938 40af9a1b c073345d c021f963 -> c19570e6 3fca9938 40c3e916",
+ "413ae0c6 40367198 3e446b0e c0f2c661 c0f1abc7 -> 40838878 40367198 3e56185f",
+ "bfa48d50 c0989c5c 3aa97654 c12b2889 c1077efb -> c12de56c c0989c5c 3f8ed172",
+ "c14283ac 4022abaa 3b7197d6 c19f35a4 c19eec28 -> c200295e 4022abaa 3cb197fd",
+ "4192dc10 3f7191c0 3ccd062f c03e6b98 c020d0e8 -> 4179d090 3f7191c0 3e833d9c",
+ "c1868fbe 403170f6 391fc6a8 41495dfd 41497d8b -> c0876370 403170f6 3b83d303",
+ "40ef8b80 4024713a 3ed2ddb1 c0c570f4 c0c50b84 -> 3fa93510 4024713a 3ed60a80",
+ "418b6e62 c088faf4 39ade173 c0e48235 c0e47cbb -> 41249d08 c088faf4 3a33fe33",
+ "41929d0c 409e7062 3d505596 3e065cc4 3fd46c48 -> 4199c6cb 409e7062 3f50a7b4",
+ "c1909400 c04cb712 3b34731b c170fdba c1702f9a -> c2046faa c04cb712 3ce5152f",
+ "416c1724 bea589e0 3fa73855 c0f706db c0f6d21d -> 40e141cc bea589e0 3fa7a254",
+ "3f35f7a0 c04db2a9 3d1c9532 40e84a00 40f88d70 -> 41039556 c04db2a9 3e95b096",
+ "c19b4819 401f07f2 3fcf37fd 4185a359 418fc1df -> c004abe8 401f07f2 40101679",
+ "4106fd1a bfffd0d2 401a3fe0 41356b62 41801563 -> 41b0e417 bfffd0d2 4097dfae",
+ "c1708dc5 3fc00bf0 4111a4ff 4157cc42 4158ba26 -> bfc25488 3fc00bf0 41121c0b",
+ "41946bac c08f0373 40c3b924 40698fef 407a8f51 -> 41b2ada0 c08f0373 40c7f946",
+ "417f9798 bddb9c80 4069b771 c110ad37 c1101e77 -> 40de6382 bddb9c80 406ad540",
+ "c1338904 408acaca 3c44a75c 418e2a3d 41a7b1df -> 41025318 408acaca 3fcdc778",
+ "41248f6c 3f0dfa30 3c45ad7d 404d7b81 404d84bf -> 4157ef74 3f0dfa30 3c4a9195",
+ "c139cdda c05de6ed 3de02bd5 4101425f 4101441d -> c0622a70 c05de6ed 3de0a2ed",
+ "411ec068 bffb3bc6 3c8b4c2e c14660cb c1462f6d -> c01e1ed0 bffb3bc6 3cbccbe4",
+ "c133eed5 be777760 41071903 4122aa70 4122d270 -> bf898328 be777760 41072d17",
+ "bfb4cd10 c0325e70 40823e89 c1a58527 c198916d -> c1aa581b c0325e70 409c2660",
+ "3f8265a0 405707a4 3d8cd14f c04343b2 c03ccb8e -> bffda9a0 405707a4 3df457d1",
+ "4131678a 4075f1ac 40391db6 418d23e9 418d257b -> 41e5d877 4075f1ac 403924d3",
+ "402fcec0 c02a69dd 3c3b2a70 40f01ab8 40f04548 -> 41240bb0 c02a69dd 3c660c31",
+ "4146be48 bf0c3420 3af7d215 c06adebe 3f9484fc -> 4132aac0 bf0c3420 401aafe0",
+ "4074d5e0 c0922fd6 3ed15765 41653305 41653e83 -> 4191371e c0922fd6 3ed213f3",
+ "411bee72 408f7e8e 3e500a15 405c3e9c 405d36e4 -> 41531d22 408f7e8e 3e57d1ab",
+ "3fb76ed0 3faaedc0 3c3efeb0 411786ea 4119a7d6 -> 412f853a 3faaedc0 3da025d4",
+ "c0a1aaf6 3f5bae28 3a5733de c17f615d c17f4aab -> c1a815c0 3f5bae28 3b6dba4d",
+ "4168cebc bf62a268 3d0942f4 c1a29f44 c194cade -> c09d36cc bf62a268 3f65dc3f",
+ "419b3d84 c08b6ed5 3b49bb6b c0662f77 c060a659 -> 417da04e c08b6ed5 3d3dd751",
+ "c199c64c 40951c84 3c974d55 c18ad30b c18acf8f -> c2124bcc 40951c84 3c9eba8c",
+ "bf353a00 c07740ca 3eb4383a c178d0bd c159def5 -> c174ab79 c07740ca 3fa8d64f",
+ "41526a6c c03175d0 3b5e247f 3df2f93f 3e8ec6b0 -> 41559880 c03175d0 3dab0a22",
+ "418b3e68 404d0fbc 3e6dad45 c1a804d0 c15f835c -> bda4d700 404d0fbc 406fe7cc",
+ "c1302d42 c0181511 3a1adfe0 c17343e7 c17342f3 -> c1d1b858 c0181511 3a4452d4",
+ "c14a21ee 3ec33790 3eb36213 c19c9ddf c19c970d -> c200d5b6 3ec33790 3eb442e3",
+ "40e59838 3fc0f950 3aea2b63 419f935f 419fac2d -> 41d905d4 3fc0f950 3c013fd5",
+ "4032d358 c04ca450 3bb244f3 be9f9b4d be9f57b3 -> 401ee428 c04ca450 3bbae82e",
+ "c11994b2 4070f6c8 393517bd c1245251 c123af55 -> c19ecac2 4070f6c8 3ca4a9fe",
+ "40b4891c c07c849e 38d1e1c1 c0dd9a43 c051bde2 -> 3f0a6410 c07c849e 3fe97a55",
+ "c15694b3 bf8b58fa 3ac3ae77 c0155ace c014f032 -> c17bde13 bf8b58fa 3b9c20f7",
+ "41248878 40477a78 3b9831e1 419dcfda 419dd046 -> 41f0144c 40477a78 3b9d38be",
+ "418e22b8 bf73cd60 3e9f7d10 4153cba5 4153ced3 -> 41f80956 bf73cd60 3e9fb5a1",
+ "c14e123a 409723fe 3b612ad1 c183bd26 c183bcb0 -> c1eac608 409723fe 3b6bb378",
+ "41232120 be88ca40 3a5274b4 41851ae3 4187ec81 -> 41d81442 be88ca40 3e354511",
+ "c0c24814 c03674f2 40648139 407f660c 4080296a -> c004b3b8 c03674f2 4064f7cf",
+ "c186cea8 3ec2dd10 3b9d9e24 c180936a c1809264 -> c203b0c8 3ec2dd10 3ba7592e",
+ "c1078766 bf572928 3f8d6d4a 40ab191a 40b1737e -> c0419100 bf572928 3f9a2267",
+ "41253a5a 405dfd14 3bc0dd5d c032cba9 c032bb97 -> 40f112e4 405dfd14 3bd15dc7",
+ "41635ea8 c04e32e8 3a9e878c c18af503 c18aea83 -> c04a0378 c04e32e8 3b78bfcd",
+ "40d7f924 403edee8 4067b3d3 c0fe3dc9 c0fe38c3 -> bf990888 403edee8 4067b918",
+ "40f50928 c039771e 3b74c14d 4114b30a 4114b386 -> 41879bee c039771e 3b7a73a6",
+ "3fd7eb50 40805d8e 3eedf3fb bfd6eb90 40d25864 -> 40844994 40805d8e 4092e90a",
+ "c07058c8 c08a221a 3dcdf273 40c7ccd5 4110d4d2 -> 40791db0 c08a221a 3fc0995b",
+ "4127b80e c0574398 3e680a8c c036832f c0364711 -> 40f43d8c c0574398 3e69ef01",
+ "41829206 c073a22f 3f1136e6 40fe5edc 411d05fa -> 41c99f60 c073a22f 3fbff6e6",
+ "c152f122 409f7c34 3fd631df c1201e2e c115a300 -> c1b6e8dc 409f7c34 40000feb",
+ "c10c7c37 3fa1acfc 391cfb1e 418cf35c 418d1714 -> 410d8e39 3fa1acfc 3c11c2f2",
+ "c1870824 c07f09d7 397c76fb 409bc3d3 409bc6fd -> c1402d94 c07f09d7 39edea29",
+ "41647f40 c0776a70 3f6b9698 c0254e23 bfd598da -> 41427bee c0776a70 3fb04da2",
+ "4137a2da 3f45f670 3d2d5f25 c14fe814 c14ea32c -> bfbd1630 3f45f670 3da7f13d",
+ "3e500b00 c06e9a6c 3cd50028 419c4ce3 419c5081 -> 419deec8 c06e9a6c 3cdc923a",
+ "40389b10 becf9530 3dbbab36 4164c5b3 417f577d -> 41901aae becf9530 3f6c05eb",
+ "3fe02800 c08df1e5 3cc33fea 413c0e2d 4141483f -> 415ab036 c08df1e5 3e3fb1d5",
+ "41331352 c0955959 3e4bd629 c12db3a6 c11b672e -> 3f685e80 c0955959 3f455a5e",
+ "40cd83cc c0840df3 3939172b c0f1c494 c0f128ac -> bf8fcb50 c0840df3 3c1effa0",
+ "413c8e7c bfde076a 3b58c22d 41898bb1 41898c23 -> 41e7d328 bfde076a 3b62e0ba",
+ "406e4500 be89e4f0 3e6188a8 40e3f787 40e40789 -> 412d9104 be89e4f0 3e628d66",
+ "c15de1cb c06447ef 393348f5 40ce4568 410d9abc -> c0c70626 c06447ef 3f99e659",
+ "4097c4c0 3dba2a00 3a803ebc 413119fc 41324848 -> 417d9382 3dba2a00 3d1b4315",
+ "41406308 3fb09af0 4116cfae 411c2dd0 411c2e48 -> 41ae488a 3fb09af0 4116d015",
+ "4122558c 40859c48 3b294d7f c0ecabb8 c05c88a1 -> 40973314 40859c48 3ffd2408",
+ "c0528fc8 c0871887 3a3d1fcd 3fa588fc 3fa7f144 -> bffe6270 c0871887 3c26021e",
+ "c122d587 c05c7182 3e527937 41470911 4147106f -> 4010dce4 c05c7182 3e53698e",
+ "c1895f31 bf8f90a0 3f783632 3fc7e57c 3fcf0de4 -> c1794f2c bf8f90a0 3f7f5fcf",
+ "40aeb680 409bbe18 40dee740 c0aaa726 c0aa9f96 -> 3e026440 409bbe18 40deeb2b",
+ "c15f0f6a 40791a64 3b15a3b6 4116a498 4119aab8 -> c08dcf84 40791a64 3dc63e21",
+ "c15bbefb bfd77408 3d810628 41859059 418597eb -> 403da524 bfd77408 3d84d9dd",
+ "40e0b164 c045ff0e 3b5945a8 4118e415 41325ffb -> 418afd5d c045ff0e 3f4cba7c",
+ "c187d85f 4096ef2a 3d183872 c129e1e2 c1279b20 -> c1dc37a0 4096ef2a 3ddde235",
+ "bfbd6100 405dc448 3c0d367f 3f866eab 3f8a9e15 -> bed36a80 405dc448 3ccc9278",
+ "c05f5298 405a0524 3c9a8644 c14391e3 c14372d9 -> c17b5704 405a0524 3cb9cefd",
+ "412ad95a 408fa91e 40729da7 c157d680 c14cc988 -> c01ddaa8 408fa91e 40845bfc",
+ "3f920d50 4043e974 3c720e7e 41716e9c 41717b4c -> 4181db4f 4043e974 3c85fc0c",
+ "4184723e 3f74f6c8 3f0822aa be0e799e bd8298c3 -> 4183a278 3f74f6c8 3f11c974",
+ "417340ac c085346d 39235ef8 40febe7a 40ff7e96 -> 41b967f8 c085346d 3c4336d3",
+ "40d2f9d8 be8bea30 3eeab853 411380e2 411aa82a -> 418048b9 be8bea30 3f2e9814",
+ "c0f9a768 3caeb600 3f07fb5f c129b719 c129b06b -> c19343bb 3caeb600 3f0832a8",
+ "c0eb883e 4070fee0 3bdbe3fe 3fd129a7 3fd81599 -> c0b66056 4070fee0 3d0a46d0",
+ "41110674 c010132e 39f1a2b3 419d16b9 419d1e27 -> 41e59daa c010132e 3b183ddd",
+ "c1139a31 3ec16200 3e1c5381 418aaa09 418dbb3f -> 4104cb17 3ec16200 3eb053d9",
+ "416b162c c07f2078 40339a9b 418fdf6b 4190e9c1 -> 4202f7d6 c07f2078 4037c4d9",
+ "c0dad798 40415ed8 3f19eae0 410a3cb8 410ffc38 -> 3ffd8560 40415ed8 3f47e7cd",
+ "c103a95e c0355297 3a4f798a c016e996 c015979a -> c1293984 c0355297 3c3634b7",
+ "c1978de1 c08c75a0 3a81a8e6 3fa857b0 4117703a -> c158de2a c08c75a0 40826d9e",
+ "c1940d32 c02c9577 3a88a5b2 4189420d 41974b77 -> bef19c00 c02c9577 3f60dc63",
+ "4086a7b4 4090534c 393550e9 c090225a c09019b6 -> be976540 4090534c 3a39e81e",
+ "c16eaf57 4056fe34 3f6f4ae8 c1a20d68 c1919360 -> c2089408 4056fe34 3ffb7792",
+ "c13db33c 3f9001d8 3f6e6b68 40289206 40ca7cfd -> c0ec0378 3f9001d8 4031cf1b",
+ "3f0dd080 c072b8f6 3e2ba483 415378d2 4153804e -> 415c5998 c072b8f6 3e2c9bc0",
+ "3ecb2140 c0818964 3e92a9e9 3f8f7446 3f8fcbfa -> 3fc26870 c0818964 3e935a30",
+ "c13aaef0 bfce732a 38d696b3 4190e30d 4192e1e7 -> 40d22c08 bfce732a 3dffaffb",
+ "40af5748 407e8ebc 409e1ce3 c17e7844 c17e77c4 -> c126cc60 407e8ebc 409e1daa",
+ "c09c24cc 4022ed6c 3be3bfb3 3f176b8e 3f2cb832 -> c087e290 4022ed6c 3d46e49a",
+ "bfd53c90 bf464890 3a2613b4 40490769 404927d7 -> 3fbcf2b0 bf464890 3ad56e81",
+ "c05c72b8 c014f6c8 3db068be 410d6d76 410dc776 -> 40acfb90 c014f6c8 3dc6f116",
+ "41854f48 3f5acf60 3bf09a7a 40fe0e26 40fe36b2 -> 41c4d7e3 3f5acf60 3c215ee5",
+ "3eccd440 c019da19 3d222852 c1a5bf58 c132136e -> c178626d c019da19 409aafea",
+ "41388a3c 4055b748 3fc6d0e2 c0cce677 c0ccdb71 -> 40a43384 4055b748 3fc6e771",
+ "c0f883ec 3fde63dc 3e92b16a 407024ac 40733034 -> c07f5d68 3fde63dc 3e9ee0c5",
+ "4125ef9c 4021802e 39e79c74 c129c0ca c11ad38c -> 3e695c40 4021802e 3eef0f82",
+ "c1840a69 408b266a 39c03fc3 c1263f75 c101c0b3 -> c1ce0a73 408b266a 3f920859",
+ "418d23ec 40211214 3b260717 bf534e02 be31f3f8 -> 418924c0 40211214 3ea81fac",
+ "c18f841a 3e7ba7c0 3ad04392 41285925 4128e68b -> c0ecd0b8 3e7ba7c0 3c9a8eab",
+ "c174384c c0298ffc 3b0ced88 3e9b4507 3fa09bfe -> c167c178 c0298ffc 3ef4b1af",
+ "409f424c 3f57cd20 3fa1ea3b c10d0878 c03da150 -> bf697400 3f57cd20 40861ad0",
+ "4119b164 3f4216b0 4112ff2a c14bea47 c1464bdf -> c03da6bc 3f4216b0 4115ce78",
+ "c156e19b bedf0dd0 39e195c7 418174d1 41817887 -> 40302ef4 bedf0dd0 3ab19167",
+ "40406730 c06214e6 3aeb25a0 c12ca02b c12c9f65 -> c0f90bf8 c06214e6 3afa4906",
+ "c19443ec 3f082b50 3bb9d72c 40457381 40457faf -> c1772972 3f082b50 3bc69dbe",
+ "4134038e bf2a2f70 408b9bbd c184474a c1842e5c -> c0a8e430 bf2a2f70 408bcdcf",
+ "3f77f980 be10fbe0 3de4a29e bffc40ca bffc29b6 -> bf803880 be10fbe0 3de55cdb",
+ "3dfbf400 c076c407 3f21aba4 c0ec6e1e c0ec6a66 -> c0e87c72 c076c407 3f21bbb6",
+ "c0ac7ba8 4025c85a 399c764c 41316490 4132f764 -> 40b7e04c 4025c85a 3d4ab67f",
+ "40736620 bf82c7d8 3b9c33a7 bfe90106 40319793 -> 4088f8d4 bf82c7d8 40135a4e",
+ "4196ee4c 409af944 391f206d bfdf496a bf8f7056 -> 418b787e 409af944 3e9fc917",
+ "c18934d6 c02a85a8 3ad7b8ba c14dc065 c14dbd6b -> c1f0144a c02a85a8 3b0684ef",
+ "c0f78582 3fbd43f4 40587ffc 412bf55f 412bf8d1 -> 4040d15c 3fbd43f4 4058872a",
+ "40e45c48 405dff88 3e75a967 4111ff10 411ad628 -> 41844c60 405dff88 3f0424fd",
+ "bfc91160 bf911030 40983b6b c181834b c17e83a2 -> c18cf3a4 bf911030 409cbeae",
+ "c10e5030 bed5e5a0 3d94eef9 4198d543 41997669 -> 4123fb7c bed5e5a0 3de590f4",
+ "c095310c c080ae26 3c45069b c15d5ea8 c15d1990 -> c193ea51 c080ae26 3ca7e40a",
+ "3fcc6880 bf00fdc0 3a0bc580 40f568bf 40f56b49 -> 41144212 bf00fdc0 3a38c1a9",
+ "c1138271 406d8984 3da59e58 c16f0f16 c159c228 -> c1bbf588 406d8984 3f3f1de9",
+ "410b2034 406208f8 3b8c3867 3fdf9819 40b7818a -> 4146fa18 406208f8 3fffc3fe",
+ "411eda00 400df704 3dce454b 41286f0c 4128cc98 -> 41a3bbe9 400df704 3de5b8f7",
+ "405992c8 c090608a 409bb4fd 412f3fd8 412fa860 -> 4165d8ce c090608a 409c1dcb",
+ "4090a614 3fce5ec8 3b0a0416 40623497 408d3634 -> 4107e72a 3fce5ec8 3ee1f52b",
+ "c13a6674 c02b9ed9 3f1286ac c0e4e3a4 c0df84ec -> c195c04c c02b9ed9 3f28035f",
+ "c12d926c 4000f530 4105821d 40ae96c5 40af6213 -> c0ac286c 4000f530 4105b506",
+ "40655140 404345d0 3f6a71aa c14b123d c0ac9046 -> c0aeb1c0 404345d0 40921883",
+ "c04164a0 c06b8d26 40fabdb3 c193033a c18795b0 -> c1a57909 c06b8d26 4108cc97",
+ "40cee0ec bce11000 3e3b8975 40c9a190 4104e5c0 -> 415c4bba bce11000 3f97c5c9",
+ "beb63b40 3df97880 3beb4968 c1399632 c13928d2 -> c13f115c 3df97880 3ca861b8",
+ "408a9c58 3f884574 41025fc4 c0bc5454 c0b87a40 -> bfbf2bc8 3f884574 4103565a",
+ "bf140f40 c07ef286 38d91218 418e644f 4190ae91 -> 418ae8f6 c07ef286 3e12b586",
+ "c1910d98 401806f4 40d33646 c11e8348 c0eaa031 -> c1d60270 401806f4 40fc69d3",
+ "41331ee4 c01bdd50 3e54b02c 4140f3a3 4140f46d -> 41ba0976 c01bdd50 3e54d2e9",
+ "bf41fd00 3fe97ca8 3a8cd91a 412bc041 412bc207 -> 411fa154 3fe97ca8 3aac0a4a"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_mul(vec3, vec3)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "41075bac 3f4af898 3967eae5 bfbe3570 c05d8722 3ec408e6 -> c1492496 c1f3b01c 40c939a5",
+ "c0d94220 402f4f90 3a15cdde 416d3958 409a98ca 3fa69caa -> c2c952e2 40fa03d8 41cd308c",
+ "c01ec080 3fca088c 3cdf5746 c0e2cd42 c06d77bb 3914903a -> 418ca53a bffdd898 40c4d91f",
+ "c0aa1fdc 4035ee2c 408585f8 3faab210 bfa8e69c 3f80a3bf -> c0e2defa 412ce582 41d9b797",
+ "c186392d c029d48a 3fe03804 403288d8 c05dcd2e 38dc3ebb -> c23b3702 424af9bc 41a13fd4",
+ "418847ec bf7f73e8 3a99ba0f c12e8e34 4081796e 40597fca -> c339d92c 429f9f9b 4282af9c",
+ "c1958961 3ecd8a20 3f70d183 4197ea98 400a85e0 40d27f52 -> c3b17a21 c203564e 43188e0b",
+ "414802c4 bf5c8c20 4048295a 41923b8a 404bd2d0 38dfcf7a -> 43648030 41c08296 428bbfb0",
+ "c0ed9a00 4015d44c 3bbcc67f 40c2c048 40590fa0 41053c59 -> c234c12a c12ef540 42b2bc31",
+ "c13e0ef2 c04dfa95 3a952dbb c11426b6 bf96a8a8 407c8497 -> 42dbfac2 422f2100 427d7c87",
+ "416b780c 4026bcba 3e01a3e2 c161d454 408e54c0 3da83447 -> c34fb7cf 41e57dd8 4175f08a",
+ "408b95f0 c03921ec 3f156a6f 404f0088 c00653df 3db40ca0 -> 4161bd0e c194179f 411df92e",
+ "c1293bd2 bf89ca3c 3964f06c 4193590e 400d537c 40bcdbe2 -> c342d071 c22cbc32 428e5259",
+ "4180721a c070e96e 3c455b28 415b8c0c c01c90cc 3c4cab89 -> 435c4fc1 c2b5dbec 411a6c3c",
+ "40c2c284 c010d04d 3d82ccee c12cf620 c0983fa1 3edb8a92 -> c28395f0 c08fe5c4 4175e023",
+ "40f99ee4 402913f2 3a2159ff 41704c98 c07ba2db 40c0a18c -> 42ea4fa5 411019f8 42928705",
+ "c0c8cab2 3fd3ae30 3cb56e3f c0eb57aa bfc2a7ca 3ddfe5a7 -> 423896d4 c027b0b4 40652b54",
+ "c11e73b4 401572de 3c87f222 412880e8 bf559028 3c8c6ae9 -> c2d0976f 42036a82 401632c7",
+ "41853558 c024c10d 3c9e83cd c11b7e45 bfaa15d4 3b00da3a -> c321d201 403915e8 406b0a03",
+ "3dfa6000 c0980a01 3d0974b9 c13f41c5 bd4d6580 3e680c81 -> bfbb0df3 426326c6 3fe06645",
+ "c199026a bf9a7dce 3a606d70 c1976e04 4076f0b0 3d2e957e -> 43b5045c c24bcdc1 40b16590",
+ "c030ba50 bfb310d4 3b2f725a c17860dd 3f962ee8 3946888b -> 422b775c 4193d0ab 3fd7ee0d",
+ "bf183be0 3f5a4028 3f416a20 414563ec 3f67ff10 3d269488 -> c0eac2fe 411fa934 412de241",
+ "41981b2c 4078e05c 3ff7279d c176e15a bfeec1a0 3f4f4062 -> c392b002 c2beef7e 4273038e",
+ "c113c47c bf1ec928 3c1e64ad 417f707c bfa3504c 3986abaf -> c31371a5 3ff0c620 3f75f3d0",
+ "bffc2300 c0652394 3a3a6b2d 413eb9aa c003a700 40defa0c -> c1bbd8d7 c21a814a 42383686",
+ "c049a270 c02f97ad 3fdd9800 4185c7fe bfd6a104 3948e40a -> c252bdd3 c2226460 4211d225",
+ "c158c8fc 4042cb8c 3e08ee9c c07b29d8 402e0578 3f4fc3ff -> 4254b07e c2432497 41b5ea64",
+ "bf2d55e0 3ff921a4 3c730c3e 419aa898 c02f781d 3ddbbd96 -> c1516fa0 421def40 40be4ccd",
+ "4148e610 40826e42 395fbf8d c07391d0 4024e874 3c8e25b5 -> c23f24cf 4186baa9 412cae3e",
+ "c16d86af 3ea30780 410add15 c13db36a 3fce4704 3cc3120f -> 433002e7 c1dd97f8 42ebefc3",
+ "41766fb8 3fef8530 3b3ac2a4 41447f74 bf9066ec 3bdaf83c -> 433d283a 40b35d34 4010f46a",
+ "40def454 c08dacd3 3d785eff 41406f60 4090f3d2 3d0fd72c -> 42a7983f c1ad8176 41abb0ab",
+ "c15be5b4 406b05f8 3e5b17ec 409373a4 bf56e898 3e7ab7f1 -> c27d5077 41e3ab80 410909e3",
+ "40bd09d4 bea6ac80 4073b763 40248a80 409ae9cc 3c0c930f -> 41730123 41de1711 41ef19a7",
+ "4180e48e c09ac214 3cb327c1 c080419c 403916ac 3f80b566 -> c281269f 4283f4ef 420ce477",
+ "c189fdae 40927536 3a08559e c160138b 3e2c5d40 398b26a1 -> 43719102 c2860048 3f48aa40",
+ "beba3fc0 3fe15658 3b61cc45 c189d59a bff451f4 3a368a76 -> 40c88f0a c1ed1870 405b5fad",
+ "c1902367 c09bc4a7 40bdc775 40113910 c020fec0 40354d7d -> c223885c 42091c92 42f480db",
+ "41345abe 3e0bf800 39c6d918 c0f34e94 3f0f1eb0 3a73d332 -> c2ab697e 40a866c6 3db8c1fa",
+ "40179a00 bfe565d2 3ea7a3b1 41815d48 40815b2c 3bea23cc -> 421937af c19b3d33 415e5197",
+ "417e1790 c0106508 3b0f7bcc 4123e24e 40146aba 4117907b -> 4322a99f 415b7e52 4331166f",
+ "c0aba8ce c09de915 3bb919b4 40501568 c0707430 3f005048 -> c18b8782 40838654 41bdf549",
+ "c0a5fa82 3f48c080 3a223c84 411e7302 3e1696c0 40e4d91c -> c24d765a 40e0195d 422b4fae",
+ "c02de1a8 bfc50a54 3f30fa49 40467590 3f9708e8 3b1c5d86 -> c106cc62 c0ff56a0 409934b6",
+ "40ec66f8 4025abf0 3c2738d5 418fd77c 3f6817d0 3a7a7cee -> 4304d482 4254f767 402328cf",
+ "c097583a 3f5dcdd0 3f390b22 418bb9ca c051c2c5 391c6cea -> c2a5357b 41f511e5 418ead1c",
+ "418028ec c004291e 3b27254c 4192fbd8 c045dd55 3ad45deb -> 43932ad6 c2aeefc2 40ceff62",
+ "3fcd12c0 c03faa9c 3c10fb07 c09eff34 408caafc 40f6f00a -> c0febc04 41af61fb 4243286c",
+ "c194ad2e 40477380 3f8946b0 4114921a be8e6830 3d7d11a1 -> c32c91f1 42086dbe 41487ec0",
+ "4083ac38 bfe70ba0 3e43fdce 419d9c40 c0892896 40ea9c51 -> 42a221f8 c254cb30 4264882c",
+ "406f69b8 bf560d80 3c44ae45 c15d3898 c0404e87 3d47cdba -> c24ee331 3ea40800 403c0eed",
+ "4195d2ee bf29c358 3c2fe6d1 c170e8a1 405e2128 3aa7519b -> c38cfde5 4295f87f 4021a3d1",
+ "40f2a1d8 be8b80d0 3a1c8e33 3f853960 c094027b 3c485a15 -> 40fc88ec c20d6a50 3fae0b93",
+ "4177237c bff499d4 3f9fcd70 c041d320 408484aa 3f49106b -> c23b1d92 428b817a 41fbd268",
+ "c08cd5d8 3fbf8394 39c3d11e c13746b2 bfd4c50e 3feaf31d -> 4249a784 c11d2a65 41551490",
+ "c09bb4f2 40828cac 3aa91601 c0f565a4 bfabc57c 3f3ec367 -> 421541fe c1c60bed 41427429",
+ "4150ab88 bf924a20 38d4250b 41611b54 bf6c95d8 3d0aa1e0 -> 43377d09 c1e10ee6 3fc4de2c",
+ "403692a0 4083c724 40d4cd46 40594478 c0925f6a 411ef560 -> 411af31e 3f6e6c10 434f2701",
+ "c07872a0 c0876888 3b288100 c1271889 c07beafd 3f263125 -> 42222a96 426de372 41afb25b",
+ "c15d972e c053b0c8 3d04f369 40af2ad4 40293254 3d661236 -> c2979f6b c25ae100 411f93f1",
+ "c044a078 4022ec8e 39a5a0b5 4008bf60 401cf1d8 409ebecc -> c0d2107a c006104c 42087629",
+ "419fb53e bf97f884 39b39ae3 c0989bbe 3ffff748 3e39d1e9 -> c2be698c 423655cf 40c6e034",
+ "c055d368 c094fbeb 404d7d2b c0eee1aa 4061e690 38d76050 -> 41c78707 41b7b360 424ef1de",
+ "41494020 404343f4 3dde13df c1766299 4046d5f4 3afc6ce8 -> c341b122 c0fcf5b0 41384285",
+ "40350f98 c066c1f0 3f825cfb bfce9d80 c05d1ba4 3a7bfe78 -> c09221f1 c07d0bfe 418d02e2",
+ "c111cd41 c046e9e1 3e02ebad bffa5e30 bf36f238 3e3c8717 -> 418e9816 414976aa 409ac0e6",
+ "c070ab88 c09a4598 3a326b05 c197dabc 3f5b9a80 3e4f6ce6 -> 428ec2d0 42b0921a 40bc67d7",
+ "417b3070 c098e764 3bfb16d0 40a6be14 404e5c50 3970160e -> 42a39bea 41cdc7f7 41779f4c",
+ "41672334 4059d9a8 3b79eb31 baf84000 404e5548 40c835eb -> bce023e3 423a44ba 42f5617b",
+ "418db78a bff58b0c 40a7b8c7 415b8328 409a75f8 3ddae775 -> 4373093c 426cc0fc 42da4090",
+ "c167fc89 3ec9f170 3ab25a5d 4183524c c07a809e 3d12a2bd -> c36e019c 427ce709 4006b819",
+ "c1964440 4094eb74 3ddb2a31 c1211570 40825d08 3fbfabc5 -> 433d1b03 c2f6bf14 425ee973",
+ "4156dea0 4038f59a 3aa3b8ef 418ea198 c0319308 3f6044a2 -> 436f6e3d 41643a88 41b2bcea",
+ "41733b3c 408cf26e 3b7c0de4 4112f77c 3f7c2478 3b73d912 -> 430ba2ec 425db947 408e6a76",
+ "41736564 402e3a80 3bdf9805 40cf7478 3da8a500 39d19b6f -> 42c53db8 41973609 3e8d716e",
+ "4105d764 3f2147d8 391d45b0 401ba290 40784710 3932c60c -> 41a2bcce 4207ee9f 401c93e4",
+ "c02787d8 409a45ea 406ca684 416a4dc4 3f7f9e28 3ff6e7df -> c2195510 4287f886 42a845bb",
+ "bfadbef0 3f907144 4093f89f bf409180 3fd2333c 391a059d -> 3f82b1f4 c044fced 414ed1a5",
+ "4119910a 409f15f2 398c8359 c15c8e24 409423f4 392a82eb -> c3044de9 c1c0c718 41b82d8a",
+ "c1072df6 bf6bd018 40a2243d 41840a58 c0966064 3b9d7c32 -> c30b7252 41c3fe7c 42dfad95",
+ "c163db50 bfa8857a 3c9e2830 bf144400 3ec89970 3bacbbc8 -> 4103f751 c09a256c 3f1de00f",
+ "413fe8e0 c0100a05 404ce216 c1514b21 3de4a4c0 3ad0c835 -> c31ce571 41f63b56 422a0ca9",
+ "416ff2e8 c09b8944 3ba5624b bfcd1d40 c01750a4 4107a160 -> c1c040ee c1dd5860 4333e213",
+ "c09829cc bf81230c 39b5d155 c0d53db2 40871498 3d132b79 -> 41fd7ee5 c15597d8 408f07d4",
+ "c194e246 3f099620 3dccf1d4 419dc0e8 c011e964 3ccde34e -> c3b77deb 42541c2c 407a4cac",
+ "c17c8c9a 3e6095a0 40b8345f 4045b3d8 400e2916 3abc62f1 -> c243099e c20988c2 41f8b251",
+ "c08018ba 4099c630 3974ddf9 4062de00 3fe81c10 3c10d12e -> c16309d3 411c682c 410cb0af",
+ "c16b4ed8 3f2b70b0 3cdc6fa4 415cec60 c00c810b 40b1de2a -> c34b1107 42262284 42af098c",
+ "410109c0 405275b0 3a0a134f 4191b24a 3ea14ca0 3e124101 -> 4312e0c8 4279b82f 402ab966",
+ "c12ddc03 4046c388 3c8b7783 418ebc3e befbfd90 41074c8b -> c341dfc3 42730997 42f04498",
+ "411c5e0c 40446714 38d8e655 c04a3240 c08a5f44 410d5859 -> c1f701ce c24fd1bf 42fd6eef",
+ "c1076b78 c0017a0d 3b3c9fde c17a2cf2 c08ccba6 3b2a7483 -> 430456ba 4289be76 410fc844",
+ "4183d584 403b3398 3ec6adb5 410bfd42 c03f5001 3bc38a8b -> 43102eb5 c1bd5996 4156ac53",
+ "c197f6ba c046b0ec 3b185df9 40c15f34 c00587f2 3c86a8ec -> c2e5930b 41a6fa40 40db8364",
+ "c0d2430c c05ff12e 410f4e13 c0e50842 bfc16e10 40673049 -> 423c1cc2 420be4b8 4317a813",
+ "41369634 beec26c0 3d367596 c183c41a 405c5974 4016d23c -> c33bf574 423b8c10 41f47a6b",
+ "c0917778 40073db8 3d009bad be054500 3f115f60 410335f2 -> 3f17748d c036cf9b 42605999",
+ "40c92c20 3f6cdac0 3f32cecc 416739a0 c0922339 3efdacac -> 42b5b419 c1756cac 41ab6d48",
+ "41843824 3dc4d740 3de4748f c182dc7a 4086b2f8 3b04a372 -> c3872cc3 4287fead 402eea01",
+ "4107c718 c08228c7 3d1adea9 4018f9d8 c084b585 40778ccc -> 41a24573 c233a97c 4283a346",
+ "419f9e04 40958c54 40b18006 c0994256 bfe1864a 3ddbcb64 -> c2bf1d9a c266253a 423f3eec",
+ "412216e8 404f3338 40b04581 415bb980 bfd68e02 3ce63eb2 -> 430b1f0c 41dbd4da 42b5acf0",
+ "4163b254 3e913d00 3e154fe5 c1061271 409e0cc6 3e9fc10e -> c2ee7f7e 4287d266 40fd5d3e",
+ "40df27d8 be82d940 39b33c13 c11f1637 bf6bd1a8 3fc92bff -> c28aad1d c0788017 41399fdc",
+ "c0fd5bf8 3ff89e54 3d3d43ce c1142526 bf9e9e92 3f11b321 -> 42929def c102c386 41087b2c",
+ "c0b49022 405105d0 3e0a2e75 4051a030 bca88e00 3db55f4a -> c193daa8 412d0415 3fa80d01",
+ "c19521fd c00ec8c6 3b108ed2 c157e090 c07add44 3aa431dc -> 437b84ba 42ce5806 410cf553",
+ "413a1bd8 c089a49b 3a49b2a6 c1735ebe c0296b49 3c166765 -> c330ed4e 420a8a00 4138bf39",
+ "40a473fc bf4899e0 39a48d2b 414aada8 4076aa88 3de8061f -> 42823313 411e1884 406c9257",
+ "4146dd64 401e523e 3d80695b c179e541 c086f997 3e0ff06a -> c3421f6d c2b61fa8 415c82ee",
+ "c18893d5 be1c3f40 3c8dd2c7 c141d0e0 be1fe700 3d0a70fc -> 434ecdc6 409074a4 3f51b807",
+ "4168c988 c010b5b8 3914d73d c19223fa c01bce77 3ec4ecdf -> c384e3a6 40bc5170 413f935a",
+ "c032e1e0 3dee8f80 3bde9c47 4177cef0 bec99080 3ba085ef -> c22d2889 4039e2ce 3e2c200b",
+ "40cf6904 c04b4f3e 3ca17d1f c166291a 3fb341c0 40bd6229 -> c2ba79a6 425b18c3 427825b0",
+ "40c22c34 3ed85240 40a293dc c19b23af 402d8aa8 3f10e650 -> c2eb57a9 41042a20 42effdd2",
+ "c19666f1 4087d0a4 3a811e92 40b21848 c0835c73 3e05e134 -> c2d143af 42c997f6 41a39038",
+ "412e03d2 3f6fb2e0 3dad4663 40db7518 c01c2845 40cd2af3 -> 42952cdd c1a0ec7d 429eb239",
+ "c0b074d4 3f5a07c0 3a2f6135 c0969ad0 bf9133c2 3bf2434a -> 41cf9e54 400fce9c 3f823212",
+ "c12391fd 4087873a 3b31e97a c13247b9 bf066708 4040ff65 -> 42e3d2ab c2274bee 423774ed",
+ "c152ccc0 408a80ba 3fd6238b be8a95c0 3ee8c830 40a45e9c -> 40643b5e c0e52b9a 42cb5c82",
+ "40255fa8 405f10e4 3d05aa6f c10ce3ea c09bbd09 3b9600f5 -> c1b60716 c22d1158 418b7f15",
+ "3f3b7e80 403a3b66 3c536fbd 411b9b6e c07634e4 400a69d4 -> 40e3eedb 41cbdbc8 419a323a",
+ "41219f90 409cfcfa 40890441 bdc7ff00 40321150 39453bd9 -> bf7c880e 41dd0298 41cfe09e",
+ "41392f30 c0139c7c 3a1d64c9 402c94f0 402d4a9e 3fdd8046 -> 41f9aee2 41c8f439 41f22765",
+ "bfb93d50 404579d8 3cc69c85 c0fc634c bea138e0 3a1f30a1 -> 4136a034 c1bf0b43 3f962d65",
+ "41324b82 c00da780 3936928f 40b77be4 c07b9d5e 3c328a7e -> 427f9486 c2620147 410d95e5",
+ "bfd3a980 c085ab40 3d941c12 415517bc 4068fab0 3dc29fb7 -> c1b02fa7 c2769bde 4187f2e6",
+ "41908456 3c529600 3f8cb5fb c04d7398 be9f3a50 3c9dbdb4 -> c267f674 c0b5183b 4087d024",
+ "41964184 3fdd8678 3a1b6a44 41397c40 40027c24 3b1d67c2 -> 4359bc8b 42696d1c 4065836c",
+ "4137531c 409f1958 39805c6d 40c686d0 404a43c0 3a8a7515 -> 428e2ad2 42861cbd 417bb949",
+ "41635538 c0361672 3b86396c c1161847 4094a7f6 3fc32973 -> c305497e 42b963a1 421d2124",
+ "414c0d84 c07a1e62 4027d398 3f412300 c0938d67 3e9a8691 -> 4119f216 c2770423 4217a3ff",
+ "bf2dd160 40920bba 3c2e3409 4019e5c8 3f943924 3b11d872 -> bfd0fc4d 412303b7 40aab4fd",
+ "c1936392 c091e562 3ba3942a c19998a0 bfd5695e 3f72eb88 -> 43b0dcc3 42ec8167 41ec27f7",
+ "c19f553d 409c67a0 3d9931b6 412e1e2e 40646ad4 39b95065 -> c358bd70 c18f2624 41944624",
+ "c0d9fede 40424768 3b0c82c7 c0aa2024 4098e142 3e331093 -> 4210de9e c242bd0c 4181f97c",
+ "c11137c9 3fee41e0 3d45b680 4196e85e 3f812b28 3bce10e3 -> c32b34ff 41cfa020 403a0af1",
+ "403b53e0 befc7940 3e17c0e2 bfd3bd70 bff74d54 3f0bdbae -> c09af0c1 c09adc2a 405bc0cb",
+ "416d4cb0 c02f2653 3c043c06 41454e3c 3f941518 3f3960be -> 4336e488 c184b827 41800537",
+ "4169aaf0 40568678 4024ea1e 3f8a66e0 c0176dcd 40f2254c -> 417ca818 c1f7716c 432c303c",
+ "c11869c1 c0910855 3aef4d74 412f6760 c046ee61 3ac4e120 -> c2d0dbad c1a09d9d 4162277e",
+ "c033f7c0 c075cd04 40fa3ee5 412457b0 c0084ec6 408e61bd -> c1e710b8 c205d6c8 43298e37",
+ "4114f560 c08a4bf0 3c86a5e0 41999504 bf0818e0 40259d31 -> 4332bab7 c2afd5e1 4217c230",
+ "c158c864 3ede69a0 3e838ef0 415177ac 408068c0 3e119a1b -> c33160f0 c242ba46 41029c7c",
+ "411219d6 3e5b2560 3a63faf1 be6a3200 3ca27e00 3a074dc9 -> c005a827 3e0759c6 3c1829df",
+ "412a72e4 401d7b5c 3c54e351 401c07e8 40063a7e 3d719418 -> 41cfc68d 41e2bc30 40bfce97",
+ "c17b3fb0 403f6d96 3b051161 c0817f7c c096bcdf 3a6bf555 -> 427e306c 42777698 4161fd49",
+ "412c0fc4 c0770b02 409f1c1e bff72c20 c087d393 3d60bef8 -> c1a620de c218c442 4240a94c",
+ "c0db2246 407680e8 3c0f4a02 419fe1e2 bfabd580 3ecbb815 -> c308dba4 42ac5666 4119e3a3",
+ "c103f53c bf2785b0 3a0bf686 409bcb44 c091593b 3e5f6e92 -> c2209c84 4209196c 409d6f63",
+ "c190cf89 408b556c 3df07ce4 415718e0 409cf268 3d4f8d85 -> c37358bc c1f1f396 41c53bd7",
+ "3e8d9c80 c0520c9a 3bca41f8 4178f968 406e69b8 3e316666 -> 4089b993 c24829c9 414f67e3",
+ "409af680 4027f75c 3d190d33 beb60e00 c08d4c0b 3f5d2279 -> bfdc6771 c1b286ca 4191fe3f",
+ "40f4d168 c00f00a6 3c8ae4d9 40b334dc c05617a4 3df8906e -> 422b60f9 c2186c52 410d3fdc",
+ "4122af60 402aaf20 3c029bf5 4101c9be c01508c8 3b1bb72a -> 42a4f528 c002ce60 40ca6066",
+ "c069de60 be125500 3f1591ce 406fffb8 bfbe415a 3999e335 -> c15b4038 409ca8ce 40517a36",
+ "4044e168 408a7b72 39d9655c c0821ad0 408e56cc 40534cff -> c1481e2b c07a54cc 422ecb7b",
+ "c1468b34 bf1a2a30 38f291fc 411a007c bf9b6ef8 3dd4bfba -> c2eee03b 41145b06 40056516",
+ "c13c81f4 4041bb34 3bf8e64b c0b57d54 4089be76 3f33a0fb -> 4285a42b c287c3d8 41bc0466",
+ "c131fa32 bf6ce5f8 3f351a51 419f14f8 c085cb3f 3aac51e9 -> c35d31f2 41e0dae8 41a74aa2",
+ "c1593040 4042a328 40558cff c1857724 be48efe0 3c0cc203 -> 4362764a c2404b1f 42645cb1",
+ "417c6c24 c0974258 3c3a23ef c04a51e0 40848b9a 39deda7c -> c2477e0f 42a09418 419d5d77",
+ "40d198a0 c00489e3 3b9558b8 3fd7a040 befed2f0 3ed9a8b4 -> 41308a62 c0d7f3d6 4096a356",
+ "408559c8 c09ba88f 3c0ee802 41314838 bcda2600 3cac008f -> 4238b163 c258088b 3ed527cf",
+ "417f6544 c08fdc77 3d74b6c5 419ae8f0 bfa40bbc 40a7bf79 -> 439a8b4e c2d70532 42e51a68",
+ "c0e1ce22 3f4c39b0 3fe5e46d 417fda84 c027dd28 3a046ddf -> c2e1ad12 41fa1e6e 420e1d01",
+ "419fb4a4 c07b9cec 40c8857f 40a11050 405d9458 3bbaf1be -> 42c8f591 4245501e 4286097c",
+ "c144fa22 40361282 40314a4e c11fba5e 3ff8ea0c 3e1dc394 -> 42f5cd82 c2515d3e 422557d4",
+ "c0200e50 3fe6238c 40c392c2 c191d837 bf8905e8 39664476 -> 42365e94 c1f0ce2e 42efc714",
+ "4156cf14 bf94f0f2 3b6013d9 c018ff58 c04a538a 3c674792 -> c2006136 c21ea50b 4079d4b4",
+ "41543148 40834d24 3e41f213 bfa80650 c080d6b3 3b9a068e -> c18b4593 c26b20aa 418ce978",
+ "c1101c5a 4028f1cc 3945f5e1 c145b8ae 3edc5600 3baabc62 -> 42de9b8f c211fd0c 3f9980da",
+ "412a6e78 4099125e 3a340199 c194334c 3f590968 3ebbb8dc -> c3455408 c29f2ad8 411ba86d",
+ "40426010 3fbe3f40 3bc560a1 4185ab78 3eeeaba0 3e93bc63 -> 424afc33 41d2000d 40069cf2",
+ "419bbbfa c00d36a4 3a613fe2 4134d2c4 c08b7a48 3fee8c24 -> 435c00c6 c2db923f 424818a0",
+ "4155b300 3f16a468 4083db02 3f96d400 403c56e0 4098fcd4 -> 417bcfb4 421ffe02 42d228e5",
+ "40fa9808 401006a8 3e8b93b9 400a6ce0 40983100 408fbea7 -> 41878088 42287272 426c6652",
+ "4052ce30 c0224ae6 39fd2660 4091bca0 c00e1ee5 3c41d53a -> 41700439 c196e7e8 40b68267",
+ "4180500a 403f35ac 3f7ca93f 40707900 40692824 3d4253a9 -> 42710f5e 428b508e 41991a47",
+ "c188540e 40846d2a 3bd7c0be 41944c6a be478be0 3f9d8526 -> c39df293 42a01184 41d8046a",
+ "c1618899 bd9de3c0 3ea19df8 c13f480d bfb6d760 41055f92 -> 43288464 41a87471 42fa381f",
+ "c04bd040 c0286c0a 3a5a370f c12bdf82 bfcb6538 3ffea0e4 -> 4208d60d 4205510e 417c3829",
+ "c197c35c c0990199 3e6d63d4 c03ec4b8 bfd2b934 3b4fb6ef -> 42622f3a 4235ee6e 41105371",
+ "400d8558 bfa2ccbc 38d52a7c 412e3910 407432b0 3b0b18bb -> 41c0a05b c0ad2f8c 409b9494",
+ "c18e54ee c0266b40 3e980a08 c08fac6e bee3eb20 40219768 -> 429fc29e 419cc205 425b6ffc",
+ "4038d4e8 4014b330 3adad9bc 416c36a8 bf6f70c0 3cd5c2b8 -> 422a8bbc 41fccdda 4015783b",
+ "c12c6322 bf9808cc 4032da04 c15e5aa1 c0442d9f 39284c52 -> 4315baff 42462159 424c2efa",
+ "c12c758c 3fd8ff2c 3c9f1f0f 418c84be 3f2e93e0 3fd0acc6 -> c33d536a 41b36a5f 41af06fe",
+ "4167cf34 3fbe1224 3d9fd1ef c18badc2 bf6b2208 39b529f5 -> c37cf5b0 c21cef5d 4033733f",
+ "414aa0fc bf9f8352 3de7bb55 c027bdb0 c0629e32 39ca1106 -> c204c529 c2264eba 40a3b10d",
+ "c1069f4e c0958eec 3f4e8c1b c0fb5d60 3fcbd684 3de28407 -> 42842f4c 41ba823a 4184d173",
+ "40937898 c05bbd62 3df47def c1469378 c0434e0c 40bcc0fa -> c264c872 41e4644c 4271daa4",
+ "c06401c0 bf791020 3a4ea7a3 41934d8e 3ed574f0 3a968b43 -> c2833214 c19b3190 3ed9fb69",
+ "4144ed80 c075b355 3e69fb0e 4161559c 3e82d4a0 3f8abac0 -> 432d5698 c24bb043 41b00bfa",
+ "c0fd74c6 3db21800 3b88e723 c1686e3b c08f3529 3915fb83 -> 42e61ef6 4208bb49 3ef08fcf",
+ "416e72e8 403d8c4a 3ac4d2fd 412e2138 406844ac 3a2702ea -> 4322310b 42aca306 412c82e0",
+ "c119c434 40889c92 38ec1099 415f4e14 bfe165a6 3c3b1d79 -> c30620cf 429902ae 40f5b274",
+ "c12eada6 3fdcc558 3c97f0c5 409f1e40 3fc349d8 38df4600 -> c25924fc c10148a8 40303808",
+ "41891330 406405e0 3fbca694 c081a9d6 3fa24628 3913cd82 -> c28adb37 40e924b6 4145c4bc",
+ "c00bc0d8 bf1fd3b0 3d0c85df 4197cbe8 c09f7a26 3a145ae2 -> c225bc20 bf76b6b0 407bd79d",
+ "c109e17f be5d5780 39adf822 4057ce10 bfea0cc4 3c215873 -> c1e876bb 41707492 3ef7cf9d",
+ "410c0e04 3fb1bcb0 3d4ccabd c19a147d 40005f50 3df2c9c7 -> c3289748 c112fa52 40a1d257",
+ "c13ee136 4092cfb8 3f69f891 c1197294 3fa00688 3febd301 -> 42e4d410 c26ba885 423f09ec",
+ "c0bbbb26 3fe36cf8 3ff44169 c0e7ffa6 c03a949b 3a7ae4ef -> 422a2158 408716ea 41c4b203",
+ "c141aa40 be85c150 3a384a20 c13c7b59 bfdddd26 3c5b5ecb -> 430e9657 41c075e0 3f20c76b",
+ "40c4d150 c0095c02 40875fda 416639d0 3f24be40 3fd82fe1 -> 42b10080 c1d76547 42ac44bb",
+ "c0f6952c 3fb6bdb0 3bc3ed30 c18e6747 4081c08e 38f5940d -> 43092a39 c262a194 40bd76e7",
+ "bfafde20 408327ac 3a1d6b93 c133e5c1 c041f3b4 3e6000e6 -> 41772c4d c227ad29 415a06f9",
+ "c127ea5c c0497da1 3f93e4b7 40c51f4c 3f9aeac4 3b88887c -> c2814be0 c20061a4 4146350c",
+ "c1039152 40950f2a 3b129379 41828e92 bf90c478 3fd2a7d3 -> c3063223 42aaa31b 41d414f3",
+ "c12d438c 3e0895c0 3b6e767b c176c24f bfad2344 3c432faf -> 4327026b 41497324 3ebe9acf",
+ "40f29014 bfca360e 3c19ab06 418eee6e 4090ec02 41026ede -> 43076dd5 40c352c8 42a439e7",
+ "bdb89100 c0010f06 3f39e274 415b2540 4061fbf0 3b4bf328 -> bf9dfee6 c1df80f7 419d1b83",
+ "c1930b62 40991dc0 3b1ee50b 3d659200 4095b782 3a05ab42 -> bf83dd0b c2ab74c1 41b34811",
+ "40906390 409fec80 3e56cce0 4081b074 3f272c88 3dc9647e -> 41924b63 41b99b53 40a69bb7",
+ "40418e00 bf80cf76 3af95e06 3ef6e880 405074fc 3c15a8fa -> 3fbaae3d 4115d80e 40549728",
+ "4100f9aa bfbe72ea 3d59c240 4119eb3e 3e9691b0 3ff0e7e0 -> 429b1776 c13f1587 41984a99",
+ "c110ec3a c005c736 3abe1706 41536368 c05bff36 3b868b5e -> c2ef55f4 406136b8 40e82bd9",
+ "40047f68 bef5b480 39bfeb6e 4196d18c 406b33e8 3c34806f -> 421c1e37 bfb82880 3fe66747",
+ "4029d8f8 4011d6e2 3d5aa36d c152c224 3c85f600 3bdaf014 -> c20bd4ca c1efc8dc 3f464e86",
+ "41208cb6 c083c818 3f43d016 413d5ea0 bfa50d48 3d6fd838 -> 42ed8675 c276b862 4181c92c",
+ "4110e358 409b6bcc 3cbd09ad c09984ca c065d46c 3d045fad -> c22dc60e c25f47a2 4190af69",
+ "41223b10 c0000202 3c902461 c047af20 c02e2e34 3e782e29 -> c1fd15c8 c1aad648 4107e26b",
+ "4182f258 4034ce60 3fd339ad c0caab96 c09023d0 39c13591 -> c2cf55fc c2b73e48 41f4f117",
+ "bf111280 3f8580cc 3d3aed62 415e5ed0 408ea082 39a1b8ec -> c0fc078b 413f84a9 40af94e7",
+ "415ddd68 3e9dde70 3fe28349 c14cb464 409caf44 3c83aded -> c33168c5 427fce12 42044995",
+ "c186f943 be64ada0 407e8c97 40e4d544 c07d7ff3 3a3acae6 -> c2f14ce2 42827628 4234620f",
+ "4160086c c0521dc2 3b6b8c26 408dda00 c03497f7 3d8ce691 -> 427846d5 c2584192 4127acef",
+ "4192fc7c c0639df8 3d0192bd 416be420 c018a6d5 3ec9ca12 -> 438770c1 c2c08420 418d71d6",
+ "3f5bd280 bf6875f8 39239165 40d13050 bff3206e 3f2e9607 -> 40b3a057 c0f22558 403b96d8",
+ "c1991250 4072848c 3926271f c0a04444 3eab0180 3de5f0cf -> 42bfa887 c1caf394 4075c80e",
+ "40c2f588 3f3bbdd0 3b6976f9 c19d7c8d bfc7f286 3f103fd9 -> c2efdedd c1bfa188 40a23a39",
+ "412476cc c02c85f1 3e7d1d10 40dd5e08 bdabc6c0 401cdd88 -> 428e36f7 c19c14b1 420974ad",
+ "414163d8 407001d8 3c0c37d8 41949738 407865d4 3f82057c -> 43607fea 42e921a9 41f6bf19",
+ "407a6420 4098fca6 3b11a05e c16c82eb 3fcb1ce8 3da38350 -> c267545a c280ec8b 410512c9",
+ "c0795430 bf5a2ab0 3a348c77 c15df988 3fc91e88 3aaebb68 -> 425830b5 40b6762c 3fad93d4",
+ "c16c6d62 be7d5740 3e1f22dc 4100ae18 4092b91e 3e2ae528 -> c2edaef3 c28b7c18 40b42b29",
+ "c11b698a 40907908 3f80d2e5 411fe870 c07892ad 3915ea56 -> c2c22751 42a5b1fe 41fc0a62",
+ "c1930863 405f0e24 4077cb85 c1591eae 40673450 3c7545f4 -> 43796776 c2e36179 429f01e9",
+ "c0993ed0 c08da988 410ff0ae c1274869 403144d8 3d74df05 -> 424846a4 42041481 43045392",
+ "c0cbe5be 3e5fdae0 406f94c7 41132370 3f86b7e4 408d52a7 -> c26a624b c096449c 42a8777d",
+ "40535d20 3f84e0a8 3d969da2 bfed6970 3ed8e320 38fd28bf -> c0c40444 bf06c6a6 3f1b9c27",
+ "c126abed c07f4a3e 4074baef 411adfc8 400497fa 409a4d34 -> c2c9aa3d c270c56a 430d1a79",
+ "c19fbe27 405eb098 40099633 c1277c78 c0833912 3f8fe14f -> 4351056d 4235d631 4294b8f7",
+ "40d07698 c025365f 3d6fddc8 4114d76e 402ea5e0 3dcc5f8b -> 427267fa c0c794fc 410a9a3e",
+ "c12a2334 407adb08 3e9eba85 c185726c bfb2be16 3c79d766 -> 433160ab c24a226e 4134dfc3",
+ "41131796 3e8b9830 3bb07050 416dc9e4 c054eed8 3d0dafed -> 4308a0d6 c1d4470a 3faa9a91",
+ "bfd85d80 3f5e71a0 3b5e7b62 418064be 4086c6a0 3f21cca5 -> c1d907ca 40da6fc5 40ab2460",
+ "3f3de580 3fb101a0 3bb88a2b c18eaa87 c027cc1a 408d59e2 -> c153a797 c1d4d8a2 4152699f",
+ "40f1b5d8 c07e7667 3c6ca313 c17d1f52 c08a8bee 3bd6fd10 -> c2eefe49 41f19402 418ca681",
+ "c09f5f3a 405fffdc 3fb6bc9a 4197843e c03389fb 3e36ef25 -> c2bca6fe 42a08500 422a8791",
+ "c0e8dcf0 c05bc716 3f016b63 bf4e4f20 c09c1be7 3a500519 -> 40bba9c2 421911e6 419d14e7",
+ "40677690 c06d4631 3e81972a c0b4e20e 40338f38 3d062279 -> c1a38bc1 41f8d392 414ca642",
+ "3e23a480 402771d2 3b837a8c 413bc27a c03706ea 39f6ee63 -> 3ff00af4 41f1f6b9 40f15889",
+ "c12032a6 c04cce27 3e3eff23 412c5174 bf877f8c 3aff7019 -> c2d7aa00 c1beecd2 40b3d77b"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_snoise(vec3, vec3, float)",
+ "tolerance": "ulp-bounded",
+ "check": "the arguments are (cx, cy, cz, ax, ay, az, radius, ...) and the result is the form (x0, a, e). Enclosure: for eps in {-1, -0.5, 0, 0.5, 1} and d in {0, +-ex, +-ey, +-ez, (+-1, +-1, +-1) / sqrt(3)} (15 directions), form the point p = c + axis eps + radius d in double and round it to float32; the device's own reference value at p must lie in [x0 + a eps - e, x0 + a eps + e] with no tolerance, so a device whose gradient error exceeds the allowance fails. Tightness: with L = 7.9640074 and, for each octave (one for af_snoise), R = |axis| + radius, B = L R + 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R), the width |a| + e must be at most B + 2^-16 (1 + B). Report the least slack of each side, absolutely and as a fraction of e; only the two bounds fail the check. The reference value is cultmath_snoise(p).",
+ "cases": [
+ "c2461d0c 41488940 c07e9320 bb68fabd be288e0f 3e232bc5 3ca64a9f -> beffc1bc 3e2be983 3fe385e0",
+ "c154200c 417938f0 41050be4 bde44cd9 bddb2245 3cefa790 3b3cd34c -> 3ee504ba 3cf9f4d3 3f39e2bf",
+ "c067faf0 c21c93b2 c1c94dfa bb35db00 3bdae5af 3acd2c25 3bdacdef -> bee953ce 3ca5297e 3d0af24f",
+ "c236ea4a 410362cc 415990ec 3d0b18b8 bd8f1cf1 3d9a37a6 3cf87170 -> 3de3c2dd 3d3e2c82 3f10c992",
+ "41d1f6dc bfdc3340 c01f20c0 3b9f7bd8 3b1c31c3 3b41665a 3c1cdc28 -> 3f41ec30 3c66bd58 3d1456ad",
+ "4191738c c1a2f3c2 c211c115 be007580 3cb352be 3ddaed92 3b42ecb4 -> bd614cfc be8b1bbd 3f4f4020",
+ "3f58f200 c22835ab 41acfdb0 3aa2ac08 bcd45342 3cd46062 3ad20095 -> 3f16b968 3d46a2fe 3d3d1b3e",
+ "c23e1102 c20a1325 42300caa 3dd9fbdc 3e906f25 3e1c9070 3bfbb52b -> bdd23a0d 00000000 40304b61",
+ "417f3760 c23a4512 c24726ba 3b6a246f bc701b24 bb364517 3e51e0fa -> 3d83ad16 bb88b1ff 3fc8a197",
+ "c01dbe40 421a002e 416d56d0 3a3436ce 3a1b036b ba653da9 3ca8bed4 -> 3def6ebd 3b1f6279 3d821064",
+ "41f68280 c07bd660 c1f9b8cf bc9f0747 bbb189f2 bd545910 3d9d7708 -> 3bc135aa 3db9a1d4 3f2c163a",
+ "40956248 c1211810 c15cd0bc 3c37df98 3c70c3ab 3c47e6e8 3da03b19 -> 3d884938 bb29a7d2 3edd21d0",
+ "40657ae0 41f62314 c1f905f5 398ab1f8 baa8afa5 3a0f968b 3baeab17 -> 3f2e43bd 3b20efbc 3c50670f",
+ "414e5270 421006ac c22be7f5 bc100185 3d2f3fe6 bcb9a388 3bb26407 -> 3df30361 3e6aabd0 3def1061",
+ "c23cd8ee c094c010 c21dae02 3b1742d1 bb465fce bb7ff518 3b7014cc -> 3f3487af bc0b7258 3c7ad7d2",
+ "c2457338 c19d12f9 4243f768 3b094bb0 3b0c5426 bae289aa 3de14cc3 -> bda277a3 ba9df30b 3f080f75",
+ "c1eda426 4232d426 bf842a20 3d6e9677 3ee29130 3ecb07d5 3d0e5d6e -> bd926e3d 00000000 40a109d0",
+ "420b8d12 42277864 c241d9fc bb8b87b9 bb7be31b bbfd72ef 3d55b614 -> 3c32f06c bbaf9848 3e6a8cab",
+ "c21949eb c2243ab9 406cc5c0 3a60f1e7 b99916ea 3b4a7e0e 3c5eadae -> be7426b6 bc2b1393 3d848f20",
+ "41f25fd8 423ff36a c210e38c bb1cee61 ba026a59 ba8666bb 3dd016ed -> be7865e2 bb927307 3ef941a3",
+ "418913f8 c194ae3b c0d6a1a0 bb3ee6e1 bbf513ce 3bfc3faa 3aad7ebf -> be80db84 3c1a9f75 3c1af026",
+ "4005b130 40604800 c14d245c be3b4149 3c9bd311 3e1a08e0 3d3aa021 -> bd92cb87 00000000 4010518c",
+ "c23fa949 c169e48c c23503f9 bd2635e4 3e025995 bdc43cd5 3dcdd83c -> be833861 00000000 4007176e",
+ "c23898cc c22c052e c1fde2c4 3cd4e3c5 3c60fc4c bc5a14f8 3c46a1ca -> bcd1eb00 bb51e190 3da1b49f",
+ "402b9f10 c1b6589a 41e97638 3ab5bdc8 3a78c21b ba617814 3e277459 -> bcc51abc bac7aac2 3f86ad0b",
+ "c13f5754 bf4f8a00 419a70d4 baaf2e19 bac6af50 ba1a8d15 3ba6785a -> bdee80f9 3b174562 3c4c24ed",
+ "c20b69fe 40164180 c1d86af0 bd53cc85 3d5c6035 bd5f4972 3d9b9f19 -> 3e8bdc90 3c6819c0 3f759278",
+ "c203634e 41991848 c0dfc318 bbe00bc5 bbd99f71 bbae32ca 3e3c248c -> bec70efe 00000000 3fc67e64",
+ "c1e6994a 423c2d46 c17476dc 3db0b4a3 3db9803d 3d5b9834 3b6cc85b -> bdc7a7d3 bdec47b1 3f0e6294",
+ "c2108c9f c1d9e95f c1140ac0 bdb7e96d be379935 3d8008c0 3a8658d1 -> be99a951 3dff0554 3fa006a0",
+ "41c8c984 42287b38 c0d8eff0 ba368f94 ba8820c8 bbf13e8b 3e9ed55e -> 3e92e363 00000000 4021f862",
+ "4216f750 c221e5ae 421de69e baa07b01 3b7c486a 3b0e6264 3ba00190 -> 3db84cc3 3bbd76bc 3ca4fb07",
+ "c1a6912a 420dc904 4212ab1c 3a4e0501 b82b28d8 384e8cd9 3c385796 -> 3d097d77 3a9615eb 3d0d5552",
+ "4213545e c23edb34 41cc0434 bae8753f 3968304e ba027252 3aff73f0 -> be86120e 3a6be24a 3bba7373",
+ "c2383c25 c0ec7700 411ff5ec 3aa828e8 3b24cf8d ba46ed11 3e046e28 -> bde900db baf3e614 3f277255",
+ "423bab08 c0f20580 423482c8 3d2ffeee bc57d0c8 3d1a7ad1 3bb46f25 -> bd5314ba bdf70cd4 3e0ac6ab",
+ "400d15b0 c20b09c3 40cfe558 bc0d2c21 3a74e62b bbab27ff 3ba5b7c6 -> 3e637557 bca6a5f5 3cb48687",
+ "c110db14 c236d9e8 c095c2e8 3ba5c372 3c1c1005 3bd6db0b 3c073f50 -> 3e1551c0 bb4782d7 3cb101e8",
+ "419054a0 41e5ef50 c1d94ebe be3a6cd1 3c1df6c1 3d43e7fc 3c55d7c3 -> 3eb77933 3eb99f10 3f95b1a6",
+ "c0485400 c2262c96 c20c00f0 39d1b4bc 3b702cd2 396c2885 3ca2e941 -> 3e8ccea5 3b98e540 3da9afb8",
+ "c1efaf29 bff800c0 4170aaf0 3aa313a4 3aa82145 3a8d4fe6 3cbf194c -> 3e95d663 3b48aa42 3d89c9a3",
+ "c21c36ef c18096a4 41e2e49c bc0b52cf 3d54c0d0 bd373713 3b1cd69d -> 3f3b5fa3 3dab6e35 3e16ff64",
+ "419e6c00 4132cf0c 423d9cc8 ba92f360 3a9d0bc0 bad31b43 3a8b1925 -> 3db757fd 3b8e70ae 3b78b48b",
+ "4110c100 c20b4c54 42376d04 b9f8081f baec2544 3a6a9dfd 3cfda902 -> 3e817738 bb3522b2 3dd7d4a7",
+ "4005daa0 423ce684 c1d85827 bb0ccf78 3a9f9603 ba69a2b5 3d980c0e -> bd4c51d8 3b18b086 3eccecc5",
+ "42170b4a 41b165f0 420b6f2c 3e135d33 3e848883 3e9d0dbb 3cc6b565 -> bd905ee4 00000000 4065c012",
+ "423ed542 c24425d0 40cfc8e8 3e7a403e bd177d2e bde887ad 3c044d25 -> be19ba00 00000000 400ecfc5",
+ "c03ce630 41615f38 c09466b0 be1f0994 3dc8791b bdfe0dcf 3ab967cc -> befcf22b be8d1524 3fb2dbdf",
+ "413c1438 c1d6d80f c21442ab 3bf8037d 3c62a5d2 3c7d3979 3a9095ad -> bdc2ea43 3b52acb8 3c893867",
+ "c1cbdf45 c1af0a8f c1ee1ef0 bc70779e bc4e0a08 bbd9d7c5 3d8b5886 -> be3d4f50 3d1698b9 3ecb0246",
+ "c2066e8c c0adde88 c211a60f b9701cbd 3bc4611e 3b61488a 3ad6158e -> 3ebb0280 bc58369a 3c07c3de",
+ "41708008 421d6fa4 41b2cfec bc7b6783 3b2852a4 3c17c23f 3ad88e55 -> 3ee3d64a bc6ae034 3c858173",
+ "411cb1c0 41ea3e18 c19a0bee 3c4bd09f 3ac871cb 3c4ef413 3ac2a3b4 -> 3cd8c2c2 b8980738 3c43b2bb",
+ "c234ef43 409d4800 4191aa18 bcb41dbf 3d051048 bc78d941 3c33d094 -> be476ac7 bb7e1eb8 3de6ac32",
+ "c15fbc08 41dbdbd0 417b9a00 3c4642cc 3c9a5a7e 3ba520ce 3e2ad83c -> bdb4b597 3ce3e183 3f9dcef9",
+ "40c81df8 c233d3b8 41f24084 bde0da0c bcdb392b 3dd043b9 3d9eb6de -> 3ef89b09 00000000 3fea113a",
+ "413bcf8c c2175d9b 4207bb36 3b11a2de 3b148d68 3b4fec6d 3d4cc1a8 -> 3e123c18 3a7b9697 3e1d68df",
+ "417e6560 c22b16bd c18b9796 be88a602 be98b4fb 3e6f36ca 3def151e -> bdca3873 00000000 4093e0e0",
+ "40eb0298 c18174c0 c2010d5f 3c55a985 bc66ec78 bb30973d 3e469b20 -> 3f09d9f0 00000000 3fd98c3f",
+ "c1db627e bfc819e0 422df468 3d33cb1b 3db00301 3d90d868 3d4547ec -> bd12dc7b 3e7f3350 3f6ea0fe",
+ "41d19738 4240f01e 4241df82 baf84eb6 badc07dc 39eb1f8b 3d13e7c9 -> bea963c4 3b5fa641 3e0c4daf",
+ "4217564e c23cc902 4229bdb2 bbbea7d3 3c224243 3c862003 3cb28ccb -> 3e36edd0 bcf152a1 3daedb1b",
+ "c1e71165 c23920e4 c1c0a3f0 bdcea1e3 bd882118 3dfe865a 3ce6b4f4 -> 3e42159b bea074eb 3f9a5183",
+ "41a16ef0 4244d05c 4246e72a 3b8d6f19 bb882ac8 3ba14d85 3da3f6ae -> bd288bc2 bcb31ff7 3f0772c3",
+ "c1f11599 41a1d298 c200f4c8 baf5db3f 3a822815 3a819e1d 3c9e49b2 -> 3f220bef bb30afc2 3d9e33ad",
+ "41b8710c 4120c12c 40f17428 be13f2f3 3e0e7319 bd05f369 3d28fd3d -> be9d7ddd bcea9e04 3fe83537",
+ "41daf308 c0c29420 4004a140 3cefc569 bd931cfe bc986562 3c6b5814 -> bf29921f 3e2d4608 3e95a55d",
+ "c203afdd c0a724c0 c105f72c ba921d35 ba07a165 3a26e424 3dad29ee -> bd9f1336 bb1138e6 3edfe07e",
+ "c213b6d3 c1e07e58 c12fecfc bc131ab1 3c6c6758 bc7d84fa 3cac4cbc -> 3f407e64 bd12855c 3dccbf3e",
+ "c1927cc8 41e24e34 c2178187 3ceb5583 3d4df474 bc5987a3 3e65b2ea -> 3e4576e1 00000000 4010aa24",
+ "40df9728 c121b880 3ffb9120 3b7009ee bbf8177a bc4c53d6 3b44b6c6 -> 3ebc6a0f bcdc2448 3c821a3f",
+ "c18b1cd2 41c7305c 4237b4ea bca4fe75 3c8d3b75 bc510041 3c59f049 -> bcbe0cea bd4f5060 3d998771",
+ "4214c838 4210ae70 41b7898c bd234dec 3e0a0c97 be7374e4 3b59a2af -> bf25902b 00000000 400e8774",
+ "c23dbc19 c23bb1ed c1437c1c 3e6dda75 3e084e79 3dcab699 3b8025ea -> 3b4d9c60 00000000 40138924",
+ "c22d3698 4091dda8 bfd3f3a0 3d3c7512 bce72037 bd898f01 3ea41de4 -> 3f30225c 00000000 404f54c1",
+ "c1e89b2e c1e566c7 c1253604 3c9b290b 3d326f0c bd495713 3d68e16b -> 3eb863f7 bd985cf5 3f14cd3b",
+ "c115b664 41a3f9f8 41dbb560 be15aad9 bcf0e501 bd178a26 3e65849c -> beada6ca 00000000 4040934a",
+ "c1c7aa59 c18ab8ae c13a5c84 3cf0a949 bd14dd77 bca5d747 3d271b55 -> be27a594 3d205051 3eb47623",
+ "c228b0ce 41bfeda0 40d7c418 bd9185de 3d2169ba 3cdfb897 3cfe60ea -> beb264a0 3e7064f2 3f064f09",
+ "41e974fc 41f10dac 41b5fdb4 bad5534b b9e22fe0 3a1aec7b 3b97bab0 -> be569e9f ba58ebe8 3bc2b9f3",
+ "420a4b28 41b65324 3f0d3c40 3b493b4a 3af2d71e 3b5bfd80 3d44df10 -> bd845d10 bc978a5f 3e934ad3",
+ "c2199e96 41349b78 c09e53c8 3c830a94 bacff359 bc6e8e39 3b02b5dc -> bd9754bf bd62eaf6 3cb2724f",
+ "422ed30e 41f02b68 41441b78 be0d9b6b bd120669 bc841a38 3dc0ab09 -> 3e984c6f 00000000 3ff28118",
+ "c226aa00 c1de6476 c21e3ee0 3bc211c2 bc059799 3af3b56d 3e169144 -> 3e1f1425 00000000 3fa074a5",
+ "41cbed00 c211335e 41d5e5d4 39b17b3d bac8d1a3 3a079327 3bd89512 -> bee348ed ba330dee 3cfacfbd",
+ "41c20bf8 4231cfd6 41656fe0 bc9c8205 bcc52336 3c04f6fd 3c0388ff -> 3ebddd3b 3dfa1cea 3dafff84",
+ "419e6654 413a4e10 c1a766e8 3c72014e 3c0d9cf8 bcad2490 3c5f22a0 -> beb758d4 bbc47048 3d8de246",
+ "c1bec7ff 41dbadc8 c21b1465 3d04c245 3c6f4f69 3d9e8aaf 3e967551 -> be81cf31 00000000 4041411a",
+ "c2360bc5 416c6ec8 41aa80b0 3d5e9dbd be11072b 3bacbd99 3e52530a -> 3df7e87c 00000000 40361b13",
+ "c2088cf8 c190f5ea c2107112 3b42cbb9 3b888ab3 3882f305 3ea5cc71 -> bee83861 00000000 4027b6ca",
+ "41284d20 41d77904 41b22688 3ac8d5db bad43629 3ae95cd7 3ac3f043 -> 3c063524 3af3b259 3b100eac",
+ "c21f2073 c1744ad0 420624b2 3e1b19f9 3e075ce7 3d31140c 3b37d223 -> bd0bd4b8 bcdb1738 3f9c30cb",
+ "c238b6f6 41b76a7c 4024eb80 bb8d2a5a 3cbc84eb 3c2cac28 3d96da5b -> bd426809 bbd01c9c 3f088fa5",
+ "c220c5af c0d27478 c17a076c 3b1cab54 3c4c2c9c 3bd2361d 3c1f3eb8 -> becea382 bd0fba39 3d455394",
+ "c1b910af c1fdf482 c214e6f1 3e44115f 3e29976b be89a146 3ee18b90 -> bf0ee728 00000000 40ce666b",
+ "418817f8 416d8870 419d4c80 bbb4cdca 3b5c320a 3bd56cef 3b9b02d9 -> 3eed274f bc0c01f8 3ca60c40",
+ "41941eec 423d3358 c1d8d373 b9bd960e 3a9c4163 b7fa1b60 3e08ab34 -> beb34fd1 3a41f8b3 3f540746",
+ "c2168529 c23b8cee c2472bf5 3c0cf5dd ba9192d3 3a077900 3c032136 -> 3e3d9be1 bb33d8d1 3cdae9c4",
+ "41a7a27c c042cb10 409e1cb8 3d982804 3d7c44e4 bd4bc004 3b8aa8de -> bf11f9e3 bd753a06 3eba4a33",
+ "41b4f950 4094dfa0 4222d724 bdd54ab9 bd5d5669 3bb8aaa5 3c424679 -> 3ee01606 bd9fd59b 3f01490b",
+ "40931578 c2227e8e 4200759e 3b38a853 3bca6587 3d13fe74 3c079d08 -> bd7eae4f 3cd9cf37 3d9e5efb",
+ "419a9f5c c17f1628 41dda9cc 3dcf8831 3c0f179d bda599c2 3b617f36 -> 3df095f7 3e4575be 3f015df7",
+ "c211f2d0 c15cae20 415411b4 bd601a65 bd7f1bfd bb9ee6fa 3ebebc1f -> be79e8e7 00000000 40683ee6",
+ "4180ddd0 4246c5ac c18a90a8 be23d443 3d871d1d 3d631891 3e27c2dc -> 3f21be68 00000000 40302d37",
+ "3f882560 4126dec0 422c5a04 3c74695d 3d30f3bd 3cf0ba21 3b0e5c10 -> beaefc97 3e032fcf 3dc36630",
+ "c02822d0 c1e86fed c2230915 3c66bed2 b9b12103 bb11f07e 3b633f78 -> bf0129cc bc194b5e 3ca002bd",
+ "c1a8a6fd 41a6ab94 417b0200 3d1d3dfe 3d92a53f bd68b9f0 3c80fb36 -> bedd5b69 be0d6581 3ee2b2df",
+ "41478814 42138c00 4226e714 bc662621 bc9bc27f bc2cbc93 3efa51a7 -> be16f938 00000000 408338a8",
+ "418bd498 4236c60e c1963a36 3a2d1955 3a6a96bf 39b0573a 3b636f23 -> bd336746 3a14a726 3bb40c40",
+ "40d3d170 3f46ba80 c1d9c5af beaeaa31 bea80cff 3eb10a19 3b3ef3d5 -> befb4c94 00000000 409628bc",
+ "40dccbd0 c2154916 405b3710 bbd334e6 3bbac905 bba13c2d 3d96f1ed -> 3d939d7b bc1c6444 3e8f5269",
+ "c1642930 bfa01020 c246a026 bdfe3fe0 bd819d25 3dc161af 3bd55366 -> 3d320f5e 3edf7889 3f5fcaa0",
+ "421c7172 c2217063 41d47108 bea4aba1 be8a8b65 3dd55d3e 3d77ee79 -> 3e9b2c99 00000000 407ba151",
+ "c2081690 c08a6df0 c1f5806c 3a03e975 ba8cb461 b9c137b1 3d268bbd -> 3e44952a 391d7cda 3dd524ba",
+ "4214f352 41c43118 423d1856 3a23b83c bb12a342 3b06fdd0 3df31b6a -> bf25c2dc bbdebc64 3f4b35ad",
+ "41f63d94 4140e298 4208f704 3a00e75b 3a88f374 baa2c48d 3be40608 -> 3f088596 3b683da2 3cca3fed",
+ "416185d8 422a94e0 c233df1c be0e36ea 3e9568e2 3e94ab29 3c0864ad -> 3de8a823 00000000 4061bf89",
+ "400d8070 4215b484 c20a9a44 3c83a0fe 3d15e402 bcf67ffe 3ab505b3 -> 3f108c97 be2bd979 3da53210",
+ "c23249c7 c1141638 422395b2 bb1be944 3b280fd0 3ae8c8b6 3e7cb1cb -> be504ab6 00000000 3fffaa3a",
+ "c20fafd1 4246e468 c1f727d0 bbedf519 b952789a bcf26f18 3c3c1330 -> bef6d5d0 bdc377eb 3db6e4a3",
+ "c1b4883e 42186e12 400eb340 bcfa19e0 3b1eee2a bcaac181 3e6b8f66 -> 3ec09b54 00000000 40082beb",
+ "41c80f04 4152f960 412e8478 3da64a41 bcf238ad bdd27caf 3e299e4e -> 3ea43568 00000000 4018e694",
+ "400082a0 41e861e8 c23293d8 3b36740e 3b50c28d bb6f08f1 3e8e71a8 -> bdb53598 00000000 4010b211",
+ "c1bd629b c2064924 41da62e4 3b51ee3e ba277008 3b9bd6f3 3a995e48 -> bf1ea68d 3bfaba5b 3baf8aec",
+ "4208034e 41d0bf40 c1988c87 bc52c6bb bcb9fe69 3dd6c040 3ce3bc45 -> bf2b0b66 3d9e04d5 3f13cfb3",
+ "c22a26dc c23a4fd1 400f7cd0 bd2d8a20 3d398e2c bd585660 3df3d9a2 -> 3e7efdba 3d4fd63a 3fa4d85c",
+ "4230e6b4 c1516060 c2398356 bb966b0b 3cd17747 3b35f247 3c1de448 -> beafa1e5 bcd6807c 3d6c4fc1",
+ "420c2c7c 413b283c c11da73c 3a635301 bac7bc3d bac72621 3be2d489 -> 3e0647b4 bae522ee 3c66febb",
+ "418d59a4 4106166c 42298a48 bac96baa ba7f6a72 ba027edc 3add6d83 -> bf2aadff bbaa6035 3bec9095",
+ "424579a8 3fefb240 c20e85dc bd1ab186 bd237e99 3dbfa61e 3c1d71d5 -> 3bd36372 be348758 3ed5365e",
+ "c214117d c24654ed c18d0e04 bb419bc4 bb8b46a3 3b230d3d 3a9845af -> bd5c0811 3bd8ca8b 3bc7bde4",
+ "c1dab1b1 4231f4ec 4240bbd8 be3836c6 3da2e882 3de41e35 3a898647 -> 3e708668 00000000 3fe7a1b2",
+ "423a6c60 c1e706fe 423d24f6 3ce37bfc 3cd45875 3c45460b 3db383ae -> 3ebffccb bdb84e88 3f3d66d0",
+ "c243ace1 4234c018 41227774 3ddd3038 3e070574 3e992165 3c979210 -> be931683 00000000 4038f2fa",
+ "4207481a c238ffec 42386962 3d492c41 3cd841e1 3da8f812 3beac839 -> 3f3f9277 be2af61a 3eac169c",
+ "c247458f 421fe4e6 42119ae6 ba8d4252 384c54f6 baf5460f 3bc40fbb -> 3ca4795e bb59ec3f 3caaf64e",
+ "41b84a60 c2119d62 420f3114 ba0ff365 bacf0af2 ba2ee129 3b505186 -> 3e96a23c 3a0b9b4c 3c46d924",
+ "c1a19673 41269ea8 c0eaca98 3c0b959d 3baa142b bba00380 3ccb0a9f -> 3efe1c98 3ca68f7b 3dc5e9c2",
+ "423b2f60 3f9fe560 c244a2c0 3e76612b bee455d4 be6ce64a 3c03c5d5 -> 3e9ed054 00000000 40900abb",
+ "c19dde82 4179c890 4082f928 bab05f88 399466d7 b88f3f89 3cb65ef8 -> bd169103 3b03b723 3daf4df0",
+ "4220b8f0 c194f8c6 c1f4a4d1 3ca1e3c2 3c8a2995 bcc9b013 3d2d15b8 -> bf0976b4 3cc21604 3e93afcb",
+ "416e6110 41dc0254 c0b24d40 bab827f4 b95238e2 39913f5f 3c0b6863 -> 3f0a34c8 3ad81f90 3cdb38ed",
+ "40991a58 c173c4f0 c20c1439 3a2059c9 bda96ffe 3c0209d7 3d90302b -> beab6ba4 bc400612 3f4fbeb6",
+ "421493b6 4010eba0 42157204 3d2b8798 bd249858 bdad1cd7 3da8c766 -> bcdc4ac9 bdbe0608 3fa65fba",
+ "c215d020 422b0300 409cb420 ba98edb8 3c241776 3baa9c33 3b397237 -> bdf859de bc270ac6 3c7605d7",
+ "c09b9548 c11609e8 c1738bbc 3dad4868 be9f6923 be9cf21c 3e43a829 -> bede6957 00000000 40a22051",
+ "c220e48c c1f2c5d7 403261d0 bc3ec6a0 3d4260b1 3dc0859e 3e481c1c -> ba9fb3cd 00000000 4019a648",
+ "41d8bec8 3f7d6a80 4183dae8 3bd94245 bb425991 3bcf1cb5 3c047989 -> 3ed37c3c 3a120bd0 3cc26301",
+ "418708b4 41bbb970 c2428eec 3b95876e bb8d48fc 3b8b6b24 3dc23a4d -> 3e71a554 bb5f0ea8 3ef79e85",
+ "4192d928 4240ff34 c1b265f4 3a450673 398be58c bac81f1b 3dd39944 -> bebc9c1c bc0132f9 3f4e5986",
+ "c12dc124 c23c826d 4176f508 3c4f2603 bbb71e25 bc267653 3c28d02a -> 3edacc8d 3cad9768 3d6bf71d",
+ "422cb184 41a05ed4 418af244 be8613cf bdfe4619 be477460 3b1ed346 -> 3eacc7d9 00000000 40334330",
+ "bdb1f200 c2435ccc c19f1efb be2e6acd 3e1f5f60 3e43f3c4 3ee85d00 -> 3f0db625 00000000 40c0137b",
+ "c193b465 41ec8688 c2348ff2 ba6ea8e2 3c5ea012 bc475611 3b6062e2 -> bea7f541 bd2ccddf 3cd2a99e",
+ "c0e85ac0 422787b0 422f4b80 3da8b635 bd478f2d 3cdfb604 3bccbf0d -> 3f07a4ce bebd0546 3eb14733",
+ "c068d8a0 415d7a88 c17844b8 b9e59311 3b4ccaaf 3a1bdd52 3c0f8f9c -> be8e5e5e 3bb7c696 3cbc4d67",
+ "41c1c6cc c2122734 411cb694 bd0bb139 bd2e476d 3ca448d5 3ce670aa -> 3dd7ce20 3bd6aadd 3e835272",
+ "c222f113 41883ff0 c1fd734f be279492 3e973366 3ec0f228 3aa0ef47 -> 3f07533a 00000000 40814961",
+ "40b7e8a8 c01b6e50 40260770 ba6632fc baaf414e b8d98f86 3ae633cd -> 3e31ed05 b9981e00 3b82abcf",
+ "c07de5e0 c24573a7 c11a6110 39c3daab 3c0d9e31 3adad382 3c364a94 -> 3e25418a bbd8e6fc 3ca6fdf2",
+ "c1e49928 419f94e4 41ab1988 bb566b12 ba5b4115 3be54c59 3b74dab1 -> 3d060a92 38702640 3c434822",
+ "c1ac4267 c11d9628 41f48890 be7fbf54 3d66ec76 3eda7b6b 3d67176e -> bb846395 00000000 408d3918",
+ "41bd3934 c1968bc2 41716528 bda159cb bdf7a5bc 3eba3768 3c454cc7 -> bea90450 00000000 404d9de3",
+ "416b01a8 3f3c3dc0 c1d52023 3b54f734 bb67ae0b bba189ef 3c1e5ec7 -> 3e745d03 bc5b6615 3cf8b660",
+ "c215784e 41ec8568 41dc0330 bd202111 3bcb07f1 3cba70d8 3b0093c9 -> beb086c9 3df66766 3d96a7df",
+ "409ebf80 c194dac6 4232ec82 3d102c57 3b584f9a 3eb55e60 3e88624e -> bedc109f 00000000 409ea23c",
+ "c23927b0 41cbdeb8 41bd8348 bb3df507 3a0f0828 3b5a04eb 3e5d7cb9 -> 3eec0e81 3b5e0630 3fd847aa",
+ "41c540a0 c1951c17 41996e60 bda1b354 3d368ef1 bce30019 3b0d9fb0 -> 3c80e5b9 3d644aac 3e889983",
+ "c1489ae4 c0bd9300 420f3432 3c07fc7a bb948996 3ab478e7 3b407c1b -> 3d787853 bbb67f21 3c461e62",
+ "40fea4b8 4087e7c0 c1087014 b9b1598e 3acf89fe 3aa4da57 3b1fe7f1 -> 3a970728 bb2b91e1 3b80bc8c",
+ "41636128 c183ca50 c1d94b9c b963b0c9 3a75c9ad ba1e69f1 3cf522e1 -> be8608d9 bae9b985 3da870a6",
+ "41f80184 422412b8 4217c560 3dcb6925 3df04fe5 3dd72d76 3e80b1e6 -> 3efdfdde 00000000 405f16c5",
+ "422583d6 4201585c 41401ef0 3a0a0e77 b974d35a bab884ed 3d99025b -> 3f518b0d bb8c0d0a 3ec176ee",
+ "c1ea3768 40cb7bc0 413d8494 bc983448 3cb4a4e5 bb077615 3e09ac4b -> 3e6758ea 3c0b3296 3f86967e",
+ "c0a12468 409a9a10 c20b7a16 bd042127 bd98f070 3dc313ab 3cf3bf9d -> be1397ec be159edf 3f3c3e42",
+ "c20aea0f c196ee48 413f822c bc8a0c99 3df84873 bdbd184a 3d5bfcb1 -> 3e3e8a0c 3e6fc26d 3fad88da",
+ "416f45e8 4024ab60 c20254c2 bc41bc5a 3ca0a608 b912e455 3b6cb69f -> bcb75721 bba9ac1b 3cbebc12",
+ "c1dcde97 405d03d0 420beb6a bdf95a09 3dda683b bd4ba50f 3e94c781 -> bdacd2ad 00000000 406a7469",
+ "c0a82100 c22391cf c181c02c 3b8c77a9 bbee11e2 ba28fafe 3d0e4a28 -> beb07d40 3c01300d 3e0e9ad4",
+ "c216b2c6 c22a4617 423120be 3ba529a1 bb8acf04 bb8d2ed1 3c83f9e7 -> 3f10580c 3a753e68 3d708e36",
+ "c1be9eed 423f13e4 4219f088 3cc2c84d 3d274f82 bbad8d0a 3d8d721b -> 3da46a90 bdb84453 3f17cb72",
+ "c233e861 4231e500 417a1520 bb686b9a 3e38ad4a bdb2f14b 3c43d66a -> 3d9b99b7 3df1ba5c 3fa3b839",
+ "422bd5e6 41a5e550 c0e21d20 bacea02d 3c1f3918 3beaf795 3d56b130 -> bdcc2910 bc09d068 3e9577f0",
+ "c22c6a16 412599e0 c08e6c68 3b5c0ef1 bb630f15 ba93b3f7 3ef0300f -> 3eb39ea9 00000000 4071ac24",
+ "c19c617d c11ba4b8 411da408 3b4d6b75 3b07199b bb2d549f 3d08122a -> bd87e2f3 bb54e136 3dbc8d0b",
+ "41616198 417a9120 c1b5af49 bd5dd42d 3cb680e2 be233b5d 3bbed10f -> 3dafc5b0 3e5340f8 3f5fd0eb",
+ "41bf2ccc 408c03c0 c118d9dc 3a9d0c25 3ab7d2d5 baf48cd0 3bbe5476 -> 3c7c10a2 bb25a5d9 3c27e9ca",
+ "c21637f6 c1c996e2 40e0be00 b99e2351 baad5d5d 3ac4926b 3e7cf616 -> bdf16ec9 00000000 3ffdf7f7",
+ "40acd768 41858cf8 411513ec ba6e2f3c bab6f428 38def2c1 3b51a499 -> bdf9cd2c 3b25ab3b 3c35e4df",
+ "3fed8c80 421257a8 41b984c8 3d44faee bdea39fc bd521db6 3cc30896 -> 3da093e7 bba91a30 3f3a72d5",
+ "40275560 c2032930 401f1160 3b443b4e bb24a0c5 bb6ec9c8 3c8423ea -> be4f0b62 bbe4885c 3d3a6e93",
+ "c14337f8 c1939123 c21cb19d bcfeae16 bd2791a6 bd0dd7c9 3c8a3000 -> 3c3f0b74 bdbac0a2 3e5297ec",
+ "41f0cf74 c1354c3c c1a8fd07 3d8abeaa 3d90f579 bd886028 3d560868 -> 3e6d9f0e be96773c 3f761d73",
+ "c2429aaa c1e20e23 410fdf20 be83e19b be29abf1 3d593a9d 3b051f85 -> 3e7adf3c 00000000 401f83df",
+ "423b08d2 c22fdd9a 41162f4c 3ad07900 3a3e4eb4 bb70eb25 3bb18299 -> be100548 ba56f4bf 3c0df863",
+ "bfdc5860 c20da416 41aa15a4 3e9ff348 3e847c72 be9d0338 3c863215 -> 3f258785 00000000 4085cab1",
+ "41b8af54 c1b20f6c 4239e3c8 3b5358e6 3aad6b92 3a27c9ea 3cea46ea -> be00c12a 391bb04e 3dd34a5d",
+ "c213fc40 421b67c6 c1b94d77 3c3753d9 bc734322 bc29be17 3b0953bf -> be94b48e bc687abc 3cc8e7b1",
+ "41beb8ec 4245b5ca 41751f10 b8d2e890 3ac71c2b 3a9a0dc9 3b869f0f -> bee54054 bb4559ca 3c06fa2c",
+ "c1bff79c c241338a c1eaa6fd bd976991 be00a1bd 3d3e5f52 3afa3b20 -> 3ec9623d 3eb4baf6 3f2db788",
+ "c1edd443 c20fef81 c1e93388 bda413e1 bdc10586 bd2bce42 3c2a5736 -> 3e2b7586 3e08df3d 3f11f12f",
+ "3fd11400 c2323537 c21575d8 bd42e357 3ca941c6 3c9f1605 3b8fe28d -> 3f120a03 3e2d271c 3decddd1",
+ "420196a6 4115c874 c1fa169e b9ffb342 3a534341 3a791457 3e4ccfa4 -> bea107e3 00000000 3fcd56cc",
+ "bfc69300 41bdf404 c2305a89 bc978c7a 3d12abae bd19b81f 3a8ec908 -> be215327 bcc9ff7c 3db93967",
+ "c1cac5a9 c2064184 c1807842 bceb3bfa bad30653 3ca4baae 3ca260cb -> bd81d10b bc8adbaa 3dcefc93",
+ "41232c90 c1b2be18 41190a14 3be1b75b bc56c78d 3c3cc2ac 3d888808 -> 3e3391a5 3cfa8d08 3eb671ff",
+ "c0c7d398 423b7a9e 42466902 3d71a61c 3c9fe543 3d43edae 3bd38aad -> 3f3fa311 3d513dae 3e5b0105",
+ "c205dd82 c165fd64 c15a7f94 bc9d431f 3c43ee41 3d008ff8 3e0d1ebf -> 3edb1868 00000000 3fb3ff04",
+ "41e76678 c21af7ae 40298460 baa08ad4 bb14defb babbe422 3c1052f2 -> bda13306 bae883be 3d0abea3",
+ "41d71ddc 41a59318 c12308e8 be2e8b0e 3d44c4b0 beb4f67b 3c9323b1 -> 3f541e72 00000000 4052b0d0",
+ "41fc69d4 c13a3ee4 c1ba481e 3bc5e457 3b13065e bc3429de 3d2fc02b -> 3d845c36 3c8761ba 3e1857d2",
+ "c192b304 c2383a15 c1351380 bd5abf9d bd0260ec bcf566fa 3e96b51f -> be68728a 00000000 40394068",
+ "c1aca0b8 41f2a800 4151ed0c ba37ca9c 3cf58f8d bbf35092 3c51f94b -> 3e261a96 bbe7f2e2 3daca82f",
+ "41d59bac 4169b068 4224a870 bb056f3e 3b3fab2d 3b805980 3d36cc22 -> be688573 3b954814 3e315418",
+ "c1c2fa04 421f8c22 41c10d30 bccf2c4d 3cc7f122 be0dce5a 3b69c5ef -> 3e65af67 3e6ee93a 3f1b961e",
+ "c23cec4c 4228bccc 4201bfb4 3a843f80 39230961 baf55fa1 3cb88ca1 -> be0c2037 3aa4aacd 3d2c11d7",
+ "c0eeadf8 bfd086c0 419c6464 3c9ee37f baee8a88 3cb0e6de 3aa284bc -> 3ec1b1fa bc674aa4 3d011f29",
+ "4235463a 420ebfae 416db430 3a16fb15 3a9e5944 b9f2cea5 3c853ade -> 3e87b5c2 3a5e56fb 3d094aca",
+ "c23562a4 41dcb048 c0f3f440 394fccc2 b983d1ce b83d273d 3da67eb3 -> bec8ea51 b8eace08 3ef5b8a6",
+ "41bf2d28 c0eabe50 41332f9c 3d02aa9b bc9d8ffc 3c9a72d1 3b96a3c1 -> bf03530c 3de42ee1 3d99af11",
+ "c1155cb0 c10efb44 41ed32d8 bd974378 bb20a400 3d2d801d 3e105d68 -> 3e602e32 3d040628 3fc2e275",
+ "422b1754 41a5612c 4210d558 3ce93242 3d035bd4 3b094e3f 3b367a35 -> 3dbc19f1 3d4905f8 3d85dc83",
+ "40c329e0 c146c284 c2085825 be31dc53 be50e555 3e51d88d 3ec706c6 -> 3db6cb49 00000000 40b90cc9",
+ "4243e704 424338fc 41d3d5a0 3c7a0bd5 bb903808 bc9776d8 3dbdbc37 -> 3d0c398b 3c98e2a2 3f02458b",
+ "c2252e6a c11ae1f0 418c3858 bb91353c 3a870507 bb1604d9 3d030631 -> be2fee50 bbfb1b78 3dda87f1",
+ "c224c69d 414c721c c1acd3aa 3d0b979b 3e10232b 3dbb05ae 3de1f18d -> be1503ea 00000000 400f8b2d",
+ "421e0ce6 c0a8b6d8 c243c2de bd03a3f0 3cf59a17 bcd5a601 3c2ccd2c -> bebf64ad bda6233d 3e0b9f5d",
+ "c0cc27e8 4206f2e4 41d8423c 3ab92905 bafecea7 3b38bfdc 3cda80a6 -> bddfb159 bb35ffb7 3dd3afd6",
+ "414de710 c2128c0b c01640e0 bc254755 bc45e1d0 bcac29ee 3ec8602d -> bebc1ef2 00000000 4054e467",
+ "c2201cfe 4122c6a8 41dd3948 3c147a28 bc526849 bbb0bef9 3abd9726 -> be60b16f bc5bbe60 3c487927",
+ "c1e8edaf c244b358 41223c84 bb301a46 b88b4467 3b81231f 3b4af11d -> 3d1bf59d 3c080b88 3c32f853",
+ "c1c36e59 c1a2edc6 42027b8c 3b33f959 bb5e708f 3b356599 3e871420 -> beb920cf 00000000 400926d9",
+ "4190137c 41cca28c c1f7128c bae1812b bc162ac0 baf755f2 3d48ba28 -> be32dc85 3c31f3fd 3e4dffa2",
+ "c1718858 c233d8ac bff265c0 bc59910c 3bcfe2a8 3b9e6f0e 3bbcb75a -> bed721df 3c7205f5 3cf95843",
+ "bfe0a840 41a8c2b0 423e41d4 3c7cab55 3c032a7b bd7d8fd7 3b145f10 -> 3db8ea2f 3dbe60f0 3e06a639",
+ "c03b0740 c1a43b25 c1b88de9 b9001163 3a4efc0e ba4f9bc2 3a89e062 -> 3db4fd18 bb3e3d24 3b82a7e0",
+ "41d6efa4 4217e5fa 41e80124 3edcacd0 3eb70573 3dc8f8d4 3ec18d90 -> 3ee4cdb6 00000000 40f14053",
+ "40bc5620 423e26fa c23334e8 bc02192e bba1e241 bbf05824 3d15392d -> 3cebfb60 3c339561 3e4a3a8e",
+ "4180eb54 408eb1c0 41c553cc bad3a44d bad31177 ba54cfc9 3b163b32 -> bd9db823 ba664a9e 3b73f96a",
+ "413a86bc c2301c0d 4247eae0 3b2af1ff b9ad38ab badf6e7c 3ca1de3a -> 3d53d5a3 3b90cdbe 3d979f71",
+ "42283fd8 c02d4ce0 419c2700 3b6eb148 3ab57258 bae00e1c 3d28bd87 -> bf48e082 bc22c8e0 3e29bca3",
+ "c21dd324 c23f9961 c2091b10 b9febcc6 3ce0b479 bd0fc9e0 3bb1868a -> 3c1ab991 3bd3b354 3d999864",
+ "c1ceb757 4198c930 c1708a10 be4dee66 be859196 3e55efa9 3d6b78d8 -> bf43b721 00000000 406427b5",
+ "40e91718 417a8270 c14dcd6c 3e58e9cc bcf20852 3e847b8f 3b0a6d23 -> be5916ae 00000000 402c3640",
+ "41e9d014 40e69e30 c1034778 3969c314 3c91fe86 3c374f8b 3a8ee9ad -> bc3cc926 3c97b892 3c8bfaae",
+ "c1dae051 c20c931f c2425fe1 3ad973d9 3a360394 3a03445e 3e236e37 -> 3d529c6e 3a85d7e6 3f744771",
+ "4231cb58 41b668d8 42270488 bba77add bb2f58dc bae84f97 3e92fa8c -> 3edb6c95 00000000 40157490",
+ "41012484 c2369a2e 418ce520 baf6be46 ba3c4749 3aeb1332 3d768676 -> be58290a 3bcf3624 3e9386f0",
+ "c2337fae c2393715 4200e490 bd94d81d 3d36a176 3e2a01ac 3c78a1a7 -> 3e590b84 3d3e3574 3f95c76a",
+ "c247fc0d c1836620 41898648 3ed884b0 3e81b803 3e278634 3e740ba4 -> bec03c1b 00000000 40c122ed",
+ "c240e0ab 40b16498 4237afaa 391ff3aa 3a73fc50 bb22910a 3cc01aac -> be98ac14 3843e420 3db82549",
+ "c1e44db8 3f423340 423905d6 bc553488 bab6d05e 3c08716c 3e1f65a7 -> bc8fb0f5 3bc1f562 3f73b4ee",
+ "c0cfea50 c1680478 c2368762 3e6b16e3 3e094688 bd299219 3c260a75 -> befa6cc8 00000000 400e5825",
+ "4238038e bffee4e0 c1a4e745 3cc7d463 bcce20bc 3db744ee 3e0587df -> bec23c1a bd0efd54 3fe00d58",
+ "c16d8a98 41ec8c54 c1e59844 bc012e78 3c24970e bd857b20 3c290ee4 -> bec731fd 3dacd1dc 3e48c93b",
+ "c245c1d5 c1942f0a 41a6638c 3d4ea696 bdb5a227 bdb3f7fd 3ceb09ea -> bf5c99fe be175a98 3f4a8269"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_fbm(vec3, vec3, float, int, float, float)",
+ "tolerance": "ulp-bounded",
+ "check": "the arguments are (cx, cy, cz, ax, ay, az, radius, ...) and the result is the form (x0, a, e). Enclosure: for eps in {-1, -0.5, 0, 0.5, 1} and d in {0, +-ex, +-ey, +-ez, (+-1, +-1, +-1) / sqrt(3)} (15 directions), form the point p = c + axis eps + radius d in double and round it to float32; the device's own reference value at p must lie in [x0 + a eps - e, x0 + a eps + e] with no tolerance, so a device whose gradient error exceeds the allowance fails. Tightness: with L = 7.9640074 and, for each octave (one for af_snoise), R = |axis| + radius, B = L R + 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R), the width |a| + e must be at most B + 2^-16 (1 + B). Report the least slack of each side, absolutely and as a fraction of e; only the two bounds fail the check. The reference value is cultmath_fbm_grad(p, octaves, lacunarity, gain).w, and B is the sum over octaves i of gain^i B_i, where B_i is B for the centre lacunarity^i c, the axis lacunarity^i axis and the radius lacunarity^i radius.",
+ "cases": [
+ "411c537c 420ffeae 4078d1a0 3cdfc7fe 3ced8823 bd581451 3bd5bfdb 00000004 40000000 3f000000 -> 3f1c017f bdc20710 3fd2f8e2",
+ "c2172004 410ab7d0 c1f2ca42 b9a78fc6 ba1d7262 3a8c08d4 3e338f4e 00000004 40000000 3f000000 -> bea9d56b b95ec7d0 40b0ea05",
+ "4115776c c2005a28 c21c7d94 bb82d4de bbf99288 bb14556b 3e706f99 00000004 40000000 3f000000 -> 3e0cb256 00000000 40f88286",
+ "c1dc368a 41869c94 4226de20 bcfe94ff 3b70c570 3c88304e 3d6c7520 00000004 40000000 3f000000 -> bf10b24d 3d77694a 401c59dc",
+ "c203bcc0 41cb2bbc c209d08b 3d98457a bd489b84 bdcfb707 3d19027b 00000004 40000000 3f000000 -> 3d8f1a2c be4d5c90 40a0b74b",
+ "41e45754 42248ae6 411d2fac bd7d08bb be3dbc00 3e5fb94c 3dbc85a8 00000004 40000000 3f000000 -> be1bcf46 00000000 414455cf",
+ "c0ff5658 4216c372 c1aea658 bc0f34a6 3c62e6bc bbc51abb 3d16dd85 00000004 40000000 3f000000 -> 3db396b2 3d0fb0eb 3fadf568",
+ "3eaaf500 4180ac44 c105a4e0 3a9cdb0e b920ef6e ba380c9d 3d088bb6 00000004 40000000 3f000000 -> 3e9e0360 bb918bc6 3f41cdd7",
+ "4201700c 408d4338 42173afe bd1957c4 bd11a659 3d45b37c 3bf04183 00000004 40000000 3f000000 -> 3dbb520b 3dbf9818 3fe33039",
+ "c20c49a6 40291410 40962208 baaa709c b949a8bd 39947c97 3b1fa49a 00000004 40000000 3f000000 -> be925bbe 3a69b13a 3cf0f01a",
+ "418bdb28 c1f8333f c211ebc4 ba84873a ba463c1f b95ca930 3b5a553a 00000004 40000000 3f000000 -> bf770906 3b95ac4f 3d269588",
+ "c07870c0 40f13610 c1c85790 3b1283eb 3b36b039 3abd56b7 3bffdb24 00000004 40000000 3f000000 -> 3d822045 bc9bcf63 3e0c92f5",
+ "413c9a20 c23a522a c236024b bdc256ec bd305cf0 3d093814 3bb9292f 00000004 40000000 3f000000 -> beb0848a 3e05dd8c 403e9559",
+ "421c32d8 42387e66 c1af30cc bc15aee6 3d74e834 bd35d262 3a901e4e 00000004 40000000 3f000000 -> bf049507 bd8d8e0e 3fdb1326",
+ "c20eaff6 c1b56412 c10f2d70 bcb56591 bd29e076 bcd5a70f 3cad2e7c 00000004 40000000 3f000000 -> bda46ee0 3dc371cd 3fe8c2be",
+ "c223bb64 41939ad4 c2054531 3cc10801 3c94f8ed bb0df003 3b6a1616 00000004 40000000 3f000000 -> 3e312a49 3d449980 3f02597c",
+ "41ecdc4c c1e2ecba 41ae504c baa38c97 3b90982b 3c1dffdf 3be0462f 00000004 40000000 3f000000 -> 3d881847 bccf5634 3e406db7",
+ "41081668 420ea82c c1cf6363 bbd07906 3b82b3d6 3b750849 3cbc359b 00000004 40000000 3f000000 -> 3c0f8e9a 3b831b8a 3f07cf87",
+ "c10886cc c1d48d63 c237c876 3b2755b3 bd04e56a bd167c20 3c8b3546 00000004 40000000 3f000000 -> 3cb79922 3e79e8a4 3fc564c4",
+ "41c549ac 40ad6cf0 41b487b4 bc78b86e bcb6a67e bbbb5f82 3ae26484 00000004 40000000 3f000000 -> bf25ff3f bdbb9878 3ed4ffdb",
+ "be8bae80 c229817c 42168f44 bb01345a 3b0875c2 3a0ef65d 3c7fd6ec 00000004 40000000 3f000000 -> 3ef5653e bc729d21 3edbb09a",
+ "c18533dc c21f8bfe c2291deb 3c75a994 3c89ab5a bb0e449f 3be0ad70 00000004 40000000 3f000000 -> be030eba 3ced209d 3ed5778e",
+ "42287142 41822030 c212ee17 3d00286c 3d3a3436 3ca70d22 3dbd32ca 00000004 40000000 3f000000 -> 3e915cf4 3d8731fe 408ece44",
+ "c1eba852 c1be364e 415db64c 3e74ab13 bd22f014 be4840b7 3cd9de60 00000004 40000000 3f000000 -> 3e4f34fc 00000000 412c4558",
+ "c03eef80 c20adb80 41fe5c14 3eb261dc 3d2ed9e9 be4f2d0b 3d59cb57 00000004 40000000 3f000000 -> 3de797f8 00000000 4169a53e",
+ "4181b764 411d948c c1c836c3 3c6d35eb 3ab92f87 3a843a10 3dfc3962 00000004 40000000 3f000000 -> be51e980 3d343773 4087664a",
+ "c219ea1f c1066980 411c8900 3cc2c99a 3c51cdbe bc1fbebf 3d3d3d98 00000004 40000000 3f000000 -> 3f37dd86 3becb908 3fef3576",
+ "c11747d0 c20ca374 c244a40f bea1618a 3e22ed86 bcee5530 3e951a5f 00000004 40000000 3f000000 -> 3e8898e5 00000000 41a48846",
+ "42442582 409e6848 4245239e bda85104 bc0e8ace bcb8f19f 3c250714 00000004 40000000 3f000000 -> 3eadbadf 3dc9675a 40155b20",
+ "c123d224 bf259680 42463fec 3a3dde01 babdeb21 3aabd6a4 3d7429e7 00000004 40000000 3f000000 -> bd9e4602 bb32844d 3fb36747",
+ "41b66cec 4211bb12 41daf39c 3cab930c 3b9ef4de 3bdaec73 3dcdb7c9 00000004 40000000 3f000000 -> 3d7f76c2 3d994a22 40717d6a",
+ "4202cc30 c1eedf0b 40e05e58 3c1488c3 bd3f0b41 39fc484d 3ee10a01 00000004 40000000 3f000000 -> bf143d2e 00000000 41784a5a",
+ "c213337c c1825a24 c0b80728 3ae06722 3c0753d5 3b743588 3d6b9e8d 00000004 40000000 3f000000 -> bee90a95 bc5732b8 3fd40627",
+ "c243a17e c1daf546 c210a96c 3bdee19b bc217553 3c6824f7 3b39b092 00000004 40000000 3f000000 -> 3d4dace2 3e09c90c 3e73dffa",
+ "c10df350 c16e9b00 c1c8ea76 3b92303d 3b913dd4 bb927456 3c58fb7d 00000004 40000000 3f000000 -> 3f0b8c5d 3ad46f70 3e993c3a",
+ "423296a6 c1c6e3ca 4230a43a 3e96b5c1 3de42fdd 3e7d2deb 3b016bd0 00000004 40000000 3f000000 -> be8b11b8 00000000 414d1209",
+ "424489da c2414dd9 c23b602a 3b70c6de bb267566 bba1fd58 3ecb270b 00000004 40000000 3f000000 -> be882fb2 00000000 414db6b4",
+ "c1cc6650 c2173e2d 409bad30 bbaa0af1 bcdb880d bd247759 3d7f487e 00000004 40000000 3f000000 -> 3e938264 bdca314e 404c4dfa",
+ "c1e34d41 c11bd9a0 c1782270 bb4520aa bae77110 bb384961 3b84c9fe 00000004 40000000 3f000000 -> 3d8e1b40 3c2a59b9 3d96e29f",
+ "c1ca1942 c23d39f4 bf029600 3b8c41e0 3b106e20 3b5fccdd 3c1b94a7 00000004 40000000 3f000000 -> bf26dd3c 3cae430a 3e4db4df",
+ "c1267c64 c23c717d c0c0a6d8 bd81f5f6 3d06ddcd bcb414ab 3b0666f5 00000004 40000000 3f000000 -> be709ffd 3d31fd14 3fdcfdc4",
+ "c1c947d7 c1aadb76 c23cbf72 bd1b72b3 baf5d1cc 3e035db1 3dfcc1b7 00000004 40000000 3f000000 -> bf4845aa 00000000 41032705",
+ "c1cd979f c1b277ff 41bdb4e0 bc07bdf0 3bc1f212 bc94d0c4 3de96f8a 00000004 40000000 3f000000 -> be3c9e4e 3be7a95c 4080284d",
+ "4232f882 41f52f90 c2355fd8 3d9271cc 3d9172a4 bdb00051 3d14a05c 00000004 40000000 3f000000 -> 3f521f0e 3dbf640f 409cbc80",
+ "c15a902c c1fab89a c1ef6846 3bbfaefb bbabc19a 3a6049be 3cd54597 00000004 40000000 3f000000 -> bebeb15e 3aac906c 3f2764da",
+ "c23bcbdc c1d87d68 4230c31a bd83e10a bd40e6d3 3da20469 3ddeecaa 00000004 40000000 3f000000 -> 3f8edc0a 00000000 40e19e49",
+ "c234dd23 41b040d0 c22fbcc4 3cd334f5 bc644858 bcd9368a 3de10869 00000004 40000000 3f000000 -> 3e69ba9e 3d803067 408dc815",
+ "42377f12 418e6760 41d721e0 3b0eb82f 3acbdba7 bb365e5e 3c860ebf 00000004 40000000 3f000000 -> 3eaa7286 bba2a423 3ece0df9",
+ "c20ccc7e c09e8f00 c0f24d40 ba9e563f 39da0c06 bb2e59a2 3ebd30c4 00000004 40000000 3f000000 -> 3ebb9461 00000000 413de01c",
+ "41c25fcc c1e5b6b7 c07eba00 3a2527b8 ba184cec 394943db 3d808514 00000004 40000000 3f000000 -> 3e2705be ba8ce326 3fc880f6",
+ "422fde8c c1a640d7 41b087ac 3a4e0054 399e043c 3a0003d7 3aed7f91 00000004 40000000 3f000000 -> be81ba06 ba65e97c 3cfd9943",
+ "c2149916 c0b07e18 c0a3bdb0 3887bc26 ba550c0d 3a8b272d 3c68e036 00000004 40000000 3f000000 -> 3e8ac2bc bbbf2d7f 3e8046b0",
+ "4225e29e bf44cf40 4127cb64 3d9bfc92 3d2a5b7b bc04426d 3c9e49f7 00000004 40000000 3f000000 -> 3ded1620 3ca6bc60 402f7cda",
+ "418e42d4 c21c207c 41f34ba8 3d592b51 3daab19f bd9c1fa4 3d5cf5df 00000004 40000000 3f000000 -> bedddc4c 3d445dfc 40a7be4c",
+ "c218f1ed c21ec03c c138a8d0 3be10d36 bb9c4122 3b788abe 3d026c59 00000004 40000000 3f000000 -> 3f544f07 bb308b88 3f5d5ef0",
+ "41f1f754 c1891084 c236bbcc be15fac3 3e422392 bce56cbc 3ce18e2c 00000004 40000000 3f000000 -> bd84f716 00000000 41090701",
+ "c1851b76 c23ab103 c2080ec0 3ac83244 3b11ce25 3b115b03 3b95dd08 00000004 40000000 3f000000 -> bf389656 bc51612a 3d92e101",
+ "420405ee c1cc8666 c11ba998 3cea263b 3d2fbfa9 bcaccf37 3b2168a8 00000004 40000000 3f000000 -> be056936 3e2bf367 3f930530",
+ "c134a4dc 41f5e4a0 422e947e 3c11079d 3a3c6129 3a9d0fc8 3d8ce42f 00000004 40000000 3f000000 -> 3db34a97 ba72b87c 40125b72",
+ "41e0b1dc c234b7a2 4233680e 3c053f76 3bc92a3f bc00568a 3d94dbc6 00000004 40000000 3f000000 -> bedbca2d 3d135bc2 40173713",
+ "419176a4 c1b754a1 c13adbc4 3da35925 3db19a6e 3dd8896f 3bdeb1ae 00000004 40000000 3f000000 -> be140a2c 3e085bd4 40975461",
+ "c1a440cf c20ffaa2 4011de90 3d0fdb5c bd3502aa 3ce9e87c 3e6690c8 00000004 40000000 3f000000 -> 3f0be84b 00000000 41130af8",
+ "c237bde3 421f4634 c07e0180 bbd08915 bbe50f3f 3b41cacb 3e1acfe4 00000004 40000000 3f000000 -> be204d5f 3c589908 409f8144",
+ "bf896f40 c0049b30 c0f01c28 3d37b07c bce0367d 3c3c765e 3b79fa70 00000004 40000000 3f000000 -> 3ed17233 be48385e 3f909692",
+ "421c494e 41aaa140 4232a7ac 3b1bc953 3a322380 bc1122f9 3ce43c6f 00000004 40000000 3f000000 -> 3da43514 bb0616fb 3f2c2fa6",
+ "42175292 414d2140 c215dfd5 bd8fd165 3d6aecf2 3d4a4ff1 3d9ce7b6 00000004 40000000 3f000000 -> bf36ed0d 3d868ea6 40acb83f",
+ "c1b0fdd2 c2291c77 bf991b60 bd9983d4 bdcd1673 3cf442c9 3d8739ba 00000004 40000000 3f000000 -> be1dcbc2 00000000 40c67817",
+ "40c87c08 40f32a88 c1abf512 baa2ef7f bb831d5b ba6aca33 3a8fd1b4 00000004 40000000 3f000000 -> 3f42ae20 3ba64d34 3cd4f1f8",
+ "4097f6e0 c19a0a22 41c649a4 bac6b4ca ba86ed60 ba410d2d 3cd8d4f6 00000004 40000000 3f000000 -> bf3f72b6 3bef905a 3f1f2d81",
+ "40f5fef0 422a0d2a c0c98ac0 3c2eae2b bc59bfb3 3c0aa4ee 3d1a6b3e 00000004 40000000 3f000000 -> 3d16c7e3 3d9de831 3fb396a2",
+ "415035b0 41b5a8c4 c1374cdc 3d9c060c 3db531a3 bdead4db 3e4d0732 00000004 40000000 3f000000 -> 3ead9ab2 00000000 41397e32",
+ "c229ac66 c1b5de74 42357e04 be69f671 3ecd9be6 bea8e569 3d39a28d 00000004 40000000 3f000000 -> bdf96add 00000000 419c42f5",
+ "c1ff5411 c21bd882 c210fa43 bd549937 3d0f6cb8 3c18dc4c 3a99c6d9 00000004 40000000 3f000000 -> 3ee1da62 3e7d93f9 3fb1543d",
+ "41cb1a2c 423870ac c2013c28 3a5ce20a bb1c13ca 3b1ee37e 3cea75d9 00000004 40000000 3f000000 -> 3d269dc6 3bb40300 3f1c0167",
+ "41d9e464 41a0fa94 41ab67e0 3d7116bd 3cd00be8 bd2fdf7a 3da7d2a4 00000004 40000000 3f000000 -> be85143e 3d43d7a8 409975b0",
+ "c1cac9fe 421e2dca c2371229 bdb08185 bd82b8fd bdb16dce 3d2ab264 00000004 40000000 3f000000 -> 3d9154df 3dfe6ec5 40a9a30d",
+ "41fd83f0 42016df2 c1cdacaa 3dbfffe8 bdc374a6 bc92e18e 3e890e37 00000004 40000000 3f000000 -> 3d64fd94 00000000 414d49ff",
+ "c205ca8a c1606a2c c23c16c8 3d67d977 3ded8794 bdb23d0c 3e59beb6 00000004 40000000 3f000000 -> bf08c549 00000000 413bc6c5",
+ "bff03ba0 c1093fa0 c1f052e0 bc4e7a21 bb9f73ad 3c4b9813 3ccc00b4 00000004 40000000 3f000000 -> bd2eebf3 3d405ca8 3f61c43e",
+ "421ade98 c0e3b290 c0a12a90 3afc5cba 3b045372 3b17603b 3c480e98 00000004 40000000 3f000000 -> bdab8b47 bbf0eb80 3e5d6612",
+ "418240c0 40f64790 c10c3058 3df2ae14 bdf7c941 3d1eae4f 3d7f99fc 00000004 40000000 3f000000 -> bdbdfd18 3b2e3084 40e75c85",
+ "c1b406b5 41fc1bec 405bdb60 3bde1568 bbb217ef bcbbd99c 3c5808db 00000004 40000000 3f000000 -> bf43c50d bcbe6da6 3f1f6467",
+ "4166e980 c1ffd0bc c13c16fc be2efa14 3e081ab6 bda387be 3c4fb685 00000004 40000000 3f000000 -> be67fc48 00000000 40f834f1",
+ "c2242daf 41b49f7c 4219fe2c 3bb0f7aa bc3c4955 bc22543b 3c95fae2 00000004 40000000 3f000000 -> be595a64 bc9c4132 3f1b535d",
+ "41556784 414ba754 c204e145 b98f7dbb b8bd070d 3aade21e 3c90c46f 00000004 40000000 3f000000 -> bd90727f 3ba44422 3eb8d3e6",
+ "41d03c0c 405e1cf0 c1c60785 3c45ff78 bc173ac0 3c4adc98 3cb15136 00000004 40000000 3f000000 -> bf37474a 3c594a64 3f50ef39",
+ "c13ccdb8 c23a1648 413c7d78 bc0eb46b 3c83ec9e bc40c023 3e8316fe 00000004 40000000 3f000000 -> bdd993ce 00000000 410da223",
+ "c1d041d6 c246760a 419686b4 bb5be93a bb361775 bb943699 3b028a06 00000004 40000000 3f000000 -> bdbe74d9 bc955d8f 3d6ca599",
+ "4127864c c22d5136 421a85be ba166083 3a7c6a4e 3a87654d 3b3da2f8 00000004 40000000 3f000000 -> 3e9066ff bb12e24f 3d1dd7a9",
+ "c1a8d5b4 422831fc c216125e 3adf7cd6 3d1403ca 3b51cc8b 3e6c424d 00000004 40000000 3f000000 -> bc525770 00000000 41082a35",
+ "420908a6 c12f5a80 c22a1a67 3b920fbd 3c9f363a bd091319 3e0cf1ac 00000004 40000000 3f000000 -> 3f54b1af 00000000 40b41dcb",
+ "c14579b4 c1b3547a 420a16ec 3bf763d4 3b7da53e bb9575d9 3d07c0a4 00000004 40000000 3f000000 -> 3d22982e bbcadc76 3f7ef1a5",
+ "4030fd10 c20f5980 42092180 bd5515bb 3de948c8 bd8ea10b 3c5f2217 00000004 40000000 3f000000 -> bf11160b bdc067ed 408e7523",
+ "c238511b c0a9ea10 c1e0665d 3ba54046 3b4c0d0c bb411075 3c104895 00000004 40000000 3f000000 -> bdc964ee bca0f31c 3e48f979",
+ "c0445af0 41fa5a18 c11c12b0 bd9db44f bcc1d296 3c579407 3e8c2982 00000004 40000000 3f000000 -> bf0edfe3 00000000 41352a42",
+ "4225cc26 c2225436 41501db0 be8f3834 3d6f936d bdaaebbd 3d5eb176 00000004 40000000 3f000000 -> bd8cbc96 00000000 41338247",
+ "411485a0 40c57c18 c2243a7e bc1a7bc9 3b9af474 3a80b769 3ecfc4b5 00000004 40000000 3f000000 -> be4fb387 00000000 4154452e",
+ "c217c05c 41778088 4106289c b8885eb7 3a7a4344 bace5f60 3dcfa3b6 00000004 40000000 3f000000 -> be25ac6e 3a19bc8d 40358063",
+ "4220e7f6 bef0af00 423271da be5d6948 3d90c874 bd4d1b49 3b201707 00000004 40000000 3f000000 -> bb612ed0 00000000 40f008c6",
+ "40f6c250 42300a56 421d1f5e bb0e366d bac902cd badca25e 3c8e304c 00000004 40000000 3f000000 -> bdd38c54 bb943dda 3e8ae6dd",
+ "c22f7f7d 40f5b168 41f1b1c8 397280f0 3b2a6234 ba872054 3dce86ff 00000004 40000000 3f000000 -> bd005989 3b4a8604 403c3591",
+ "c1bb65fe c0cb79d0 41453ab8 3c342f8d baa7a691 bb3f8190 3b2e2cdb 00000004 40000000 3f000000 -> bd17f51e bc281275 3dd0dd1d",
+ "c2409be0 421ad8c6 c23552aa 3c512ad4 bc0741f7 bc1db66c 3a8aa963 00000004 40000000 3f000000 -> be01052c bd693f44 3e2a9fe4",
+ "c217944c 42324ea4 41efb8c4 3aaa51b2 ba3e226c 3a5fa69c 3e13d388 00000004 40000000 3f000000 -> 3e9369d7 bb1c69b6 408ccb52",
+ "c16dd4a0 c2161616 c238bbb8 3e81f7fc 3e706cde be2c0998 3e8e8ffa 00000004 40000000 3f000000 -> be969c26 00000000 41a8f6be",
+ "c1f628bc c1ecc8a9 41a540b4 3e0eb5c7 3e128dc3 bd41fa29 3b0380ac 00000004 40000000 3f000000 -> 3ec5d8cc 00000000 40d36afb",
+ "3ffe1900 41bc7720 c1e3b349 bb8a3a10 3b5ea705 3bc6e9fd 3d66046c 00000004 40000000 3f000000 -> 3d18bda5 bc9131e1 3fe18603",
+ "c200dd4a 41ea7378 c23a88ed bcccd3df bccd7e23 3d09dcf5 3ebee519 00000004 40000000 3f000000 -> befe117a 00000000 41570078",
+ "41ad79cc 4201637a c21970ac bc1f7965 3afe1001 bd228b52 3af04ad1 00000004 40000000 3f000000 -> 3e208181 3d110ee0 3f37508b",
+ "4196af18 c20f817f c0e2d0b0 3bc45404 3b2de722 bc56553f 3b249da9 00000004 40000000 3f000000 -> 3ede3592 3cb61a04 3e1b6d9f",
+ "41239a48 41961b08 410b28b0 bac2d6bf ba077ccb 38c70206 3d837891 00000004 40000000 3f000000 -> 3d0d4b5c 3ace0db9 3fcb23b9",
+ "c1a0330c c12f9d68 41b64970 3b0b10a0 3a10198f 3a9593f7 3efa8171 00000004 40000000 3f000000 -> bd7d845a 00000000 417aacd9",
+ "c1a2eb82 41cb51d0 c223ca7e 3adb1379 3a4eaa89 3a637c03 3a87764e 00000004 40000000 3f000000 -> 3d0c1b02 bbf8c03c 3c84595a",
+ "40567380 c218d8e1 4188ccb8 ba940e27 b9fb7ccd 3b041baa 3d1cc688 00000004 40000000 3f000000 -> beaf346b 3c0748c7 3f727311",
+ "41c39c50 421a3504 42467836 3ba9fc01 3c705f45 3c89f11a 3c166ce4 00000004 40000000 3f000000 -> bf0dcecd 3c8ef3cd 3f0e8120",
+ "c1a1c142 c0a9be30 c147065c 3a3cd099 ba977b2c ba3ee15d 3ae28c45 00000004 40000000 3f000000 -> 3f322a1e bb3eebc2 3cd506a9",
+ "c0d69ca8 c0d66d60 c212891e 3a4d922a 3e9d4e5f be1f4bc1 3eaa5834 00000004 40000000 3f000000 -> beb9cb24 00000000 41ac9285",
+ "c246fc38 4102ae20 40d10fc8 3e2b97b6 bdc27d20 bd972b41 3e8deaeb 00000004 40000000 3f000000 -> be3e7e40 00000000 417674a0",
+ "c0a2f3b0 c20f5cef c103e1c4 395ce8bd ba1fb581 b96fcc80 3ca9b456 00000004 40000000 3f000000 -> 3ea20d74 bad004a6 3ec6929e",
+ "421fe0aa 41bb1d2c 4207b0bc bbad74cd 3b782db1 bbeb47a7 3cb027fc 00000004 40000000 3f000000 -> 3ebac1aa bd0e746c 3f106090",
+ "422315b2 4104c504 419ff858 bd9fcb38 3e239163 be0adefd 3e35b690 00000004 40000000 3f000000 -> bf4326af 00000000 414c74c0",
+ "41163514 c22f2b2f 3f32dd00 ba1f93d7 3a68e94b 39d04ee4 3e8e30da 00000004 40000000 3f000000 -> be3b7978 00000000 410e2b5b",
+ "c23be10c c03a5c40 410c2bd0 3c5d55c0 bd03d389 bae984a1 3b8c7f92 00000004 40000000 3f000000 -> 3ea82377 bdbdf1bf 3f267d7c",
+ "c2359360 4169d378 c232d50b bdce756a 3db86fdd 3d08a77d 3c141a22 00000004 40000000 3f000000 -> beec6c7e 3dc6e3c2 4085a7aa",
+ "c15b16b8 c22b46a0 c22b0d9e 3a43ab54 39c49540 3a117eec 3c8f7ce5 00000004 40000000 3f000000 -> bf4b1b94 bac84690 3ebbf1db",
+ "c2317306 41075380 c11351e0 3c36c52c bc05fac0 bc73f063 3a996a28 00000004 40000000 3f000000 -> be540e3f 3cfed04b 3e5416b4",
+ "c22d68b6 422dace0 c1413374 be14c27c 3cc72c35 3dfb6543 3d9e54aa 00000004 40000000 3f000000 -> be3afd1f 00000000 41093001",
+ "c220599d c05ad660 41dafdc0 3d23882a bc88995f 3cc3bb24 3dab11a4 00000004 40000000 3f000000 -> bd8922a7 bdc3c9f0 40788856",
+ "c0fe4e78 c20adb17 4183900c 3ae63506 39ba8a8c badb5a15 3c7282ee 00000004 40000000 3f000000 -> 3e15b863 3bd70782 3e7a2246",
+ "4203017a c2152b1a 410df588 3a474995 3a928480 38e0cfb6 3d9250ff 00000004 40000000 3f000000 -> beed58a7 3b72db13 40075ce5",
+ "c11c9b98 c23cf58c 41a08b5c 3760a7fb 3ac5e2a1 ba7fb52f 3e0ab73e 00000004 40000000 3f000000 -> 3ea7d74d 3a7f8b97 407fe5eb",
+ "c1ef704d c14b2ac0 c2452805 3b2daf91 bb7da37c 39562286 3dc9bd51 00000004 40000000 3f000000 -> bdec5160 3ba3a1c4 4040e47b",
+ "42018cf0 419ce7d8 c21760c6 3c362d87 bcc7d1d6 bc814785 3cbd890f 00000004 40000000 3f000000 -> bef82201 bd6c0ce0 3f94be22",
+ "41b190bc 423251f6 4245a90e 3ea4c751 3e629011 3e8796f5 3b2e5070 00000004 40000000 3f000000 -> 3d5829c9 00000000 4171eed5",
+ "4229606e c2252a63 c1e5851a 3d880688 3d8e1367 be28a442 3d2b6fb2 00000004 40000000 3f000000 -> 3da3fda3 00000000 40ed21f1",
+ "420fd0a8 4215f48c 423c6508 3acc1227 3c64e999 3b50349e 3e136eb8 00000004 40000000 3f000000 -> be110df8 3b2e4a0b 4094fb19",
+ "41237d7c 420c2988 c1e4d57e 3aa08d69 baf8f89a 3af687e4 3bfe9c2f 00000004 40000000 3f000000 -> 3e2598c2 bb834a07 3df01623",
+ "41f36f74 c1f3b158 c10629fc 3caa5373 bc12d517 3c9f5f5c 3c20de7a 00000004 40000000 3f000000 -> bec3b24f 3d6050fa 3f3718bc",
+ "c025aa70 420be70c c19d2761 3d7aa26c 3cb9f35a bd96c78f 3b650cdd 00000004 40000000 3f000000 -> 3e496efb 3e1098e1 4021384d",
+ "bfa424c0 4005d200 418f83a8 be05b11b 3dc56793 3e175267 3dc7bff5 00000004 40000000 3f000000 -> bf1512b0 00000000 41219a0f",
+ "c183a0a4 c1f42c6c c186c3f8 3a103d46 3ab210cb ba44e1d3 3e9c0f2a 00000004 40000000 3f000000 -> 3eee9c87 00000000 411c3c2e",
+ "c221d850 4219533c c21e81a6 bc049735 3b893ce3 3bf85884 3cb753b6 00000004 40000000 3f000000 -> bf50002d bd3c01d0 3f1df244",
+ "c22bf575 4125b210 4235f31e 3ced564a 3d747ea1 3d9e2d85 3eea36a8 00000004 40000000 3f000000 -> bceb5634 00000000 418e8f1c",
+ "41b7923c c242eda0 413b694c bb1444dd bb8a58ed bb64d35d 3a8b7539 00000004 40000000 3f000000 -> beee7494 bcadd192 3d14bf16",
+ "c1ccac23 418f89cc c1debe36 bd435d47 3c8d15cf 3ccd69b8 3d8bf797 00000004 40000000 3f000000 -> 3ec7788d 3dc40de4 4064d5aa",
+ "3fa18a80 c13a51b8 41610668 3c0d1e47 3e05953b 3ea61ff9 3e384977 00000004 40000000 3f000000 -> 3f051bbe 00000000 4187068d",
+ "41c4cc20 c20037f8 41c7f87c 3c759bb1 bc37204b bca0f93c 3c900d50 00000004 40000000 3f000000 -> bf1569a6 3dea34f8 3f5d944a",
+ "c1e7a170 c17607a8 c11824c0 bce59249 bd247b14 3c089c8f 3e9fbd09 00000004 40000000 3f000000 -> 3d839393 00000000 41385f5e",
+ "4177cb88 c2227f1d c200ddd1 bb71c7ac bc9a7c83 bac33178 3c449a2d 00000004 40000000 3f000000 -> 3d66dd71 bc867476 3ef4c752",
+ "420e2e14 c1b3b6de c1f6a4d5 bb5ec704 bbbb1ef4 b9ba3033 3a9e7431 00000004 40000000 3f000000 -> be3f6fcb 3c8c025e 3d2f4373",
+ "c240dbf3 41e17ff4 40aa9840 b9c9cce5 3a948e51 bad432f8 3efc4242 00000004 40000000 3f000000 -> becc3aa6 00000000 417c3364",
+ "4146ff04 41d0546c c0fe7040 bd052f6a bd4ba0c2 39952496 3c9ccb33 00000004 40000000 3f000000 -> be8c8080 be39cb6b 3feb450b",
+ "41e61164 41ad821c c1b282b6 3a16211e ba64f483 bb2907c6 3d2cec18 00000004 40000000 3f000000 -> bf28d674 bafb911c 3fa36a13",
+ "41a60e2c c16f90e8 4163bd10 bcf30046 3c8c5e01 bc94e11d 3b2ee13c 00000004 40000000 3f000000 -> 3e9f5902 bd92cc11 3f2e582b",
+ "42159f40 c148f810 410e0e98 b9bde814 ba951933 384cb80e 3ea032af 00000004 40000000 3f000000 -> 3f18309e 00000000 41201f5a",
+ "42294a94 c1ff8889 42210fe6 3cebc33b 3d19012b bd40f60c 3dad6897 00000004 40000000 3f000000 -> 3e94f0f4 be4eab35 4093400a",
+ "41daa4f8 41ad85bc 3f86e620 3c608281 bcb6110d 39f4f78a 3cfa574a 00000004 40000000 3f000000 -> 3e45d604 3da15402 3fa524cb",
+ "c144db10 423482c8 c0c98a00 baa83824 39adf9e1 3ab49f60 3e611d77 00000004 40000000 3f000000 -> bf0c89ac 3a7eab6c 40de1b95",
+ "4052aeb0 c1bde8aa 41f63704 3cdbd6d0 be4d42a7 3e7fb717 3c047d34 00000004 40000000 3f000000 -> be41d3e9 00000000 4127f1e8",
+ "c1e42928 c16bc4e4 bec52e00 3a8ddb4f 3b7fd64f 3bce15d3 3e99a768 00000004 40000000 3f000000 -> 3f51a34e 00000000 411ccded",
+ "c1e322db 422b57ea 41e8a030 bb882c35 3b6246c9 bafd1d26 3e28ec8e 00000004 40000000 3f000000 -> bd686c66 39259560 40a68df7",
+ "4211ff44 c23881bb c2408cbc bcdb0532 bb7a122e 3c977ce9 3bead6df 00000004 40000000 3f000000 -> be84d440 3d96ff04 3f300a90",
+ "c1d129a4 c239ea97 c2113185 3c8ab16e bc13c331 bc42ce29 3d815d00 00000004 40000000 3f000000 -> be1b01cc 3d0b6454 4009ee29",
+ "41b54d74 c2024474 c19e6a2d 3ace17b7 bc169492 3c5c82cb 3d5daf55 00000004 40000000 3f000000 -> bd42580a bced5044 3fdcb0a3",
+ "c22ae99e 3ff9bb80 420e208e 3adfb11f 3a13028b 3a2b936b 3e29ece0 00000004 40000000 3f000000 -> bd41e7a0 bb644498 40a920c7",
+ "42182fb4 42429ae2 c23d8dfd bca4e0f7 bb097ff9 bc0e8822 3e061731 00000004 40000000 3f000000 -> bea790ca bd25623e 40940379",
+ "3fd654c0 c2004134 c21f34ce 3bad1e4c bb91738e 3cc04991 3ed8f2a8 00000004 40000000 3f000000 -> 3e20721b 00000000 41647cdc",
+ "41d5a748 c2166cd2 4132b138 b995c986 3abc59b0 ba4128e2 3d9b3055 00000004 40000000 3f000000 -> 3ed7857d bb6b41e7 3ffd5342",
+ "c2327858 c1456280 c07ca960 3b5630f5 3bf9ff4c 384c9e8e 3d540510 00000004 40000000 3f000000 -> 3edd0178 bc011321 3fbd2e0a",
+ "c1095c08 c19426f6 4100a1e0 be8d7e18 3e1350ea 3d9dfedf 3baf2075 00000004 40000000 3f000000 -> bf2c9d8d 00000000 41265815",
+ "420cfe34 3fe4c000 422288ea bc14289d ba767164 bc1bf9dd 3d7063e9 00000004 40000000 3f000000 -> 3c6a2ab8 bcce93c2 3ff04f9d",
+ "4106de90 4218ede8 c12b5f44 3d949959 3becc8fc bc510b9d 3e9d6a79 00000004 40000000 3f000000 -> 3e463517 00000000 41427983",
+ "41b1867c c18801d6 c07f2d90 3da94056 3d5eefa9 bd4691c9 3e3ec0cb 00000004 40000000 3f000000 -> bebd6f7d 00000000 411723ed",
+ "418e9730 c0522760 c219afa1 3b808738 3ba77258 3b431d1f 3b09f536 00000004 40000000 3f000000 -> bf3c3145 bc62cc8d 3d6be9a6",
+ "408fc498 c17ca84c c1e0575a be68ed93 3e49b4e1 3d869b3a 3d2988f4 00000004 40000000 3f000000 -> 3f19b000 00000000 41321d1d",
+ "c185eb50 41f46684 422438ce bd041fbb 3d3c6d0a 3cade74c 3e5debbd 00000004 40000000 3f000000 -> bd979076 00000000 410d1fc9",
+ "4220889c 417e64a8 c1b4e6e5 be1f032a 3e3afb7f bde6b793 3a999237 00000004 40000000 3f000000 -> 3eb36a56 00000000 4107a31b",
+ "c198b1ec c22dc971 419f3d30 bc5b4a3f 3cb1e0ae 3cd8a0b5 3d61ab08 00000004 40000000 3f000000 -> 3e54ad7c 3e057830 40219e7e",
+ "c2157ad6 c1b57802 c20d481f bc9eed89 3b2893fb 3d2bc0b8 3e378580 00000004 40000000 3f000000 -> bf574a4b 00000000 40e5f8ca",
+ "41a09a98 421082c0 c1423da4 3b32fab0 38d7d112 39c69431 3e6311b9 00000004 40000000 3f000000 -> bb058760 00000000 40e4f043",
+ "4201c118 c1c77d72 c13d190c 3a8380d5 3b128f31 3b2bc499 3d89e52e 00000004 40000000 3f000000 -> bcbb300c bbc28f87 40006f56",
+ "c22c6586 c1f4b9f0 4102c408 be93be68 bedefc74 be63d070 3d0f3748 00000004 40000000 3f000000 -> bed4e2bb 00000000 4199a654",
+ "42431cda c1bb70d4 40d59710 39b54f8a 3a8960da 389f4e82 3c2c9140 00000004 40000000 3f000000 -> 3ea25656 ba5ed09c 3e224482",
+ "41e842ac c0c249e0 c1fb04ef b92baa35 bbcfc7da bbc25faa 3e0e18ce 00000004 40000000 3f000000 -> 3e8a698a 3c04b047 409012aa",
+ "3f471400 420415be 41dc4504 b9dbe505 39fd8182 3ad9e25e 3ba232df 00000004 40000000 3f000000 -> bf288f4c bbc690bd 3da9375c",
+ "c17ef784 c0421070 41018340 3b060b54 3ae7f604 3a31f106 3d84f2a8 00000004 40000000 3f000000 -> be810e8d 3be6dc30 3ffa1506",
+ "412294e8 41f581e0 c1ed6a5b 3d522f51 3bb34d0a bd098914 3e3419fb 00000004 40000000 3f000000 -> 3e9609bc 00000000 40f22257",
+ "41abef80 c246c2fe c1333b00 3ac3aa06 3a6426cf bb270329 3eec98d8 00000004 40000000 3f000000 -> beacfb15 00000000 416d2701",
+ "c225fa27 41e6a1c0 c003b630 bb953b24 bbc7a807 bbba95e9 3c0ee528 00000004 40000000 3f000000 -> 3f08274a bba4dae8 3e70fc35",
+ "c1aadf86 c19868be 418763fc ba194e68 ba2d4f0f b9d85039 3e919a5e 00000004 40000000 3f000000 -> bf7cb3fc 00000000 41117ac4",
+ "41ea5fb0 3fbfcd80 41b374a8 3d57d5c6 bbbe1e28 3d4444a2 3ec7fdcb 00000004 40000000 3f000000 -> 3eb095c7 00000000 416b8cd5",
+ "41465f10 42318290 c14a3098 bba8ade1 3babb17a 3aca10ff 3dc477fc 00000004 40000000 3f000000 -> bf058600 00000000 40530957",
+ "c1ae95b5 4116686c c233e34f ba049bd3 ba8f5621 b9e09208 3c6e1b79 00000004 40000000 3f000000 -> bf51f676 baf6e444 3e9c2141",
+ "4136c8f0 420df1ca c1590ee0 3d254034 bd546a0d bc0c3685 3be794f5 00000004 40000000 3f000000 -> beec463a bd946bf4 3fd6b638",
+ "40d0d920 c0059320 c0d565e8 3b0e3d53 3804f389 bb11d2c6 3d49ab0a 00000004 40000000 3f000000 -> bede810c 3c0b459f 3fabacea",
+ "423184c6 3ff9cda0 41bb42b4 3b8648a8 3b8ef1d1 bbb5f177 3ce1b7bb 00000004 40000000 3f000000 -> 3f158afa bc5be546 3f4ea486",
+ "41bc0984 422e1234 422476c0 bd465b77 bd8e18e0 3b0ff000 3cbcd7b0 00000004 40000000 3f000000 -> babf4056 3b116770 403b0e68",
+ "c220d502 c1a4f1f4 c22cc417 ba771b8c ba33810c ba7ed2d6 3d3678eb 00000004 40000000 3f000000 -> 3f3aef80 bacf8f28 3f8e58ad",
+ "401a2f80 c2305cea 41f8919c bd33b9ab bcba2e38 3daf557f 3dff4a0f 00000004 40000000 3f000000 -> 3e8f9f3c bd98cf34 40de0b11",
+ "bfb474e0 c0f4c3e8 c1e8f590 3cd65c3f be428311 3d838fb4 3e11cbe8 00000004 40000000 3f000000 -> bea73a61 00000000 412fab2b",
+ "41ce56a4 4204604a 4221c3a6 be8fab07 3d930e63 3ea7b5e0 3bbade5b 00000004 40000000 3f000000 -> 3d565f00 00000000 4161d489",
+ "423ceea8 422b713c c22c0909 bb9eebd7 bd042d73 3b26e6ad 3dca4b4d 00000004 40000000 3f000000 -> 3ee0bd66 bd16e86d 4079c760",
+ "c0c59d08 c216a452 41e50c4c bdc76c2a bd0d92aa bd672195 3bfc7add 00000004 40000000 3f000000 -> 3c26156f 3dd027b8 4056b35b",
+ "c226a59a c21202b7 c1866c38 be89b9ca 3da19dd1 3e927d8d 3ef30817 00000004 40000000 3f000000 -> 3eb0dd15 00000000 41df1535",
+ "4180a394 c1b79724 c1bb2854 bb060fa8 bb73898d 38b7b883 3e9e4800 00000004 40000000 3f000000 -> be8d94f5 00000000 411fc504",
+ "c2222362 40445870 41effa38 bb737865 bbb06a60 bb708108 3c472a25 00000004 40000000 3f000000 -> bccaa1e0 3bb19ba5 3ea98722",
+ "421c46b6 c03fbdb0 c0b24410 bbab6847 3c3c440b 3c0b1ee9 3c72448e 00000004 40000000 3f000000 -> be0c85f5 3c9240b3 3f0483f0",
+ "413b9520 40f31e78 42100788 be40a08d bec16475 be781059 3c0ea11a 00000004 40000000 3f000000 -> bf39cb79 00000000 417c796d",
+ "423f3baa c22889b6 422b0f2e 3aeb777b baaa67f5 b9b7313c 3bd4231b 00000004 40000000 3f000000 -> bf08ccaa bbadc97b 3df9aa09",
+ "4137c568 42119c8c 4165f978 3a783f09 3c4af1c9 3c9aab30 3e27a578 00000004 40000000 3f000000 -> bf4a8912 bd28a51e 40bac9e0",
+ "41ed0734 422c1422 c239a3ed bce3710f 3ae065d0 3c72ead0 3defdf8f 00000004 40000000 3f000000 -> be366f45 3b49a570 4089fd3d",
+ "c0071180 42051b36 41693b40 bd24be5a 3bf55025 3ce1fcbc 3aba96cf 00000004 40000000 3f000000 -> becee216 be658794 3f6bcb47",
+ "c18a5630 c099ea10 c10b2fac bad63cdd bb560a47 3a5a484b 3d426a9e 00000004 40000000 3f000000 -> 3f319d4b bc0f10d4 3fa786df",
+ "c23b3cde c20e74c2 41fcbedc bc0b48f4 bbcd6318 3c647aff 3e0f2700 00000004 40000000 3f000000 -> be08fc3a bb105cd8 40998908",
+ "4106c7bc c237fc09 c203a58b bc06d21c 3ad282f0 bbb3b018 3c8d8e89 00000004 40000000 3f000000 -> 3d593f9d 3d228bcc 3efce465",
+ "c11398e4 c207685c 419678e0 3de869b0 3e47ffa9 bedf9423 3acefa7e 00000004 40000000 3f000000 -> bf4c4df4 00000000 417b6f1a",
+ "c1e6bb2b 410b15b8 c20cb87c b99502f3 3a409ba8 b84e92bb 3d46f1f0 00000004 40000000 3f000000 -> bda597d2 3a76de04 3f9423e4",
+ "c1759b68 c107f7b8 40ee5b00 3a05be61 ba3b4e24 38205568 3b340bba 00000004 40000000 3f000000 -> 3f218382 b8b35630 3d0f07a9",
+ "4229a830 420c74cc c20fd5af ba94d0d5 bad71942 bb7fbe29 3dbf6ae6 00000004 40000000 3f000000 -> 3d166c7c 3b6258aa 403599af",
+ "c1acf5a6 4235dd36 420c1de2 b8cb08b3 3a1860fe 3b405c26 3bed3d75 00000004 40000000 3f000000 -> 3e8b8939 bb24b98e 3ddab037",
+ "c217886d 41c1f4b0 c1cc3599 bd28addb 3d2ab68d bc69c127 3e4aa918 00000004 40000000 3f000000 -> 3ec8ee4b 00000000 4103a8fd",
+ "40b24060 40942988 4245422e bd1644e3 bce7bb46 3ca04920 3b59cb51 00000004 40000000 3f000000 -> 3f42f670 bd9f0b88 3f8f43c4",
+ "4169eff0 40236a10 c22f88a3 3c923781 3d8e9199 3d4b1af5 3e88c514 00000004 40000000 3f000000 -> 3e1e4a00 00000000 4134b1fc",
+ "404d4180 c102ad20 41e72b58 3c548ac1 bbd286fe bc4707fc 3dd66424 00000004 40000000 3f000000 -> be3ca775 bc2e1158 406b62c7",
+ "c102e82c c1c325fc 4225f9fa 3ebda24a 3e8dca26 3ec78d8e 3ae2eb11 00000004 40000000 3f000000 -> bf1ca4e9 00000000 419a98d6",
+ "c058e0d0 c1a81acd 41919924 bd78327d bc308e3f 3d8e8ae1 3b286860 00000004 40000000 3f000000 -> be0c390c be01de0d 40130b7a",
+ "c1efe89c 417b6400 40334040 3ceb8e66 be5a5990 3e420eb0 3c0476c8 00000004 40000000 3f000000 -> 3f1998b9 00000000 41164ac5",
+ "c23838ee c17679ac c2133da4 bdc45bd1 3dba62a1 3dca71ab 3b96d8b8 00000004 40000000 3f000000 -> 3ea6e903 3e7a2c18 409bf8e6",
+ "c11778b0 c1cbf70c c204806c bd882870 3d8d15da bd8522b3 3e0f6713 00000004 40000000 3f000000 -> be568d96 00000000 410266e0",
+ "40472670 423d275e c19a91b4 bb975444 3b906510 3a714d3b 3ac34c3f 00000004 40000000 3f000000 -> 3e5e2750 3cb9a972 3d360dc4",
+ "41a8f150 415b720c c1c42375 3b16f824 bb29b313 bb1ab960 3b5b411a 00000004 40000000 3f000000 -> be97ae58 bc144a86 3d58b580",
+ "3f8922e0 40fc0ba0 4228c3f2 3cadd7fa bcca5d19 bd35b16c 3ce56f73 00000004 40000000 3f000000 -> 3ed33dab 3dbeae4e 4003077c",
+ "c18dd196 c0cb7c78 c101d4d4 ba276cf4 3ab79f6b 3ab53b75 3c4da549 00000004 40000000 3f000000 -> 3d36d904 bc69a408 3e76d2bd",
+ "c0d3e190 41ba7a78 c0e9b910 3ce44345 bb25b220 bc920066 3b31e6a7 00000004 40000000 3f000000 -> bed4363a bd465f38 3f0ea10f",
+ "41d57528 c22ce5f0 c2388bcb 3b92b73c 3bc9a1bd ba74957d 3b82a0a5 00000004 40000000 3f000000 -> be36458a 3d0cacf4 3ddb4461",
+ "c23a5527 423dcca2 c1c33eba 3d20dd56 3c2c58ed bd37ec2f 3bc28d97 00000004 40000000 3f000000 -> bf0272e0 bd3bbc57 3fbbb50a",
+ "422c99e0 41d89c28 423830a4 bba57b65 3a15735e 3d08e1b9 3df6b561 00000004 40000000 3f000000 -> 3e2fa9cd 00000000 409d613a",
+ "41a1eacc 420b2912 41e9ff0c 3a35fa62 39d061f2 ba1e7df4 3ab14509 00000004 40000000 3f000000 -> 3e9c8394 3a48b28a 3cb04edf",
+ "c177126c 41d10714 420ed386 bd0a6e68 3c77e5f1 3d29d9a3 3d188bb1 00000004 40000000 3f000000 -> 3f20880a bdff1e40 4012c3e2",
+ "423d2c32 c1f2dde3 c237d2b5 3b3614b1 bb48cf27 3a0cb284 3e373e09 00000004 40000000 3f000000 -> 3e53c1b8 ba434f80 40b86241",
+ "417c2520 c20fd22d 41548b5c 370b906e 39ad8287 3a82b1fd 3ba75d7e 00000004 40000000 3f000000 -> be32a6c1 3a3d6eb0 3dca28bb",
+ "c19dc40a c1b9a43b 41a5e134 3e1d562e bcf01cb7 bc3c0a09 3c3667be 00000004 40000000 3f000000 -> be9da6b7 beb73c62 409af455",
+ "419deb20 c1ea18c4 c1a5d59f 3a7bca2b b99e31cb bad9ded7 3bd364aa 00000004 40000000 3f000000 -> bf2e6463 bbebd10a 3dc1e3a2",
+ "4223ff9c c1423a04 419aebac b9c1e0bf ba212a04 bb8b9add 3c4c5f36 00000004 40000000 3f000000 -> 3f3803e2 bc13d2e9 3e7dccba",
+ "c1963329 423742d0 c12dba78 bd36da8e bd0ada39 3b8d0c54 3e01e136 00000004 40000000 3f000000 -> be33466c 3cbf1722 40aeabd1",
+ "c22fc106 41179f3c c171d4d4 3e941ead bea2e3a2 3dba6c98 3d03e3b4 00000004 40000000 3f000000 -> 3e257e4a 00000000 41707c95",
+ "41b7ed18 41747d70 414ba814 bc9dee16 bb3d457a bc81dc09 3b8c20c3 00000004 40000000 3f000000 -> 3ece9045 3d4c876e 3ed52822",
+ "c2300a12 c1859f1c c1d2e3a6 3ad21ef4 b98db128 3aa80509 3e5a515d 00000004 40000000 3f000000 -> be4154d9 bacb3114 40db655c",
+ "c1fe8d79 c19edc85 3fc163c0 bee653f5 3ea98448 bdf37fad 3d0acddd 00000004 40000000 3f000000 -> 3f0b5b03 00000000 419a3189",
+ "41806410 3fafba00 c2343ff7 bb0b762f baea9be6 ba234fac 3e6e47fd 00000004 40000000 3f000000 -> bf436251 00000000 40f02fed",
+ "41c415cc c211ecc7 40574420 3dc6c26a 3d0a65f3 bcf88436 3e7d910f 00000004 40000000 3f000000 -> bf60255c 00000000 4134dda1",
+ "421279ac c208ecb7 40b1dbc8 3d5e6d68 bc2bdf44 3d6506e8 3d4598af 00000004 40000000 3f000000 -> bf187b25 3cadf2c8 40668cab",
+ "41ed3b54 bfaed640 41ccf804 3ae68342 3c61a0fd 3b5f0ebf 3e71b396 00000004 40000000 3f000000 -> becdc708 00000000 40ff40e7",
+ "c1b0e8fc c22fc242 41fd581c bbaa9b2c 3c99314e bc6b4fe0 3e9986f6 00000004 40000000 3f000000 -> 3ea0fa29 00000000 41253310",
+ "4236f4f0 c1605208 c14343d8 3da23d25 3dc3cc31 bdb521c0 3d103852 00000004 40000000 3f000000 -> bc472e12 3e48026a 40b1773a",
+ "421fb438 414da15c c21663f1 bdb5d1f9 3dabbff3 3d99331f 3b8eb4bd 00000004 40000000 3f000000 -> be2c2033 3c2c802c 40848512"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_frustum_axis(vec2, float, float)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "be17c8ac be987fc8 42733cca 42b47e45 -> c00ba0ce c08c4940 416b7f80",
+ "3f01644e be911c7a 421ac577 422f2bac -> 3fa4f7ee bf39028f 402331a8",
+ "3e9e77d8 3d84bf80 427011cb 42c34759 -> 40ba4f13 3f9c11f3 41967ce7",
+ "3f53028c 3ca8d400 429e7fe2 42faaf5a -> 4197f815 3ef32df8 41b85ef0",
+ "3e8d858c 3ee4afdc 42c7cad7 42fd4120 -> 406c704f 40bf084b 4155d924",
+ "bf29d94e 3ee14700 4095d287 4234a723 -> c156dd93 410e7e0d 41a1ecd2",
+ "bf221d14 3ee4f81c 422ef3f7 42b074ea -> c1616399 411f2b72 41b1f5dd",
+ "3eae2290 3e2ae048 424fe60c 42a28578 -> 409f5dc8 401c6241 416a49c8",
+ "3e23df98 3f43c12a 421b8b36 42acd010 -> 40735aac 4191595b 41be14ea",
+ "3e0f7e20 3d7e7460 426d78f6 428b3832 -> 3f37b32b 3ea2e07a 40a3ddb8",
+ "bee53ad2 bf395966 3e806db5 414b1f91 -> c03249eb c09028dd 40c71c23",
+ "becfbcbc 3f0fa424 42360915 42bdbb2a -> c12034e3 415d8d38 41c56d3f",
+ "bf187b27 3f3b98c2 413e8dd6 423319b4 -> c11c9ae5 4140aba2 4183763e",
+ "bf396ea6 bf1e4fa8 42c1fc4e 42edf0c6 -> c0feb552 c0d9747b 412fd1e0",
+ "3da9ef10 bf32418e 428d3c99 42a18c04 -> 3ed7b651 c06246bd 40a27b58",
+ "bd80fbd8 3e291060 40408dc2 4245fb3c -> bfbb603b 407599cd 41b9f260",
+ "3f64bf40 be8b1e4a 40e730d4 418ec529 -> 4097da69 bfb8b4e9 40a9f1e8",
+ "3df56000 beaf8ce6 4044e6d9 41c4377d -> 3fa47b57 c06b5a4f 412b9aa2",
+ "3d18cf20 3d873d80 412cdbaa 42452b12 -> 3f37cb0f 3fa2a97a 4199f428",
+ "bd6b6f90 be946f56 4047f604 4121e0c8 -> be4dccc9 bf81c01c 405fc68e",
+ "3ef22598 3f0b0aa2 42215e33 4260cfb5 -> 40700a78 4089d511 40fdc608",
+ "3f5a3632 3e6d0910 42a0c521 42b9d3b8 -> 40aaddd4 3fb99b27 40c874b8",
+ "bde9e630 bf02cfb6 421bee73 422653a4 -> be17f727 bf29fa43 3fa65310",
+ "beb001b2 bf261d44 4227856d 428911e8 -> c0929b32 c10a5dc9 41553cc6",
+ "bf155da2 bf252960 428ac799 42bd9112 -> c0ed0eb6 c1031041 414b25e4",
+ "3e0bd408 3f6a27e0 42ba9c7c 42f27372 -> 3ff3ffbb 414c4cbe 415f5bd8",
+ "bdfffbd0 3dcd3300 42aebfe2 42dbe28c -> bfb487b4 3f90b700 41348aa8",
+ "be21a2f0 be3a08a4 42721504 429084ef -> bf6d2f01 bf887df0 40bbd368",
+ "bf79c6b4 3f19a956 4195ce4b 420575c4 -> c0e488af 408c97e2 40ea3a7a",
+ "bef02888 bf3f744a 428b7310 4299fa9b -> bfda15f3 c02ddba5 406878b0",
+ "bf45c632 3f256792 4204ae26 427a13a9 -> c1356403 4117b3d8 416acb06",
+ "bee4947c bf7a88d9 41fcdd83 428d1f8c -> c10b1fed c1987cbf 419bd056",
+ "bf7ffdb2 bf59056b 4209803f 4296f458 -> c1a466f6 c18b6003 41a46871",
+ "3f31cdb0 bf162ba2 41eba360 428e5e1a -> 4167dc84 c143d3b9 41a6ea84",
+ "bf12cffa bde79780 429bdf13 42c07fc2 -> c0a80b2c bf848aac 411282bc",
+ "bf2bc738 3e951ac4 4216b03f 42ac28b8 -> c181ed5a 40e18e20 41c1a131",
+ "bf7af105 3f3b0e3e 405e1279 41be3b90 -> c11f4361 40ed6f39 41227941",
+ "3f440d4a 3f2c0f80 42536360 42948488 -> 41032e9a 40e64207 412b4b60",
+ "bf6f7708 bf258258 4104feb9 42451c01 -> c19946e2 c153e0df 41a3dc53",
+ "be84ac8c bf03a11b 4295184b 42d0c990 -> c0777d1b c0f58a39 416ec514",
+ "3f0aca06 bf48a0bc 422af603 4291f7b8 -> 41032bd9 c13d9da4 4171f2da",
+ "3e328070 3f61aee8 420a3d7c 424e19d3 -> 3fbd4501 40ef4c17 4107b8ae",
+ "3f6e5f90 3cdd50c0 42a12163 42d1826d -> 4134311a 3ea74c21 41418428",
+ "3f0513b8 3f09bdd4 42a47018 42b51baf -> 400aa6e3 400f8305 40855cb8",
+ "3f35b748 3dd9c620 423b752b 427896c1 -> 40ad920d 3f50031f 40f48658",
+ "3e563d70 befef2ec 4224cf24 42806efc -> 401a14fa c0b75c22 41381da8",
+ "3e978fa4 3ef58e28 4183d69b 41ec841a -> 3ff7e448 4048d056 40d15afe",
+ "be668a6c bf5243aa 42862c22 42af0de5 -> c01343c1 c1065001 4123870c",
+ "3f317786 3f60eea0 42c21336 42fe95de -> 4127ca5a 4154aae9 41720aa0",
+ "bf6b19fb 3e7c4e70 40b75480 41e08196 -> c1241672 40301883 4132ac76",
+ "3d566600 3e4e0b70 40e01315 420c830f -> 3f3c70c7 40351923 41610159",
+ "be972cba 3e595060 421403bb 42547fd2 -> c01851d7 3fdaf5ba 4100f82e",
+ "bf7ac68d be986ae6 41d3344b 428dd576 -> c1ae6e7c c0d408a1 41b210c6",
+ "3f5ff22a bf2111fa 42a37d7b 42f5b739 -> 418fdc29 c14ef05b 41a4737c",
+ "3e9784b0 bdf25b88 425035de 42adce10 -> 40a50323 c003f882 418b6642",
+ "3eb78af0 3eacafa8 42a98098 42d3510c -> 406fd5a4 4061a5f7 412741d0",
+ "bf4a56ab 3cda9740 42af4619 4308682f -> c19a3040 3f2692bf 41c3148a",
+ "bf2c07f8 bf47954e 42a427ad 42cee55c -> c0e5c631 c1054982 412af6bc",
+ "bf496c83 bf06f358 41b9fd15 42870695 -> c18b4f88 c13aabeb 41b10ea0",
+ "3ec12094 bf5185d6 3effe07d 42245343 -> 40f4eb3b c184db0a 41a25382",
+ "be28ef70 3f7f1e4c 4089242a 421538d2 -> c02e51b7 41839fda 4184144d",
+ "bf1a19d3 3e3b40f0 406e5689 40ac3343 -> beff6145 3e1b292a 3f541ffa",
+ "bf440b63 bf547daf 42844f0f 42ad289d -> c0fa430f c107a0df 41236638",
+ "3f5a3ebe 3e4b30f8 4270279a 429f131f -> 4104fbea 3ff79f5d 411bfd48",
+ "bf2284ac 3ebea60c 42ab88fa 42c60276 -> c08674c7 401dbab0 40d3cbe0",
+ "3e85d9e4 3b5dd800 42a7d669 42b1c841 -> 3f266382 3c09e2b8 401f1d80",
+ "3f590426 3ea264f8 42b405e2 42fb189e -> 41710021 40b4578d 418e2578",
+ "becca63c 3f22ed84 428c40f6 42df66d2 -> c104f053 4153ac69 41a64bb8",
+ "3e8456c8 3e9ec248 425f0dbc 429a85de -> 4031d07a 4055501b 412bfc00",
+ "bf7bbec3 be722d40 428841a4 42cbfc38 -> c18534ce c08024b1 41877528",
+ "bd20a3d0 bebe44b4 424d8b6f 42ad20b4 -> bf30978c c0d129a4 418cb5f9",
+ "3ecea70c 3f2794f2 40ffd22d 41ba31a0 -> 404559d5 40a009ef 40f47a2a",
+ "3f31720c bf71cd69 424b261a 42b7b852 -> 4163c175 c19b2dff 41a44a8a",
+ "3f2700ba 3f71f442 3eaf0261 41a74166 -> 40d6a6ed 411b7e85 4124855c",
+ "3f4c4b30 3f0547d6 42b72e44 42c270ae -> 400fc3b1 3fbb953d 403426a0",
+ "3f42f2c4 beac0d14 42585b71 42904c15 -> 40dc0a14 c04231f4 41107972",
+ "befc61c0 3f33cefe 41efaaae 429cfe01 -> c13f6833 41885e05 41c226ab",
+ "bf2948a6 3ed5e6dc 41d98f80 428b50bf -> c160a1e4 410deb57 41a9d9be",
+ "bf7b6a09 3f00a056 42a034cb 42c41529 -> c10cef61 4090353a 410f8178",
+ "3f18ad5e bf75a29b 41fdc3e1 42268e4a -> 403d4999 c0984493 409eb166",
+ "be9664e4 bf17e9c6 411bed8e 4251ddfc -> c0c8c83c c14acf68 41aae298",
+ "3f7e5c58 3f2875ec 41da8418 427f78b6 -> 419146fb 41406e73 419236aa",
+ "bf0325a4 3ce5d340 4283671d 42d19a32 -> c1203e8d 3f0c6873 419c662a",
+ "beec3406 bf39f6a2 41c6ffb6 42620997 -> c0e98161 c137d6e3 417d1378",
+ "3f680108 be435a7c 416ed143 4260cf2d -> 4195a102 c07bfba2 41a51adc",
+ "3f368ee2 bf6e78ab 42aa276b 42cbf7e9 -> 40c0e8c9 c0fbfe2c 410741f8",
+ "bf249ab8 bf757579 415dace4 427e1ca5 -> c17f837d c1be82f9 41c6b16c",
+ "3e695478 bf4f8885 40f2d040 4157a536 -> 3f2bc962 c018cb4c 403c7a2c",
+ "3dfe64d0 bf77e080 42afc718 42c28634 -> 3f1507fd c09136a5 4095f8e0",
+ "bd37a000 bf529dae 42878ea9 42a5c796 -> bead6ca8 c0c6ea7f 40f1c768",
+ "bf427876 bebe6222 422a089f 422f8bd8 -> bf060128 be833029 3f306720",
+ "3f5a9770 3e4f4fa0 42832310 42b84bd7 -> 413590af 402c3207 4154a31c",
+ "bf4345fd bf145d29 42ae7578 42d2cf84 -> c0ddd43b c0a88a4c 41116830",
+ "bf1c4932 be9c129a 421dad37 424db4a0 -> c06a91fc bfea400b 40c01da4",
+ "3f3b0656 3edde9ac 41ffa937 4212a618 -> 3fdbf7d3 3f82802e 40168be4",
+ "3f2bce9e 3e9fce1c 42c33f2e 42c78a39 -> 3f3865d9 3eab842c 3f896160",
+ "be542948 3f4e6e34 4170117f 42453518 -> c06364f0 415d4086 418930b8",
+ "3f66233c 3f6909c8 41cb5f08 426bdd19 -> 41713ed7 4174493a 41862d95",
+ "bf4b8160 be4aca74 42acecef 42f5f9ba -> c168483f c0677775 41921996",
+ "bf7c7be8 3ebb0e44 42592cce 4281ad99 -> c0a66854 3ff691e6 40a8b990",
+ "bcb2c3e0 bf41e54c 426714dc 42d32d26 -> bf0590a1 c190deab 41bf4570",
+ "3eecd270 3ee569dc 4221b857 42954487 -> 40fd21c0 40f5368e 4188d0b7",
+ "3f0d3f2e 3f3c9fe8 41ac3f17 42789124 -> 41334150 416f61c7 41a27198",
+ "3f7d4d50 beb24e20 429838f3 42d3201f -> 41692102 c0a41ada 416b9cb0",
+ "beea262a 3f41a05c 4239dc40 426dad4a -> c03d9333 409cc437 40cf4428",
+ "3f54a71a bee34bac 401e42f6 42426e22 -> 41994ab2 c123d8df 41b889f3",
+ "3da16450 bb107200 41836eae 41f7e966 -> 3f12dda4 bc8371cc 40e8f570",
+ "3e6fe6d0 3eca40c0 429ecbbc 42be032c -> 3fea0736 40454d1d 40f9bb80",
+ "3c436a00 3d083a20 4192be28 422ad0ee -> 3e14c424 3ecf6a6f 4142e3b4",
+ "3ecc815c 3e8e5f7c 428ee8e9 42b8b6a7 -> 4085944c 4039fdb8 412736f8",
+ "bf0fc8ca bd6a9190 42868a11 42b64f2b -> c0d6a48a bf2f154d 413f1468",
+ "bf36cc6b 3f51e524 410332cb 424ec1d4 -> c1786e5b 418ea0d5 41adf521",
+ "3f1fc2ce beef46f8 429b6028 42b6811b -> 408770de c04ada41 40d90798",
+ "be1c2fc0 bf20420e 414f4c93 42383a1f -> c0218ee5 c125c50c 418466fa",
+ "bf1a4ea8 3f15f628 41a97a22 4280cd59 -> c15064e0 414a866d 41acdda1",
+ "be0941c4 3f47cd92 41ba834e 4254bfca -> c0002266 413a8603 416efc46",
+ "3de6ee40 3e84ae00 40fdb38b 41a572e3 -> 3f3810ae 3fd381c0 40cc0c00",
+ "3f2d7100 3f3fd6aa 423f7301 42ac2b6c -> 414f2aea 41652463 4198e3d7",
+ "bda2ca78 3e314950 427d1173 42cefeff -> bfcca9ec 405ee344 41a0ec8b",
+ "3f19d2da 3f2ee608 4231cf97 4235f24f -> 3e9f09fe 3eb4d419 3f045700",
+ "3e843c50 3cebf5c0 427bedb9 42e0237f -> 40cad894 3f34fa6f 41c45945",
+ "be16ca9c bf22219c 420c9548 42922f0d -> c032cf98 c1404205 4197c8d2",
+ "3f35995a bee54f8c 41ffb807 426701fc -> 41125745 c0b8ca09 414e4bf1",
+ "3f0caa00 bf20fffe 42b561e2 42cd5623 -> 405297bc c07109cb 40bfa208",
+ "3f3f7ab4 be4e5dfc 4203d740 426cccc9 -> 411d0300 c029383a 4151eb12",
+ "3e9ec344 be5de11c 424d8e29 42c491b0 -> 40e8aa59 c0a294c3 41bb9537",
+ "3b7cb600 3e8e2bb0 42bb7b73 42fe5512 -> 3d83fb7e 4094807b 4185b33e",
+ "be70d054 bf1065ea 42a77784 42d08a6c -> c01a8c99 c0b957e4 41244ba0",
+ "3f0b7982 bf07c1a9 420f10ad 4283dd3e -> 41037af2 c0fff34f 4171539e",
+ "3f5126f6 bf01c0fe 42b7bb5f 42f8f010 -> 415517c4 c10432d6 41826962",
+ "3f3dcbdc 3f5f33cc 421577ba 4289153b -> 4138e683 415971d9 41796578",
+ "be9057d4 3f371546 42614022 42c6628a -> c0c16b41 41755494 41ab84f2",
+ "be9c7dbc bd4779e0 41dc58fe 4260304c -> c08b64a1 bf31ae78 4164079a",
+ "bebb7f06 3c680400 4220b867 42b1cd36 -> c10ebbcc 3eb09fe0 41c2e205",
+ "3e1cabf8 bf694589 41be9737 428489ec -> 404fd024 c19ab55c 41a9c83c",
+ "3cf42b00 3f57e968 429d8c8f 42fb34a0 -> 3f32a7d7 419dfb15 41bb5022",
+ "3f3b1b5e bf2ec8bb 427ed4a0 428cdf91 -> 401d616d c01303fa 40575410",
+ "3e289200 beb77d5e 4258233a 42961f9b -> 3fdd8955 c07124c7 412837f8",
+ "3efd2e18 bf3259d8 427b1ccc 42bdd57e -> 40fe4756 c1331ff7 41808e30",
+ "3f095766 be7f9054 428fe04a 42c9b726 -> 40f83dd6 c066f684 41675b70",
+ "3f1002aa be59a690 4280f09d 42b1f318 -> 40dc8f3e c026abf6 414409ec",
+ "3e978930 bf7b2d7e 42b55f27 42b9672e -> 3e98b94c bf7d2591 3f8100e0",
+ "bef54eda be8975da 41d4da38 422ede41 -> c0832aba c013003b 4108e24a",
+ "be5185e0 3f3a99f6 42acd956 43015537 -> c08c792b 417a361f 41aba230",
+ "3f7fb000 3f79310e 42bdcf12 4301c50e -> 418b4a7f 4187c093 418b7614",
+ "3ee48884 bebab0f6 41a0f8c9 425afa66 -> 40f74428 c0c9fe92 418a7e02",
+ "bf63ba4c 3f6299ca 402ef8e6 420dbda3 -> c168b7da 41679106 4182ce15",
+ "3f3a8f56 befa9026 4184dc1b 42204c1c -> 4108cfca c0b7bf6a 413bbc1d",
+ "bd8aecc0 bf1746f6 41a1ab23 41a440c4 -> bc338655 bdc37cae 3e256840",
+ "be0bdccc bf70bfbd 41434a4a 4276919c -> c0581290 c1b9f735 41c5bf0a",
+ "bf43538d 3f3cf792 42ab3bd4 42c7313f -> c0aaa884 40a51a23 40dfab58",
+ "3f751c70 3de6b180 41addd8e 4204e810 -> 40b012b9 3f25b760 40b7e524",
+ "bed36fcc 3ec65c8c 42b094dd 42f88ee0 -> c0edc9fd 40df158e 418ff406",
+ "3eb63d04 be7a130c 429c5a2a 42f87870 -> 410326f5 c0b3f8d6 41b83c8c",
+ "3ece2858 bd94f9b0 4239a623 42b1fb68 -> 410927c2 bfc63983 41aa50ad",
+ "be940198 3f3ff07c 428d23ce 42b53f58 -> c039815e 40f091ca 41206e28",
+ "3f4b060a bf37ea32 3f1cd876 41a428fa -> 40fc9a85 c0e4d40c 411f4236",
+ "3f376520 3ef2a624 419b2bd1 42350fdf -> 4114421f 40c428e5 414ef3ed",
+ "3f7ef662 3f2eb48e 42c1ed34 42ca22da -> 4002d216 3fb34823 40035a60",
+ "bf6c6b92 bd45d3d0 42aad96e 42afa1b7 -> bf8d54b8 bd6c8549 3f990920",
+ "3ed9f93c 3f0ad63a 4247c26f 42bb0df0 -> 4114738f 413d1c3a 41ae5971",
+ "3d91d0b0 3ec03160 41893184 422d479d -> 3f6e8180 409d2eaa 41515db6",
+ "beddd444 3daecd70 410e8fe1 41ef44a6 -> c0919073 3f656925 4127fcb6",
+ "bf24bd91 bedde044 42c19f44 42f3b036 -> c100dfb8 c0ad91f4 414843c8",
+ "bd829450 bee71b20 41c3809a 4221c82e -> bf02a463 c0673793 41000fc2",
+ "bf2ef3e7 bf6d4852 42a79ee3 42aa198f -> bed8decb bf131122 3f1eab00",
+ "bf25ab61 3f000e1c 425eccd7 42bdc2e5 -> c14ad83f 411cca3a 419cb8f3",
+ "bed0ea42 bf5da984 42a761bf 42d1ed80 -> c08ae1ee c1135b47 412a2f04",
+ "be2c0a60 be96e360 41b4ffd3 42908104 -> c0856778 c0ea011b 41c6821e",
+ "bf7e61bf bf0a16f6 4269e295 42a3e80a -> c13aab02 c0caa9cd 413bdafe",
+ "3e7094f0 bec2ba28 41a7b4e4 4284e83c -> 40ab0082 c10a68c2 41b5f606",
+ "bebb477c 3dc98d20 41fcf611 428e616f -> c0e79558 3ff93b51 419e47d6",
+ "bea32a32 3f2d3468 428efca8 42b598e6 -> c044dec5 40d0fbeb 411a70f8",
+ "bf3036a0 bf14a340 4298d55d 42bae828 -> c0bba187 c09e44bf 41084b2c",
+ "3efc7c88 bebd459a 42875380 42eabff6 -> 41441e43 c1130436 41c6d8ec",
+ "3f4ee8ba 3ebf0d3c 429d2429 42ec5dc0 -> 418010bb 40ec8041 419e732e",
+ "bf43ed09 bf1c7a99 41adab8b 42454501 -> c12909f6 c1070157 415cde77",
+ "bed63ca4 3f5520ac 42a5274a 42bd36fb -> c0211688 40a04103 40c07d88",
+ "3f1c0bde bf4713f7 41bedf01 420b8f88 -> 40572c82 c089415b 40b0801e",
+ "bf3f17f1 3ed61908 42a9b8d8 42c1ae94 -> c08f14a7 40204e17 40bfade0",
+ "3f6ae0ce bf5cb68e 427b0981 42af2326 -> 4136196d c12b1e05 41467996",
+ "3eb96e80 3ea54974 42374b16 42454240 -> 3f21da49 3f1044fe 3fdf72a0",
+ "bf79d51b bebc2d80 41a5ad94 427a6422 -> c1a383f5 c0f65328 41a78d58",
+ "bf072368 3ebc7530 4289a963 42a825d9 -> c080becd 40338ada 40f3e3b0",
+ "3d106a00 3ec62078 42ba317f 42ce0722 -> 3e330622 3ff59c01 409ead18",
+ "3f7e8708 3f6e792e 4145c6c1 42063d7a -> 41289dd9 411dfb33 41299794",
+ "3e485ac8 bf342532 4229fcee 42b4e8ff -> 4096227b c186fdaf 41bfd510",
+ "3f7a7b5a bc80b840 4091f600 42002ba6 -> 41571ca0 be5d1643 415bd9cc",
+ "bf593b94 be882d14 407616e0 4234bc91 -> c18c50bc c0afeb11 41a55b23",
+ "bf1e7870 bea97458 42a712a8 42dc9aa0 -> c1048c69 c08dbc5b 41561fe0",
+ "bf4022a1 be9dec1a 423695d6 42aca6ac -> c1743f48 c0c8c139 41a2b782",
+ "bf57ca0a 3dd6e540 42c2ea59 42c31cbd -> bd29e703 3ba932e0 3d499000",
+ "3f1ce76a bed77a72 41429625 41e5adc6 -> 40a247a3 c05edc6e 410462b4",
+ "3cb28100 bf443e14 422d8aa4 4295c9ad -> 3eafc322 c1413a77 417c116c",
+ "3e948938 bf5b4b2c 42c698d7 430e4b02 -> 40c791d5 c19351ab 41abfa5a",
+ "3ecf1d34 bf73354f 42555c0d 42806752 -> 400c9a74 c0a51b46 40adca5c",
+ "3f088c5e 3f19b8f6 4250272b 42a54fea -> 4102a681 41131533 4174f152",
+ "3f36ef6c bd79aaa0 42add5ae 42f7e184 -> 4153a6aa bf906dbb 419417ac",
+ "bf2ef7e4 3ef8147c 4193248b 428895e0 -> c1886b98 41416ca7 41c7997a",
+ "bf32100c bdcf9cc8 428256b6 42a4f005 -> c0c08621 bf60793b 410a653c",
+ "bf350d06 3f2d44d8 409438c6 418465ec -> c086dbc1 40810fda 40beaf75",
+ "bf2d6850 bf447af1 428bfd7a 42c0a8b4 -> c10eb4b1 c121b18e 4152ace8",
+ "3ef29b04 3f2ae38c 42bfcf13 42d2d6ee -> 40104799 404b421d 40983ed8",
+ "bd4f9f20 bf7ed451 413f7b7c 42469cc1 -> bf748279 c1960d6b 4196bde2",
+ "bf3e1b5b bed34eda 41210b20 41a3ba36 -> c07727dd c0095c0b 40a6694c",
+ "3f616006 bf3c0b4e 41df371d 42245354 -> 40b9a52b c09ae524 40d2df16",
+ "3dc95dc0 bf345e3e 42070986 423e1216 -> 3f2d2782 c09b191f 40dc2240",
+ "bf433790 3f751ee0 4299c5ab 42edd9dc -> c1803b42 41a102ee 41a82862",
+ "3ee74120 3f2105bc 419d3c89 421bf3c0 -> 408bb79e 40c291f9 411aaaf7",
+ "3f12d4c4 3d0ecba0 42accbc8 42d0aaf1 -> 40a498ad 3ea01289 410f7ca4",
+ "bee7c984 3e9cf444 428228c1 428f638c -> bfbfa773 3f81c734 4053acb0",
+ "bee1eaac 3e791150 401cd43a 42178132 -> c0fa1a14 4089dd98 418db3ee",
+ "3f7a2a9a 3f4be6ce 417aea88 42274712 -> 414c5517 41268b3e 415118e0",
+ "bf045fa8 bf5d68bb 42abbe5f 42b64789 -> bfae552f c011cb8b 402892a0",
+ "3e198bf0 3f4d73d8 3fbb7514 410ff586 -> 3f109500 4041751d 40710dc7",
+ "3f2eb558 3f0413ee 3fbaa46e 422de574 -> 41656449 412d6afe 41a81051",
+ "3f7c6be2 3f7d2276 4297ae99 42befd81 -> 411b08f4 411b7918 411d3ba0",
+ "3e6d08e0 3f4795e2 42841986 42a36922 -> 3fe7ee4a 40c349ba 40fa7ce0",
+ "3f5ebf9c 3deb2600 4274a97d 4275a1de -> 3dd81e06 3c6425e9 3df86100",
+ "bf7fb0ed bf052a03 41e61941 41fd31d9 -> bfb88bae bf403914 3fb8c4c0",
+ "bdf8c7d8 bf430cb6 42b98619 4303c3e8 -> c0179d1d c16dbcb8 419c036e",
+ "bdb3cc80 3f76e04a 41b10034 428badf2 -> c0060c25 41b80e6c 41bedbca",
+ "3ed65770 be8229a0 4283b920 42a09fd6 -> 404195da bfeb1db7 40e735b0",
+ "be884042 be9eb9ec 42b11fb9 4301065a -> c0ac48d6 c0c8b423 41a1d9f6",
+ "3f204010 be811206 424e774e 42549bba -> 3ef6133f be463248 3f448d80",
+ "bf0aedd8 bf674595 41e48d42 425e5793 -> c0ea9625 c1434154 415821e4",
+ "3e2ea390 3f52a086 411f81e5 4260958a -> 407c0229 4197f85a 41b8b511",
+ "bf5fca7c 3f22f41e 4288df74 428a32ba -> be944b2a 3e57f5d2 3ea9a300",
+ "3f2ffc6e bf0dda88 42064a3f 42792c6e -> 411df3cc c0fea296 4165c45e",
+ "3f74b4be 3e7561b8 42907e07 42aeb674 -> 40e718f0 3fe7bc4b 40f1c368",
+ "bf6b7567 3ef051c4 3f974b17 4242e5e6 -> c1aee931 41328592 41be2b8d",
+ "3e4ebc78 be148c08 41c2e30d 421256a8 -> 3f9df181 bf62f9b2 40c39486",
+ "3efe2594 bcb4b1e0 426c304c 42a57f3b -> 40bc3cf1 be85d5aa 413d9c54",
+ "bf14ca00 3f0b8f36 427acf0c 42c34cb6 -> c1227e9a 41186a2b 418bca60",
+ "3e216458 3eb994ec 421ca136 428dd78f -> 40203318 40b835ec 417e1bd0",
+ "bf61f77a beeb4772 425a123d 42a8948e -> c1523c74 c0dae676 416e2dbe",
+ "be8f880a 3f6859c4 42b23b4c 42b66dd5 -> be969d62 3f73d13c 3f865120",
+ "3f0a9422 bf537018 4167c522 42258246 -> 40e8e99b c131af35 415721fb",
+ "bf5b3136 bf75eb9a 419b2f2b 41fd2fc4 -> c0a7d2b3 c0bc4988 40c40132",
+ "bf4e1a2f becf79a6 4245ca10 4294b072 -> c1205b1c c0a16c91 41472da8",
+ "3eab10f8 beaa899a 417dd624 427aa221 -> 40fa2663 c0f96071 41bb2c98",
+ "be9f636c be68a384 4265bec8 427ee9b8 -> bf7ab715 bf36f7e7 40495780",
+ "3d4503c0 bf221db2 40e6a380 416628da -> 3e30c26b c01172e1 4065ae34",
+ "3f781fb0 3f03c248 41edee18 429ab35e -> 41b893c5 4144075b 41be6fb0",
+ "bf38aae5 bf616300 429a05e0 42f253c2 -> c17ecbb5 c19b7d34 41b09bc4",
+ "be6a1e04 bf4ca25d 42817f67 42d370fa -> c095e0d8 c18300f4 41a3e326",
+ "3f6707de bee0839c 42844c7a 42bbc892 -> 41484ab9 c0c2a46d 415df060",
+ "3d6319c0 bf17140a 41986a74 4206f01d -> 3ed0667e c08aa353 40eaeb8c",
+ "bf221b24 bd393260 41e1b567 4290323a -> c15e4f8f bf7dfa2d 41af89c0",
+ "bea9990a bf75074d 42911846 42c7c62a -> c090e5ee c15157ea 415ab790",
+ "3f2802c4 3f70f748 42c2b0c2 430058b8 -> 4122c477 4169721d 417802b8",
+ "3f6326f0 bf0497b4 426b1530 428a69b3 -> 4094280d c02cf683 40a6f8d8",
+ "bf5d6eac bd4d0b70 41fc2fed 42450c74 -> c0f57ef4 bee353d0 410de8fb",
+ "be2f5f84 3f339042 407736e8 4229e258 -> c05396e2 4158a528 419a6eea",
+ "3ce65840 bee6b42c 4262ddd6 42afb61a -> 3ee025b1 c0e07f24 41791cbc",
+ "3f29cdd2 3f5f3566 40ce83b3 4206846c -> 41103465 413d8edf 415967eb"
+ ]
+ },
+ {
+ "glsl": "vec4 cultmath_af_frustum_ball(vec2, float, float, float, float)",
+ "tolerance": "ulp-bounded",
+ "check": "enclosure and tightness: from the arguments (mx, my, z0, z1, fp, warpVariation) compute in double zm = (z0 + z1) / 2, h = (z1 - z0) / 2, axis = (mx h, my h, h), c0 = (mx zm, my zm, zm), |c0|_1 = |mx zm| + |my zm| + |zm|, R0 = z1 fp + warpVariation, spread = (|mx| + |my| + 1) h and d = |GPU centre - c0|. Enclosure: for z in {z0, (3 z0 + z1) / 4, zm, (z0 + 3 z1) / 4, z1}, eps = clamp((z - zm) / h, -1, 1) and the nine footprint offsets e in {(0, 0), (+-1, 0), (0, +-1), (+-1, +-1) / sqrt(2)}, the point P = ((mx + fp e.x) z, (my + fp e.y) z, z) satisfies |P - (GPU centre + axis eps)| + warpVariation <= GPU radius. Tightness: R0 + d <= GPU radius <= R0 + d + 2^-19 (R0 + |c0|_1 + spread). Report the least slack of each side; only the bounds fail the check.",
+ "cases": [
+ "beb93774 3f479b84 42ac6b83 42b7c51c 3cd0299c 3fe1326d -> c200da26 428add17 42b21850 40830530",
+ "bf0bca41 be0414a4 413e0a14 421625b2 3d3a525b 3fd1a94a -> c157dcfe c04bf558 41c5a837 40561d5f",
+ "be2dfb28 bd20c890 41ba4c99 426ca91c 3d11916b 3e13d8fb -> c0e024bb bfcf2405 4224e7b4 400fd0ef",
+ "bf050336 bf416fba 40abd67f 423f8aa3 3c52ce78 3fddf6e5 -> c15d5d01 c1a0f614 41d50573 40166bbd",
+ "beab56ce 3ed232e4 41f94c2b 4226e88a 3b49b3a1 3f4c257e -> c1432321 416f64f5 4211c750 3f6d0a86",
+ "bd0a6c90 bf3768f6 42b275bf 42dd3156 3c779517 3fb28b28 -> c058198c c28f2a26 42c7d38a 40443e5d",
+ "bf562c1f bf3e9d20 428c538a 42b7d32e 3d2c355b 3da1a394 -> c287981e c2715bb1 42a2135c 407c6148",
+ "bf06c83c 3d495200 424a1bb8 42507dbb 3c92c895 3e30dd85 -> c1d82d7b 40217301 424d4cba 3f8da95b",
+ "bedf47b4 3dea4fc0 42b684a6 430cd45f 3cf29681 3fd05290 -> c24a6cc7 41546d0c 42e816b2 40b989f1",
+ "bc98d6e0 bd7f3840 427dc08f 42e25e16 3d1ff754 3fcd4cb1 -> bfd2e587 c0b0155f 42b09f2f 40c0c750",
+ "3e0cc908 bf77e4d2 42169549 429336ce 3ad13ce8 3fc48f94 -> 40f4bb0a c25775c7 425e8172 3fd39ed2",
+ "3f5a8534 3f79c588 41904b3a 4233197f 3d025c9d 3f951e59 -> 41d67679 41f5223f 41fb3f1c 4025c4ef",
+ "be843dbe 3f1c5522 41e1e573 41e74a7f 3cfb9dde 3fbb346c -> c0ec2afd 418b98a1 41e497f9 40167043",
+ "be8d0848 becbd22c 420b8a6a 42387c7c 3d3e5397 3f80a1cd -> c1328248 c180fdbf 42220373 40497ac9",
+ "bce1c4a0 bc881460 425c50bd 426c09e6 3d3fd46a 3fd4fcb5 -> bfc93b16 bf729479 42642d52 408daf50",
+ "bf5f873d bf539164 420b15f6 429f7baa 3d317033 3fd32033 -> c247f9c7 c23d468c 426506a5 40a3542c",
+ "3ea78e58 3d100da0 42460993 42acb84e 3baed6c5 3f3d0ca9 -> 41b1db73 4018e8d4 4287de8c 3f998521",
+ "3f5049d0 3efd37b0 42b84bc4 42d94f6d 3cfe7cf5 3fc93df3 -> 42a360f1 42469edd 42c8cd98 409e54ec",
+ "3d838380 bd394970 42ab17c6 4302af48 3d01b716 3f7599e8 -> 40de2ab3 c09c80ca 42d83b2b 40a323fd",
+ "bdbd6ef8 be9f91e6 410c1800 4251b393 3c40169e 3f89cd8e -> c0351716 c1188abb 41f4b993 3fd87c82",
+ "bf10a6da 3f325cf6 40a72cca 41b4df4e 3cc174eb 3f8c8cba -> c0fba210 411b2368 415eaa80 3fd0e5da",
+ "bf07755a bd69a9b0 42bbda82 42e98f00 3c8fc0f2 3e447cb1 -> c25efbd1 c0c0522e 42d2b4c1 400f71a2",
+ "bf06d1d0 3e805228 419d7836 4289439b 3c82b697 3eba4523 -> c1ba0ac3 41311307 4230a1a8 3fbac19b",
+ "3e2606c8 bf300516 42ae4131 42faaee0 3ce02564 3f6b16fc -> 4189cb76 c29216be 42d47808 408b2388",
+ "3f740cf6 bf2dbbf3 4235dff5 42b1ad60 3cb6fbf1 3f859f2c -> 428009ca c2364b8c 42864ead 4041d367",
+ "3ef3c748 3f149d80 41e447ef 4298b35e 3cd52c7a 3f035b85 -> 41c7c1a0 41f38e4e 4251c55a 40200124",
+ "beba6cf4 3df2ad50 41dd6801 4239343a 3b9deba9 3e98a6a8 -> c1577caa 408c40ee 4213f41d 3f057769",
+ "3f319c28 bf5983db 414dc001 424b52a8 3d088c06 3c70151e -> 41b0bffd c1d87638 41fec2a8 3fdaca80",
+ "bedd8910 bd4e8780 402f41d6 423fe7d2 3c709bfe 3e1d2890 -> c12f8c7a bfa3a85a 41cadbef 3f5bace9",
+ "3eab28f0 bdbf87b8 41f230fb 426f89ea 3c987015 3f1f037d -> 41711e27 c086e82e 42345134 3fde273c",
+ "bf4f6bbf be871b00 402ba770 41bc66f4 3d135757 3f8f3499 -> c12a091f c05d822d 4151dbe2 3ffba594",
+ "3f1f6362 bee0e2b4 412ac288 42669665 3d0783f9 3fc22ddd -> 41aa2535 c1701028 4208a384 405b2906",
+ "3f4fce44 bf1526c0 40c83c1d 42297468 3d3be7d9 3f713bab -> 419ddee7 c1629f21 41c27bec 4038b20b",
+ "beac9b74 bf10c054 42460bd3 428fb732 3cef6e3e 3ff88909 -> c1a3aa75 c20940bd 4272bd1c 40815852",
+ "bc11d3c0 3f2aa972 42476339 4270ffbb 3c6e08a8 3e07aa63 -> befadc50 4212ca9a 425c317a 3f81036f",
+ "3f68b660 3ee73abc 419752d8 428660ac 3c64828b 3fb9fce5 -> 421c8b0f 419b8bae 422c3562 4018fa46",
+ "bf40e876 be1014ec 420ec5e5 42803a48 3d422fcf 3f4577df -> c2166b2e c0e0b182 42479d3a 4073e827",
+ "3f4d90e2 be9f8ee6 42a2ca8f 42bd987f 3d4c91b1 3e2b3ae6 -> 428d7b61 c1dba239 42b03187 409cdcde",
+ "bf78447c 3f63e128 42568b5f 42be5d27 3c56c5e4 3e9d4f0b -> c29052af 42847895 4294d16b 3fc71157",
+ "3f21c5f4 3e979ec4 429ce991 42a26e8e 3d3ccbb1 3fe2b39b -> 4249cd5b 41bd2308 429fac10 40b07899",
+ "bf608c53 3e53c6e8 42c63fd9 42ca3a36 3d49b9cc 3fef69da -> c2afa329 41a5a5e2 42c83d08 40db36a3",
+ "3e0fb508 3f617d72 42ba4080 42dbc6f9 3cf59d8c 3f79b32e -> 4163ed4c 42b2d1c3 42cb03bc 4088a682",
+ "bf452fd3 3f06b6c4 41d7f3ad 4201cc2d 3cdfbc25 3ef54841 -> c1b725cc 417a3ece 41edc604 3faec4af",
+ "bf2f9462 bf0b713c 42a6ec81 42d05f15 3c1f42c9 3f3029e8 -> c280b319 c24c6c0b 42bba5cb 3fd9bdaf",
+ "3d789820 bf40b31a 423a4280 42413e1a 3bf7b902 3fa12268 -> 4038430c c20ed4fa 423dc04d 3fcfe4d6",
+ "3f6263f8 bf5d122e 424b6081 4294c5cc 3cd00747 3f30782e -> 425d7e05 c25849b2 427a760c 40250638",
+ "be582edc 3f394c08 420ff1fe 429fd4c8 3d0f04c4 3def73ea -> c143c00e 4227c88d 4267cdc7 403a13c0",
+ "bf31f656 3eb84d60 420ac126 42146ed4 3d12c17f 3f7ec31d -> c1c7a484 414ec149 420f97fd 4014c967",
+ "3f44d1c2 3ed40098 4125d51f 4216705b 3d37f058 3fb1acf8 -> 4193890d 411eea9d 41bfe5a3 4044ef5f",
+ "bf65d64d 3e9699c0 42247ae8 4292f6c6 3cd0fccb 3fdc7fd3 -> c24dc796 4186d642 4265343a 40663c1d",
+ "bd74fca0 3d913270 429e3976 42bc6a16 3ca17333 3f87d6fa -> c0a5dcfa 40c49aee 42ad51c6 403ac0b4",
+ "3f75a11c 3e9397c8 41cd91a8 428fd914 3d1271b0 3faef3fb -> 423b54b9 41612022 42433d7e 407c0ff2",
+ "3f42b820 bee2ce46 42542845 42b7aeb7 3c57ca93 3f8347ba -> 425c6611 c2005bbf 4290e16d 400f119a",
+ "3f7ee486 bd124650 422348f9 42b2657a 3bf90c98 3f628a92 -> 42817502 c014951a 428204fb 3fc811bc",
+ "3d5a96a0 be5236ec 4188e47b 42673c12 3cac5bc7 3fdc1d7b -> 3fffe2c4 c0f61549 4215d728 403be78d",
+ "3f5e3c98 3efd3538 420d5353 4270eccb 3ca7cae3 3ea62cba -> 4225eb0a 41bd0a6a 423f200f 3fc77917",
+ "beee0830 3f33896a 41e6321d 428b1d0c 3b666cc0 3e13359e -> c1b6dbf1 4209ec22 4244a993 3ec6e4e2",
+ "bf046bd1 3f6b742c 42c682b5 42f074ba 3d083a35 3f9e929f -> c2631076 42c9de2c 42db7bb8 40a79bab",
+ "bf2bf828 bee64aa4 421a4c43 42a6ee46 3d05206e 3d5dfbc1 -> c223f63b c1db9180 42741468 4031189e",
+ "bdbd9fa0 3ba7ea00 421a4d54 426004a2 3d1ed3ec 3ffedf4c -> c08c1d34 3e782546 423d28fb 4085367d",
+ "be8f0384 bf2b1706 41b437df 4229696b 3d4adaff 3ff79b62 -> c110fb0e c1ad716a 4201c2ad 40810693",
+ "bead5176 be70d0ec 42ae08df 42d2cfc6 3cd0a993 3f5293b8 -> c202466e c1b50296 42c06c52 40607c09",
+ "bf0c665e bf22b2e8 4225b59c 4268e255 3d14d4cb 3ec3020d -> c1da9a7a c1fd52b5 42474bf8 401fc6b6",
+ "bdcd22c8 bf490a04 42929fd3 42c9b82c 3d05380a 3e93ffce -> c10b90e6 c288c75c 42ae2c00 406474af",
+ "bd4f4c80 bf6d6f8c 411e268e 41d15b56 3b17125d 3fe7e95b -> bf698fa1 c185c20a 4190374e 3fefa3c6",
+ "3f0de540 3f5693e4 40f4d16f 41b1d604 3cbaecc9 3fe711e8 -> 41047ec7 41485cc4 416f0a60 40140051",
+ "3f31dc18 3f30a038 42c1e20e 42c46f83 3b942376 3f106dce -> 428796fc 4286a62e 42c328c8 3f811418",
+ "3eff5dd8 3f17cc1e 429960e7 42fac382 3d09c365 3f6f280e -> 42499235 426fa3b6 42ca1234 40a4d91f",
+ "3e6843b0 bf439a26 429b52de 42aecf62 3d380f96 3faaf06d -> 4195c32a c27c3ee0 42a51120 40a86d35",
+ "bef2f434 3f1e73c4 424e9dd9 425ea592 3d3ccbb6 3ff44845 -> c1cbb19c 4204d8dd 4256a1b6 408f2c65",
+ "3f3d114e bf7d59af 42078db7 42a430ff 3cf234a8 3f96df9c -> 422b51aa c2659136 4267f7da 4066cb73",
+ "bea83dbc 3f5e626a 42917241 42c49028 3cc87361 3fe195fd -> c1e0c40e 42948cc8 42ab0134 40855bd2",
+ "bf0ed226 be1a7200 3ffc94e7 41c42310 3d243970 3fda7216 -> c0ec7627 bfffb520 4153ec5e 402c22f9",
+ "be7a1ea8 3ade6400 4211f380 42881122 3d11f7cc 3fed1d3b -> c14c3da9 3db59918 42510ae2 4088dd6a",
+ "bf3db0ec 3e28d4b0 4009e2de 41b46c58 3ac8cc13 3fa552b6 -> c1127627 40025aee 4145a8b4 3fa9c03c",
+ "be685384 3f08eab0 42b8ab99 42ba34a8 3c0139bc 3e2ad761 -> c1a84a1c 42465b22 42b97020 3f66bd35",
+ "3f634258 3f120b50 41a56a6e 41ec67ce 3d02d71a 3fbcd80c -> 41b25ac7 41653ba8 41c8e91e 401ad6df",
+ "3ef5e84c bf4b9a14 427bfd9c 42d78476 3d476a0f 3f72a8dd -> 42240642 c287ce51 42aac1a2 40c63854",
+ "3e988e10 3f1fbb02 3f661fd5 420828f7 3d0fe944 3f57798f -> 40a690d8 412e667f 418bc176 40026a65",
+ "3e384a60 bf05ec1a 41eafa9d 4247e978 3d2afff4 3c8429d8 -> 40e47e15 c1a60b20 421eb363 4006929b",
+ "3e0cdec0 3f5b0f66 42b52601 42bd488a 3bcede04 3fb88fb5 -> 414bd6c6 429e7d6d 42b93746 400287f7",
+ "3f6a7484 bf1694c8 41d76892 42936300 3cd007d9 3d0503d9 -> 42384d7a c1ecbd8f 42493d24 3ff3b7db",
+ "3e96dd10 bf195004 42ac9176 42eb3b94 3d367591 3f9c1d0e -> 41f05249 c2743901 42cbe685 40ceb170",
+ "bed04296 bf080894 4273abdb 42b081be 3d1b83f7 3eddeca0 -> c1f2b4d5 c21e8893 42952bd6 40723364",
+ "3e8d1a6c 3ee52d34 40d403c4 41fe0380 3cae9efb 3feae97a -> 40a93922 41096c97 41998238 4020c6aa",
+ "3f14af90 3d828ac0 42be21ed 42d1f081 3cf992a1 3fb5d5bf -> 42685d05 40cc0232 42c80937 4093cc68",
+ "3f29ff00 3ea2cb50 42c391ff 430f3820 3d3ffb09 3fc48b82 -> 42a009ce 4219421d 42f10120 4103f9e5",
+ "bf16d3c9 3edac618 41f49d2d 42a05464 3a64023b 3f80648b -> c2027db3 41bd46b5 425d7baf 3f89566a",
+ "3dee2a10 3f6d44bc 420b5b1a 428a010d 3bbfed6a 3f99ae8e -> 40c13673 42407c67 424fae9a 3fcd6e65",
+ "be4e4680 bf74a6fc 4187d986 424db8e8 3cb60f5c 3f4d2946 -> c0dc7ead c202c233 4208d2d6 3ff8e5f7",
+ "3e9f5b9c bdb64b28 429c3058 42bf4ad0 3bf041d2 3ff99b99 -> 41d84dd6 c0f76f92 42adbd94 4029b1c3",
+ "bf5e668b bdcf2e60 426cfa3e 4285bf2e 3d22ceaf 3eed4736 -> c25b2154 c0cc2274 427c3c4d 4047c8ef",
+ "3e872820 be657680 41ee2faa 428fa72e 3c8c4c20 3db93d41 -> 41568f96 c13622c4 424b3318 3fa90b7f",
+ "3f52c3d8 3e958a78 428dbbec 42c61f12 3d41694e 3f6c6b4d -> 428be6d1 41c68649 42a9ed7f 40b33e04",
+ "3e0f2148 bf491c9e 4226d503 426ceab2 3d23a44d 3f961bd3 -> 40e1bc93 c21e9753 4249dfda 4062813c",
+ "3da93660 bf36bbc6 41ad1d7a 4249ffcf 3c5083bd 3f76ac89 -> 403ebb65 c1cdf8ff 42104746 3fcd9d0d",
+ "3f795bd6 3f358286 4263a898 4292d8ce 3d3db3f4 3f90e5e5 -> 427de9e2 4238d34c 4282568d 40910c56",
+ "3f51a9c4 be410e38 4187c269 41b63d02 3b2e055f 3fba37f5 -> 41823834 c06fcf3a 419effb6 3fc1f784",
+ "bec96e5c 3dee93a0 42884165 4294a60d 3d1f46ed 3fcc1e06 -> c1e02c8a 4104c1bb 428e73b9 408f84bb",
+ "3ec4f150 bf50fab9 424cae74 42864051 3d200ab7 3d9a884d -> 41b6030b c24122d8 426c978b 402cb23e",
+ "3defc120 3edc7f90 42823a49 4282d0a0 3cfa9ff7 3fa6c550 -> 40f47a1c 41e0d773 42828574 405375c4",
+ "bf77c0c5 bf63e8b7 4159405c 42595e82 3d2ef5be 3f792ff0 -> c2037704 c1f1dec9 4207d74c 4052dd5b",
+ "bd406fa0 3e272250 42900937 429e4a4d 3d0623c2 3f89de1b -> c0634276 41456101 429729c2 406ad29c",
+ "bed4152a bdbcf5b0 40b633b8 42209a8f 3b204455 3ef62701 -> c117eb82 c0075b3e 41b76106 3f143a2f",
+ "3f4f9118 be28d8f0 42129553 42664309 3d3540ed 3ea51280 -> 4218c644 c0f88d54 423c6c2e 4037abed",
+ "3f70ee96 3eac17ec 40ee2627 4207fc22 3d1e1936 3ed7dd77 -> 419bff53 40deda31 41a5c0e7 3fddefda",
+ "3f54978a 3f4ec216 429ef7d7 42d2b842 3ba6a59a 3fff106b -> 42998055 429549fd 42b8d80c 4021d78a",
+ "3e3d7048 bcc3ddc0 428ce853 42a0599e 3d04b365 3ec85cb6 -> 415eedd0 bfe67e2e 4296a0f8 403f4a4e",
+ "bf585aac 3dcc9ea0 422f3eaf 42b8e3d2 3ab7b03a 3f278016 -> c2664f31 40d9d161 42884195 3f48b5e7",
+ "3f76a5c6 3f3d2902 4285bb50 42aec8ba 3ba73b05 3ec6307d -> 42949f55 4263f6e7 429a4205 3f55544c",
+ "bedb8556 3e485ba0 4188b7ec 42838d2f 3d2d0d8f 3ebe683b -> c18e1d6f 4101b58a 4225bb2a 4049a980",
+ "be31c4d8 3f641b6e 42a20eda 42d4fa2d 3c3b596a 3fc01e56 -> c18236cf 42a7161d 42bb8484 402e0136",
+ "3ef9c38c 3f0d0a28 420dd712 4219cec6 3ba132d9 3f8f17e4 -> 41903912 41a2e213 4213d2ec 3fa750c8",
+ "3d940900 3ed834f0 429a1b82 42ab23cd 3c8c263c 3f2b704a -> 40bc1409 42095857 42a29fa8 40088f3e",
+ "3ee50578 3f7eecd8 428077ab 42cb1b6c 3ce157fc 3fe6ed0f -> 421450d5 42a5175b 42a5c98c 409321b1",
+ "3dadfe70 3c1db300 42a0c00d 42dcde06 3c3f254a 3f808872 -> 4101af8f 3f6b14c8 42becf0a 4012bb0f",
+ "3f270daa 3e7345e8 4280bed9 42b495ba 3d200d4a 3fb3a44a -> 4249daaf 4192f9e0 429aaa4a 409dd165",
+ "be6a5c60 3e0bf558 42016474 42856940 3c3ca9d5 3f00504d -> c1355c9a 40d89d8f 42461b7a 3fa27cd6",
+ "3f724698 3f581b5a 429a9eb3 42a59318 3d3319d5 3f473c1e -> 429783af 4287261d 42a018e6 408cbfea",
+ "be1d3608 bf44e19b 41ce2f46 42871279 3c4e13ec 3fd8c62a -> c0e534ed c20f85a7 423a9e4a 4022c2d7",
+ "3db414f0 3eaadb78 421ebfa5 42aa2e42 3d45f9f9 3fb8eb3f -> 40af8c4f 41a68e4b 42798e14 40b1d792",
+ "3f64d12c bf36e06b 4259a6c9 42c20414 3c406f8f 3f74a197 -> 428757ac c25856aa 42976bbc 4006182f",
+ "3f54c7e2 bf76dd24 42ba075c 42c0e7d4 3d20c5cd 3fc5c2d5 -> 429d7af9 c2b6b497 42bd7798 40aa98cd",
+ "bf79d640 bf6d471b 4299dfd9 42c105f3 3d1e6f2d 3fa08e3c -> c2a945eb c2a0c38c 42ad72e6 409f9b48",
+ "bf3ddbd2 be08fd58 427c5df1 42a7a33a 3c130b8e 3e6e3e20 -> c259e87b c11d3a70 4292e919 3f7c2e02",
+ "bf028302 3f7b6aca 4213be28 42998901 3d478dc0 3e69e867 -> c1e7de75 425f55e9 42636815 407dfe9a",
+ "bec73610 bd3826c0 4270d950 42b47a96 3d17b1ea 3e30018e -> c1ea274d c05873c1 4296739f 4060e5a5",
+ "3ed3e824 bf41e201 4289cde3 42a75379 3c2010f8 3fdb3e62 -> 41fc9330 c2671787 429890ae 4021f1b3",
+ "bda7b428 be94d55e 42049e0c 426588e4 3d28a965 3eda9dee -> c06d3e43 c1528c5a 42351378 40328ebc",
+ "bf58408b bf31de96 42b2c2f8 42ffad0c 3d1f9a0c 3f8893c2 -> c2b77e06 c296ec97 42d93802 40c18ddb",
+ "bf5100b0 3d850e40 42c0ffff 42ebbee9 3cf8dbc0 3ef823f0 -> c2af0481 40ded70c 42d65f74 408219aa",
+ "bf482807 bf4313b2 408e4c9d 4234f78d 3d1c6285 3f1d3875 -> c19b65f5 c1977467 41c6c121 4015dc72",
+ "bf288f7f be351938 41edac75 427f7d5a 3d0c4cbf 3fa6de3c -> c1f678ac c10466fc 423b29ca 405f7626",
+ "3f607de2 3f2b0fd4 41c0127a 427adede 3d43ad72 3fd2bd31 -> 42181ad7 41e7ce7e 422d740e 40949173",
+ "3f12272c 3f056ec0 4186f404 41c51d24 3d135beb 3fd25d1e -> 413d9499 412d1492 41a60894 4021eaa8",
+ "bf0f192a 3d94eea0 428bcab1 4292a1e0 3cd0c13b 3ed4adc5 -> c2201acc 40a6a1bf 428f3648 401229d5",
+ "bf420f7e bee1b144 424e0314 4293a7d7 3c19b606 3e192bd3 -> c23e0387 c1dcfc70 427aa961 3f57a5c1",
+ "3f20358e 3e92a1e4 426cc691 42719346 3c810e1e 3f52bf6f -> 4215ae1c 4188fedf 426f2cec 3fe32bea",
+ "3f558ebe be583418 423b7b4e 426be2f9 3d2a2f10 3ff1dbaa -> 423096c1 c132c6da 4253af24 408adff0",
+ "bed2c3c2 bebab636 42670414 4281b3a2 3d039af7 3fd89e6e -> c1c9e189 c1b2d787 427535ac 4071abf1",
+ "bf59dfb0 3f685d52 42204016 424ca320 3cf42fd2 3ee834c3 -> c21b45b7 42259976 4236719b 3ffd435e",
+ "3e5e0820 bf4b7d22 42b49978 42bd7cb6 3ce6a563 3f4f45c3 -> 41a07d7d c293163e 42b90b17 405e8cef",
+ "bf39b5ec bc81d7a0 4281b09d 42922916 3d44df9c 3f1fd4f6 -> c2481c5a bf8be90c 4289ecda 408462c5",
+ "bf0962ba 3f05f744 4232fbec 42a51f05 3c44529c 3f262924 -> c208a433 42053d7b 427e9cfb 3fd1baf8",
+ "be95f41c 3f75100a 428d3419 42d8992e 3d1e9de7 3ec397b1 -> c1d195aa 42ab41f0 42b2e6a4 40926f90",
+ "3e85b604 3f755b04 427f3a88 42c2756b 3c98da5d 3eedbe20 -> 41a838b4 429a5732 42a10958 4011d6c2",
+ "3eb2f588 3e3aa250 409c2745 41b8fef6 3caa9f4d 3ed835be -> 409c9cfa 4023546c 416008c7 3f676991",
+ "3c8ecf40 3f282566 42a67993 42acd3f5 3bae4b07 3f2d5800 -> 3fbd47b2 425edc73 42a9a6c4 3f9185eb",
+ "bed0383c bf3da053 420ed5ec 4243daa6 3d3a6cb7 3fe15722 -> c189bcee c1fae078 42295849 407f4d4f",
+ "be4e5098 beba23d4 428f32db 4296c437 3d31dd6f 3f9de0d5 -> c16ce95c c1d5bea7 4292fb89 4090393d",
+ "3d2c5d20 3f3582ee 4203ace0 42890859 3cbc16b5 3f95407b -> 4008977b 420fd746 424adec9 402f5071",
+ "3f08c3ee bd7eb730 4141a7dd 42039f68 3cc9078b 3f3d7c49 -> 41405d8a bfb32221 41b4095f 3fc61bdf",
+ "bef15490 3f3bda8c 420ac448 4239f341 3c4c019a 3f51c683 -> c1990e05 41ee4746 42225bc4 3fb2fe01",
+ "bc7b7740 bed6d128 42aed5bf 42d39051 3cbbbacd 3fa4f7ec -> bfbdc708 c2221e82 42c13308 406da32f",
+ "3f2b4bd0 be8997d0 40e02405 423385a2 3c5da86f 3ddbf1c9 -> 418adebb c0df1800 41cf8a23 3f36f42e",
+ "3d06da80 3e4b4ed8 4290a34a 42bbc33b 3d2cdbf4 3f8f9579 -> 402f195f 4183fdd5 42a63342 40a2aece",
+ "3f43e786 3f17f95e 42145e81 42463cce 3c73d1bc 3fa2bc16 -> 42049ee3 41cdc33d 422d4da8 4000936f",
+ "bf102cf4 3f42ef80 42800b61 42e2ae2e 39094534 3db0ed69 -> c247c6ab 42870e3e 42b15cc8 3dcfd452",
+ "3d8b2700 bf2c4a49 40e533e7 41b3c0b4 3cef34f2 3f93f7ce -> 3f80da8b c11f89fa 416d0dae 3fe7f41f",
+ "3ef87cb0 bf3136c0 421f26bf 4293fe2d 3d33ba2f 3e3d68f3 -> 41dce3d7 c21d884d 4263918c 405ba5d8",
+ "3ce3c580 bf7b0fa4 41a078e0 41bb2140 3d38406f 3fe3f7fc -> 3f1aa2eb c1aa72ad 41adcd10 40355445",
+ "3e96b57c 3f2a9824 401a92d9 4226bf46 3c912cf2 3f66c261 -> 40cfb487 416b1c68 41b06874 3fd1f369",
+ "bf6bd08e bf0383e8 42c6ccd2 42dea6e6 3bf68221 3f9395db -> c2c21c49 c258835f 42d2b9dc 3ffed12a",
+ "bf7dac27 3f324812 42124249 42177b42 3c385d33 3e584fd8 -> c2138446 41cf599e 4214dec6 3f23321b",
+ "3f774be2 bf143d3d 3fdab9ff 410f684e 3d0d205c 3fb099d4 -> 40a4f16f c045bf2d 40aabf8e 3fd821e2",
+ "bf2c3cc5 bf1a5bfc 42b7ea46 42d3b5da 3d16b21b 3f12ba3c -> c28516c0 c26e8c7b 42c5d010 408ef90b",
+ "be034ad0 bf3233ae 42c441e4 43079963 3c8b7830 3eab721a -> c16fbd4f c2a2b2be 42e9ba55 4029320f",
+ "bf75bff5 3efe8cd8 42a21bfc 42e01dcc 3c5b92bf 3f2e18d2 -> c2b96174 424004e9 42c11ce4 400ba786",
+ "3e2c0b20 3c0ccc80 3f1caacb 42269bf1 3d0b4e44 3d6e93a6 -> 40633a53 3e39f613 41a90e9c 3fbcc968",
+ "3ee8eeac bcc4de20 429d4599 42a6b4f6 3b8bbd28 3fb061fb -> 42136490 bff924f2 42a1fd48 3fdde59a",
+ "3f3fb12a 3b946700 4168ec2b 41f9d888 3cfefeb1 3e9e5531 -> 41892514 3dd458d5 41b7274f 3fa405c1",
+ "3d7fa4e0 3f05f29c 424b55b3 42ac6a3a 3d246d74 3fff2e99 -> 4088d9c2 420f68b2 42890a8a 40ae8a87",
+ "3e430bc0 befab05e 424bce8b 42735b1c 39cebbd9 3f732845 -> 412a58a1 c1daf15f 425f94d4 3f7952e7",
+ "bed1a648 be8c4828 42bccabb 430033e7 3ce61b68 3ebc9811 -> c2364bb7 c1f3f51e 42de9944 407e0f27",
+ "3ebd27d8 bea0f18a 424fc62a 42c0ed2b 3ce1c918 3efd3da0 -> 41db4ff1 c1ba9a34 42946820 4049d249",
+ "3a624800 bea2133a 40de284c 41ac8155 3d333e42 3fd6401a -> 3c499235 c0906058 41640b68 402784ba",
+ "bf745fdc 3ebf2c24 414c44af 42363a55 3b9474de 3f81446b -> c1deb352 412e378f 41e94b81 3f9bb2ff",
+ "3f2a1498 3f40d030 428c6c9b 428d46ae 3c3a0689 3f5947d8 -> 423b27b7 42542b8c 428cd9a4 3fd35245",
+ "3d24a2a0 3d74d7e0 42410aa5 427f509e 3d23b2b6 3fb86f76 -> 40102ba5 40566889 42602da2 407f7b74",
+ "3efaf950 bf1a74d0 42bc4885 430e2b5e 3d04fa77 3f0ed3fd -> 4267abe6 c28e93ba 42ec4fa0 40a58fc8",
+ "3e8aec78 3e9036ec 41a9a808 4208f734 3c2adca7 3f6be777 -> 40f0b8d7 40f9e3ca 41ddcb38 3fa3aa8b",
+ "3f5b4bba bec9c3c4 42185695 428f62ff 3c109cd0 3f236f01 -> 423c13ac c1ad0a9e 425b8e4a 3fa2bc1a",
+ "be9b85de 3e8ee0b4 41dbf470 4245ca5e 3d2ce420 3faf2f7c -> c13af8f7 412bc530 4219e24b 405d2d3d",
+ "bd109500 3eb4a2c8 413d15d4 4184723c 3c982e35 3d27800b -> bf003283 40a02a54 4162fd26 3eb26a63",
+ "3f07cad4 bf1f20d4 42594f74 428f78f0 3ce07f18 3fad37d6 -> 4205bcfc c21cb89e 427c20aa 40546f6f",
+ "3f4a8690 bf602cbd 4079e83e 42393125 3a905b89 3f655a30 -> 419edd69 c1afd8cc 41c8cfa9 3f726fb3",
+ "bed34890 3e12bcb8 4285fc93 429e1bec 3b861989 3fec2d79 -> c1f112fd 41276d4d 42920c40 400acd4a",
+ "bf69651d 3f322b4e 420e4301 422edf06 3d454267 3ea33366 -> c210909e 41dcb74f 421e9104 401b273a",
+ "bddc3ac8 bec683a2 420e0944 4241794b 3cc44bfb 3ff8e255 -> c090509f c18215c0 4227c148 40469f7e",
+ "bf2d3a2e 3da84dc0 41d907fe 4212b708 3ccb4be8 3d11ada8 -> c1acb4e5 4027cc41 41ff3b07 3f722439",
+ "3f55fb22 3e2464b8 42973494 42dd9210 3d1f2127 3e66d9c7 -> 429bcb7b 416f61eb 42ba6352 4090f2fb",
+ "bee02208 3a176800 4277efd9 42ce992c 3bf0d5c9 3f0b6234 -> c210b573 3d4381e0 42a5488c 3fa6e3d9",
+ "bf787730 bf047732 426eb818 428ad92d 3b2b76bd 3f85b4b1 -> c27a9bc5 c2059baa 42811a9c 3f9cf9ff",
+ "3ea96870 3e519760 41b57ef0 42277610 3d38bb0e 3ef6d3f6 -> 412adead 40d36662 42011ac4 4017b2c2",
+ "beb61442 3e8dd7c8 4269c050 4276f710 3d0ca7de 3f753c8c -> c1aaf434 41852d19 42705bb0 404501d1",
+ "bf252c98 bf4b5965 40f73567 42214768 3c84e9bf 3f7fdda2 -> c177fe5b c198a7a6 41c02e15 3fd3ae05",
+ "bf2a9b02 bea344c8 40e78f6a 419addcc 3d34a200 3f6cf67b -> c10dc96b c087b076 4154c1a6 3fe3c274",
+ "3da37ce0 3e75b248 41815ab9 41a24ff5 3c47c0c4 3ef29ac7 -> 3fba43f3 408bf6bc 4191d557 3f38a24b",
+ "be7e57a8 3f6f129a 424477fb 42ad1106 3cd79773 3fe49a5f -> c186c5a8 427d5c9d 4287a682 408207f1",
+ "3f155802 3d8d4400 4287c1af 42bb3d82 3c9cbada 3e8d58d5 -> 423c6d91 40b23c59 42a17f98 40044fb3",
+ "3d6b9600 bf11cc60 42a2dc82 42b0ed4e 3d05084b 3dade129 -> 409c58ad c2418493 42a9e4e8 403d535f",
+ "bf1bb265 be8c64fe 42b7a4ce 42c153d5 3ac3da35 3fb5ba02 -> c265453d c1cebcb1 42bc7c52 3fc83cb3",
+ "bdc94cf0 be1d647c 42902bff 42dc811f 3d2cd19e 3f104d53 -> c10f60c3 c1603550 42b6568f 40a6e617",
+ "bf56f174 bf0521ba 421eb82a 4264277a 3d0d7435 3fb81f66 -> c22269eb c1c93128 42416fd2 405a232a",
+ "3f7a0474 be112800 426724ba 4285ec44 3d303663 3fc9e520 -> 4273aa00 c10d77b5 42797ea1 408ea94f",
+ "3f247e5a 3e9bb208 42bfd6c4 430e9712 3d123fa1 3faaa130 -> 4299414a 42110eda 42ee8274 40cd95b6",
+ "3e98440c be4df7b4 42c239c1 42ce1561 3d358feb 3fe1222d -> 41ee1964 c1a1095a 42c82791 40ca72c5",
+ "beb99154 bee225b6 42bbcfd5 4304f2a0 3c74cb85 3e516812 -> c22470b6 c2486659 42e2da8a 400c3b3b",
+ "bf27bb19 bf71745a 428a40f6 42b1ed8f 3cb27486 3e90d246 -> c24f296d c2951bbf 429e1742 400e2619",
+ "3ef7a4c4 bf22f650 42524176 42654531 3bfc177c 3ee1055b -> 41d496e7 c20be50e 425bc354 3f616ce7",
+ "bd8f4c80 bf799240 42494de5 42633c6b 3c62c745 3f407536 -> c06fe152 c250e3ad 42564528 3fc4e465",
+ "3f005dd2 3d0efcc0 428dfb41 429367fa 3bbea16b 3f6360f3 -> 42111bac 4021a2c2 4290b19e 3fa8961c",
+ "bec1cd24 3f6c6f42 420dba06 42751970 3ac5f43e 3f526421 -> c1926bb3 4232a187 424169bb 3f6a1dce",
+ "3f0f7a6c bf15bf9f 41541e75 4214168e 3a296c33 3fd4ebd3 -> 4161700e c16b4a33 41c91e2b 3fd7fe68",
+ "bf4dfb39 be1a4e68 41ae9f5e 427add27 3c1e4032 3f882523 -> c2080ce2 c0cbd68c 4229166b 3fd5b2b8",
+ "bf379ffa 3ddc62f0 41c66934 42797c60 3d05f4b0 3fdfae1f -> c1fa1c69 4096176d 422e587d 407264fa",
+ "be7c9768 bf1f1476 3ef43138 41e51791 3ad1d366 3fc7ab9d -> c065ce74 c110baeb 4168e856 3fcd8b81",
+ "be5be394 bf436890 42b6c86d 42cf7beb 3b8fb3b3 3f720e2b -> c1a79bb4 c294f2bb 42c3222c 3fb34979",
+ "3f1354dc bf0cc34a 4176e0f3 41a9353b 3c817251 3ff1d45b -> 41286c28 c120e9dd 419252da 400e4ec3",
+ "bf52ec4d 3f7acac0 3e8575fe 4207438a 3add0aa2 3fd9c918 -> c1609c5c 41858893 41884e76 3fe118cc",
+ "bf2ee662 3f5db0c2 4202a098 42263863 3d3af4ef 3f8f8efc -> c1cacea0 42008824 42146c7e 40412d33",
+ "bf1b380a 3df341b0 41f745a7 425ba40a 3be85c9f 3fd6c668 -> c1d0230d 40a3182d 422ba36f 4004503b",
+ "be3e29b4 bf10d4be 418e9d47 420dae8e 3b8a437b 3fe481c2 -> c09e369d c170fed8 41d4fd32 3ff7a51e",
+ "3f55f656 3f33a040 4207c63c 428e5d8c 3ad11fde 3ff76bbe -> 422fba1e 421386d4 425240aa 4002fd7b",
+ "be791c44 bf721e34 41bfec95 421c834a 3d07fbe9 3fa9df0d -> c0f5ae21 c1eec8b7 41fc7994 40281427",
+ "3f3e8972 3ed28f2c 417d5b33 41bbf71b 3ca64147 3e46d602 -> 416a2f2c 4101658a 419d525a 3f2bcadf",
+ "bdbc2310 bf120188 41a5264e 42193616 3b2a23cf 3f86c828 -> c02d4814 c1867a2e 41ebc93d 3f93849a",
+ "bf2bd83d bec4c658 41096a7e 41c28ed4 3d10eefa 3e47bfee -> c130b8da c0ca5c18 4183a20a 3f871f8c",
+ "3f08ce96 3ef1f7e4 42b57928 42c06434 3d1a5860 3eb94d8a -> 4247cb4c 4230afb5 42baeeae 407f2a29",
+ "3cc3ca00 be30cf34 42b49f8f 42d893a5 3d23ce83 3fe2b5d3 -> 4017e3b6 c1892a58 42c6999a 40c3433c",
+ "beb6a64e 3f49d7ae 42b33c80 42f3ba30 3cf94452 3f5e73f1 -> c216e313 42a6be04 42d37b58 40927924",
+ "3eb9d098 befbcd96 42a28596 42aa9372 3d37e2c9 3fde230f -> 41f1c681 c223d186 42a68c84 40b2108d",
+ "3ebf7308 3e04cbf8 42a033a4 42f16f0c 3cee0fba 3fb8ddb0 -> 42162e6d 415057e4 42c8d158 409e7aea",
+ "3f43564e bf5f4b9a 42004746 421ca283 3cdbaf96 3fed50c9 -> 41d96621 c1f883c9 420e74e4 4039df47",
+ "3f0337f0 3f06ba2a 42be815f 43101486 3d0371a7 3ffdb4ac -> 427559cd 427be94b 42ef5536 40d36473",
+ "bf1ca30d bf4f8880 42266466 42666e38 3ada9ec5 3e9f89c3 -> c1f2cd17 c220d8f2 4246694f 3ed0cd73",
+ "3e858b3c 3d1ff740 428c126c 42cd20cc 3d01cb61 3f67ef72 -> 41b4135c 4057b436 42ac999c 4084ff7f",
+ "bedc0b76 3ebf53f0 42a7c1b0 42abbb1d 3cad576b 3ec0d27b -> c211e739 41fdb96c 42a9be66 400c64da",
+ "be7573ac 3ecc7584 42a6b197 42b8cc7c 3cc42bc0 3fbc4da7 -> c1a8813d 420c5ce9 42afbf0a 406bc565",
+ "3e064a00 bf23d44c 420fc7d6 42a8cc1c 3d36056f 3fd83a36 -> 40fc836d c21a07ae 4270b007 40ae1474",
+ "bd1376a0 3ed1d518 42755ad8 42ccd1c0 3d358efe 3fcd9251 -> c03ca5c8 420637b7 42a3bf96 40c4a87c",
+ "bdc34530 be8849aa 42558e09 42ab491a 3c1653da 3df931a0 -> c0d4196d c1940893 428b080f 3f68576c",
+ "bf74b2df bf09b6f0 422c9127 42acfce7 3d2f7833 3fd93bdd -> c277d360 c20b7975 4281a2bd 40ace2cc",
+ "bf52be3e 3eddefc8 4208b3e8 4290c613 3cf49d2c 3ff101a6 -> c22f72a7 41b8c445 42552007 40816c8f",
+ "bf2f3d32 bf79403b 4276dcce 42bf6bd8 3d1a9e7c 3fd9f566 -> c2578675 c29946a4 429d6d20 40aa1cc1",
+ "3f180ee4 3ea53900 427c8993 42d3d052 3c0b6434 3fed98d9 -> 4248d033 41da32e2 42a90a8e 40307a26",
+ "3f2e144a bd9490c8 42a0269c 42a3bb1b 3cf0dd85 3de1d4c4 -> 425c3d16 c0bbf5aa 42a1f0dc 40211e05",
+ "3e9e9980 3ef0c88c 424f4fe3 42b4e82c 3c037a81 3efcc983 -> 41b04b93 4205d304 428e480f 3f9c20d3",
+ "bec7f9b4 3ecb519c 4201ae0c 4267bf62 3d34690f 3eaff0f6 -> c18d2a4d 418f867f 4234b6b7 40395175",
+ "3be80400 3edf0cf0 412f0ec8 42321761 3d080d7f 3fdf83f3 -> 3e491201 41414d0c 41dddb13 404e68d6",
+ "bf20a50b 3f0b83e4 42751fa8 42bec52a 3d2dbcb4 3f8540b8 -> c2449f20 422ac293 429caa7f 40a2c9b3",
+ "be0fa388 bf2aacb0 40cb1b88 41fbe91e 3abdd2db 3f4918f9 -> c029d5ab c149cd0e 41975800 3f54c93e",
+ "bf676a91 bf64f96b 41509c09 41dabf4c 3bb5fc5b 3fdc7b32 -> c19203bf c190794d 41a186a8 3fefedc1",
+ "be1c6614 be6af620 42aae719 42cfe809 3c9a29b2 3de5185e -> c1676d45 c1add6c4 42bd6791 40045e7c",
+ "3d645f60 beda5ebe 429c2dfc 42ca1b2b 3c90a95a 3f66be2e -> 409fcf52 c218cf72 42b32494 402be6e8",
+ "3f23a1d0 bf29c393 42a00e6f 42fccd76 3d2e0315 3fd09267 -> 4283f27c c288e449 42ce6df2 40dffd9f"
+ ]
+ },
+ {
+ "glsl": "vec2 cultmath_iv_snoise_ball(vec2, float)",
+ "tolerance": "ulp-bounded",
+ "cases": [
+ "c0b75188 423d2522 3fe31de1 -> bf800000 3f800000",
+ "4246e964 c17bd730 3ffdfea1 -> bf800000 3f800000",
+ "c1fc8975 41f194d4 3fabf475 -> bf800000 3f800000",
+ "422c4d44 c071c1a0 3fd3f608 -> bf800000 3f800000",
+ "c23713bf c1e1f045 3f9bd561 -> bf800000 3f800000",
+ "c1ca302c c1c9a6d7 3f0eb662 -> bf800000 3f800000",
+ "c240811b 41fd106c 3f4b9b12 -> bf800000 3f800000",
+ "40b4c4b8 c20a57d5 3f8fbe05 -> bf800000 3f800000",
+ "41bfdf38 423c4866 3fd09ad4 -> bf800000 3f800000",
+ "4132fb74 41928344 3fdbd120 -> bf800000 3f800000",
+ "41144c7c c217c5e0 3ed0b522 -> bf800000 3f800000",
+ "c1942dc5 42094cd8 3e8c25d3 -> bf800000 3f800000",
+ "423da796 c0ebaa98 3db0bfe8 -> bf7ce0fc 3ed394b1",
+ "4210e1d4 c1fb88da 3f92c7ce -> bf800000 3f800000",
+ "c138f714 411b6590 3fd319a6 -> bf800000 3f800000",
+ "42351de6 c1050a60 3e89f897 -> bf800000 3f800000",
+ "4208db38 40e77400 3feba820 -> bf800000 3f800000",
+ "400aeda0 42237bba 3d894c73 -> beee05c0 3f1f9a22",
+ "c104362c 421a7d38 3fd19d99 -> bf800000 3f800000",
+ "c18b5312 c1c20c75 3f3e91df -> bf800000 3f800000",
+ "c2010afc 40e7e338 3e744721 -> bf800000 3f800000",
+ "41fa5b44 c1818bb6 3f2f18ef -> bf800000 3f800000",
+ "4147268c 41b60648 3f3fd0b5 -> bf800000 3f800000",
+ "c0329330 c1b57f58 3fd258fd -> bf800000 3f800000",
+ "c1d3705e c20962ee 3fa184d5 -> bf800000 3f800000",
+ "4201aff6 c20329a4 3f8ea755 -> bf800000 3f800000",
+ "41bd66b0 41e5a36c 3f8dd837 -> bf800000 3f800000",
+ "41905f4c 41d7c74c 3e63da68 -> bf800000 3f800000",
+ "422f3ce6 c22b9bbc 3ed958f6 -> bf800000 3f800000",
+ "c203d8fc 421ef6a8 3ff5012b -> bf800000 3f800000",
+ "c191d4ce 416d4478 3ead6501 -> bf800000 3f800000",
+ "41889fd8 4193d99c 3f9d01e8 -> bf800000 3f800000",
+ "c0923388 40e4a4d0 3f04d36f -> bf800000 3f800000",
+ "bfdb55c0 c189577a 3fb08164 -> bf800000 3f800000",
+ "41cffb88 c14fee54 3f195ec9 -> bf800000 3f800000",
+ "c2206f47 c1ab31ee 3fc0969f -> bf800000 3f800000",
+ "c11c56bc 411509fc 3fb6da8f -> bf800000 3f800000",
+ "c1bea39f 410e8c74 3f70f9d2 -> bf800000 3f800000",
+ "41fe6da0 be9d5180 3fcd86f3 -> bf800000 3f800000",
+ "c244ca5b 4215f0bc 3f08efe0 -> bf800000 3f800000",
+ "c21414a0 c092eb00 3fd48870 -> bf800000 3f800000",
+ "c1045274 c20a3ecc 3fa0018c -> bf800000 3f800000",
+ "41744400 40cfbf28 3f71a813 -> bf800000 3f800000",
+ "c240f288 c1502664 3f99d0c5 -> bf800000 3f800000",
+ "c1a1a0f2 c1c4e3f1 3f6b017e -> bf800000 3f800000",
+ "4211d0ba 422831e2 3f4cca33 -> bf800000 3f800000",
+ "41f949ec 4207ac2c 3fc8fb09 -> bf800000 3f800000",
+ "c0810210 41d67964 3f1bf57a -> bf800000 3f800000",
+ "c1cdae76 c2319898 3df46831 -> bf800000 3f62119a",
+ "419ed1b0 420d191c 3ec0cf6a -> bf800000 3f800000",
+ "41f84cd4 c0abe0b0 3fb25e57 -> bf800000 3f800000",
+ "4244c95e c16b1838 3fdfd1f8 -> bf800000 3f800000",
+ "420fadc8 c17bb67c 3edd3bd3 -> bf800000 3f800000",
+ "418b7dec c0ac0238 3fb8a231 -> bf800000 3f800000",
+ "c1afa335 c1388c9c 3ee4ffa8 -> bf800000 3f800000",
+ "c21a9ae5 42397eaa 3f2bcbae -> bf800000 3f800000",
+ "c2435565 42356616 3f939f77 -> bf800000 3f800000",
+ "c11b19e8 c1f2dea0 3d9413cd -> be5b2b20 3f75b1a4",
+ "bfe4eb60 41881744 3fafa7af -> bf800000 3f800000",
+ "40258540 c2023d62 3e4a6634 -> bf800000 3f800000",
+ "40d209a0 4235a828 3fb65a94 -> bf800000 3f800000",
+ "c1acee5c c1ea31e3 3fec74bd -> bf800000 3f800000",
+ "42219de2 c19b33af 3fe69f77 -> bf800000 3f800000",
+ "41072f40 c245dd0e 3f93f90b -> bf800000 3f800000",
+ "c1fcc7f6 c2111a02 3f495671 -> bf800000 3f800000",
+ "c22e71e8 c2004ea8 3f447a22 -> bf800000 3f800000",
+ "c22797f0 c2143c56 3e3de781 -> bf800000 3f800000",
+ "41b331d8 41957c7c 3fe6386f -> bf800000 3f800000",
+ "41324fe0 c1144c70 3f0020cf -> bf800000 3f800000",
+ "4180bea0 3f7c2e40 3faee059 -> bf800000 3f800000",
+ "c1f96894 c1855516 3eacbe51 -> bf800000 3f800000",
+ "c2191696 c21c823d 3f7c167c -> bf800000 3f800000",
+ "c2446fa6 4246a594 3eb6143f -> bf800000 3f800000",
+ "c1a04cc9 c1e8718f 3fa86cd2 -> bf800000 3f800000",
+ "c0d1f7f8 c0e909b0 3ff2bc08 -> bf800000 3f800000",
+ "424773f8 c1e0c4ff 3df4464a -> befb28db 3f800000",
+ "41646070 c102d5c8 3f7b7637 -> bf800000 3f800000",
+ "c19df3d7 c0b07de8 3dba3bf0 -> bf3a8330 3f3f673a",
+ "c2458ef1 4208a848 3f090982 -> bf800000 3f800000",
+ "41fa5788 4189e9b4 3fcccf9f -> bf800000 3f800000",
+ "418afe84 c1cd82da 3fcbd6f5 -> bf800000 3f800000",
+ "c1e1b473 c125ff98 3fac1362 -> bf800000 3f800000",
+ "c110c100 c22d4d65 3d6d98fb -> bf1e5894 3ea573f7",
+ "422054e2 c2320242 3ebb6a8b -> bf800000 3f800000",
+ "c1eb2be4 41e11ce8 3feb8577 -> bf800000 3f800000",
+ "c0d17e20 c1a8502c 3f052593 -> bf800000 3f800000",
+ "42346fe0 41347ffc 3ec135a0 -> bf800000 3f800000",
+ "c1f76eef c240b8cc 3e3c92d6 -> bf800000 3f800000",
+ "c1f657f6 421a45a2 3fe3779e -> bf800000 3f800000",
+ "c216af32 c21b87a4 3f08ef5e -> bf800000 3f800000",
+ "c1dc24b0 c1f336d7 3f262d36 -> bf800000 3f800000",
+ "c1441180 41496960 3ff762cc -> bf800000 3f800000",
+ "4210a312 c1e2c98b 3d80a6f4 -> bf57e016 3e34c4b6",
+ "c1b314b1 410e90e0 3e9c620b -> bf800000 3f800000",
+ "c23bbd89 41c18670 3f3a25a4 -> bf800000 3f800000",
+ "c19962f5 c22163fa 3fa9e339 -> bf800000 3f800000",
+ "c215fd7c 40e50690 3f8d60d6 -> bf800000 3f800000",
+ "c244f58b 4210bbe6 3df5f5cc -> bf019788 3f800000",
+ "4132ab1c bfd928a0 3ee6b5e6 -> bf800000 3f800000",
+ "41a39e88 c23dae3e 3f82c4d2 -> bf800000 3f800000",
+ "41e2d098 c1ab021b 3ff4a19e -> bf800000 3f800000",
+ "41d12580 418cce74 3fdbebc4 -> bf800000 3f800000",
+ "420f5b0c 42036e6e 3e9fac69 -> bf800000 3f800000",
+ "423573cc 40e96950 3e16a495 -> bf5bf7b0 3f800000",
+ "c1d8fe78 418bf470 3d4638aa -> bf800000 be6cc936",
+ "c2399b82 c207f9ee 3f0da52a -> bf800000 3f800000",
+ "41b6b2b8 4219857e 3fca0d0f -> bf800000 3f800000",
+ "c1dbf93a 42474e48 3f8a32a1 -> bf800000 3f800000",
+ "41ac0a38 c1e2399c 3f2b40fe -> bf800000 3f800000",
+ "c1bc4843 41d4a1b0 3e92b70b -> bf800000 3f800000",
+ "41c1228c c2092c32 3ec3b585 -> bf800000 3f800000",
+ "40024370 bf3ca900 3f1b3ead -> bf800000 3f800000",
+ "c1f29eb5 c1b8a092 3e07ea92 -> be474494 3f800000",
+ "3ed9d280 c0a06438 3f096018 -> bf800000 3f800000",
+ "3f4b6c80 c2037147 3fffa63a -> bf800000 3f800000",
+ "c006c520 41df1364 3ebfcb06 -> bf800000 3f800000",
+ "c239a6ed 40f23248 3f25895f -> bf800000 3f800000",
+ "42337362 423e75e8 3e91d785 -> bf800000 3f800000",
+ "41b121bc 40bb2748 3f13a025 -> bf800000 3f800000",
+ "c1067524 c235725d 3f6b09e9 -> bf800000 3f800000",
+ "401f07a0 4115fcb4 3e018d22 -> be98b714 3f800000",
+ "c242ef82 c1e63af8 3f55138a -> bf800000 3f800000",
+ "4218f336 41a6b918 3ebb1b74 -> bf800000 3f800000",
+ "41b0ad04 4207b3d8 3fe411e3 -> bf800000 3f800000",
+ "c1e7b003 c1dcb492 3f5e50a5 -> bf800000 3f800000",
+ "4007c020 41adab60 3fd3b379 -> bf800000 3f800000",
+ "40831f00 c1d31d22 3f60975e -> bf800000 3f800000",
+ "c20d18fe c1d8fa68 3ec3148d -> bf800000 3f800000",
+ "41ffe5e8 41ea3bc8 3eb9ada8 -> bf800000 3f800000",
+ "c23482c9 41ef26b4 3fef2649 -> bf800000 3f800000",
+ "c2420b64 41e09bdc 3ee49425 -> bf800000 3f800000",
+ "412b5fcc 423fc32c 3fdb306d -> bf800000 3f800000",
+ "c1ebdff8 bef16600 3ff58e45 -> bf800000 3f800000",
+ "41046930 411a81dc 3e1136fd -> bf800000 3f31b00e",
+ "c2462b2f c193fae0 3fbc8f52 -> bf800000 3f800000",
+ "c0d92d90 41be96c8 3fc08d5e -> bf800000 3f800000",
+ "41a67478 c1efd64c 3fd76b19 -> bf800000 3f800000",
+ "c078ee70 4215fed8 3fcf746d -> bf800000 3f800000",
+ "c23fd577 c143da20 3f3b0644 -> bf800000 3f800000",
+ "42151304 c1f5c4ec 3f56e44a -> bf800000 3f800000",
+ "c1d40914 42057600 3fe8d5a6 -> bf800000 3f800000",
+ "c1c97730 41a4c3cc 3df1864f -> bf800000 3e991814",
+ "41866890 4125402c 3efaf8de -> bf800000 3f800000",
+ "40f8edc8 c1932802 3ee385f6 -> bf800000 3f800000",
+ "4213135c 42374994 3fa3c4c1 -> bf800000 3f800000",
+ "c1534e94 c20eedce 3fe9ee7f -> bf800000 3f800000",
+ "c0943f10 c1339d64 3de16564 -> bed84297 3f800000",
+ "c0e39258 c17ef418 3f9953df -> bf800000 3f800000",
+ "c222e6c4 40ac1c18 3fe7e3c9 -> bf800000 3f800000",
+ "c10be87c 410ab5ac 3f9a1d7f -> bf800000 3f800000",
+ "bf620540 c1860600 3f1b0e90 -> bf800000 3f800000",
+ "407e7930 c17384a4 3fc35626 -> bf800000 3f800000",
+ "c2079c0c 41cd20d0 3f9bf8c2 -> bf800000 3f800000",
+ "418e5910 41d34c10 3e8aa2ec -> bf800000 3f800000",
+ "3f3b6940 c213e37c 3fe25b62 -> bf800000 3f800000",
+ "413f5ae8 411576f0 3feab42e -> bf800000 3f800000",
+ "c203b4c4 4173f8b8 3ef0f1c8 -> bf800000 3f800000",
+ "c09c1ed0 c1019468 3fce1dff -> bf800000 3f800000",
+ "c1583778 41f4db84 3f7c8b7e -> bf800000 3f800000",
+ "c1976a9e c209d4d4 3e9c4208 -> bf800000 3f800000",
+ "c20ae92e c1c3a334 3d0beaf9 -> bf1a297a bd432a58",
+ "4164a360 c2255a32 3ffbccb3 -> bf800000 3f800000",
+ "4227b8d2 c189a870 3f9c5113 -> bf800000 3f800000",
+ "4216a680 c1ea6f31 3f45ed0f -> bf800000 3f800000",
+ "c19c40dc 41dc972c 3f9fb1d9 -> bf800000 3f800000",
+ "4227d724 4228a010 3ed7d434 -> bf800000 3f800000",
+ "41abab4c c02bd7f0 3ff5dc09 -> bf800000 3f800000",
+ "424399d2 c1ce8ab6 3fef2aa1 -> bf800000 3f800000",
+ "c154f64c c238043b 3fe9db38 -> bf800000 3f800000",
+ "be829c80 c2020a8e 3f8abdca -> bf800000 3f800000",
+ "c1b8111e 420c1942 3f99e778 -> bf800000 3f800000",
+ "c089edc0 40215b70 3f824830 -> bf800000 3f800000",
+ "c218a745 4211c4ce 3db4c976 -> bf800000 3e018a1c",
+ "422039dc 41a03bd4 3f081e29 -> bf800000 3f800000",
+ "c19aeaee c1a4b68c 3f644035 -> bf800000 3f800000",
+ "420b757e c20d636c 3fa4b955 -> bf800000 3f800000",
+ "c1fedb76 c0af2810 3fe272f3 -> bf800000 3f800000",
+ "c1ade6e1 4119d42c 3faeb3cc -> bf800000 3f800000",
+ "c1f68ec9 c2068301 3ce7669a -> beaa1041 3e017172",
+ "c2270c9e c1b33329 3dc112e5 -> bf087695 3f7f54f7",
+ "c22bf319 c0fa0fa0 3e9d2311 -> bf800000 3f800000",
+ "c22c865a 412abc40 3f36cce7 -> bf800000 3f800000",
+ "41e43914 420b1d4c 3f007613 -> bf800000 3f800000",
+ "c21a0503 41f0fcd4 3debfb38 -> bf47f35e 3f800000",
+ "c205503f 41fb3794 3fc5e16c -> bf800000 3f800000",
+ "419be7a4 41921e94 3ff29f1a -> bf800000 3f800000",
+ "bf90d100 3fe99de0 3fe4bb4c -> bf800000 3f800000",
+ "c1b7da70 c1932efc 3fbad21c -> bf800000 3f800000",
+ "417b8d90 4242eae2 3f024ac2 -> bf800000 3f800000",
+ "42277c94 c1bbeca9 3f393f3e -> bf800000 3f800000",
+ "befe0f80 c2399aa7 3f96b04b -> bf800000 3f800000",
+ "4246ccac 42042cf4 3f0ebe78 -> bf800000 3f800000",
+ "c21b0461 c1d1de3b 3fb003a0 -> bf800000 3f800000",
+ "c224795f c22ea70c 3f1922cd -> bf800000 3f800000",
+ "c12b9a3c c22d68b8 3fa4eac1 -> bf800000 3f800000",
+ "4202f270 c219a332 3fc84044 -> bf800000 3f800000",
+ "4223c412 be9d9b80 3f7670fe -> bf800000 3f800000",
+ "c22da22a 4115e7a8 3fc203c5 -> bf800000 3f800000",
+ "c20ab528 41eff43c 3e59aa9b -> bf800000 3f800000",
+ "c0f520f8 c10da6f8 3f9e9e82 -> bf800000 3f800000",
+ "c21ef512 42129ff8 3f9538f4 -> bf800000 3f800000",
+ "421b9d28 413fdc70 3fc3eec6 -> bf800000 3f800000",
+ "c04831f0 c2041cec 3ffbcc98 -> bf800000 3f800000",
+ "bf0ed140 4103e0d0 3f63f95e -> bf800000 3f800000",
+ "c1bfbf7d c12034a8 3f690a19 -> bf800000 3f800000",
+ "41177fa4 4216f958 3effea9d -> bf800000 3f800000",
+ "c225c220 4203f0f6 3fdf1777 -> bf800000 3f800000",
+ "c03350a0 c244477e 3fc4ae91 -> bf800000 3f800000",
+ "42182b02 c0e2cfa8 3f629994 -> bf800000 3f800000",
+ "420444e6 420981d4 3d7dcc44 -> 3d5939d0 3f800000",
+ "c202f5ad 41973f7c 3fd38761 -> bf800000 3f800000",
+ "c22cce85 42427bb4 3ec9f0eb -> bf800000 3f800000",
+ "41acd754 3ebe2480 3f64c854 -> bf800000 3f800000",
+ "42178384 c16229c8 3ff23b30 -> bf800000 3f800000",
+ "41eed4d8 c10802a4 3fea1f56 -> bf800000 3f800000",
+ "c23990b3 41f47b28 3ec6e230 -> bf800000 3f800000",
+ "c19db4fb 40bb5778 3fec2bff -> bf800000 3f800000",
+ "420e8450 c181c3fe 3f94f262 -> bf800000 3f800000",
+ "41c66c38 4150ffe0 3fdb7a17 -> bf800000 3f800000",
+ "41fb9d78 c2448dda 3ec3c8f3 -> bf800000 3f800000",
+ "c18da4bc 415cdff0 3f270f0c -> bf800000 3f800000",
+ "42353c00 c18e8b30 3fe4b6fd -> bf800000 3f800000",
+ "413e0f1c c1f62274 3f53f21f -> bf800000 3f800000",
+ "c1c18a04 42177440 3f3f8170 -> bf800000 3f800000",
+ "41f2621c c1ea8b48 3f716472 -> bf800000 3f800000",
+ "422a145a 418ac110 3f9831e1 -> bf800000 3f800000",
+ "420d784e 4209bbb4 3f9fab5a -> bf800000 3f800000",
+ "c1c9374c 4031f620 3f1237ad -> bf800000 3f800000",
+ "c21ccdf2 c192f3fc 3f3403c7 -> bf800000 3f800000",
+ "c1cc5556 c1900941 3f36393f -> bf800000 3f800000",
+ "c1805cf4 42209cee 3f7d9eb3 -> bf800000 3f800000",
+ "c1c361c9 40b2af10 3fb8827b -> bf800000 3f800000",
+ "414061ec 420a2e6c 3e3fbf48 -> bf800000 3f800000",
+ "c23f8be0 c10451e4 3f9d0be8 -> bf800000 3f800000",
+ "41e01fe4 c236157c 3fae1902 -> bf800000 3f800000",
+ "409c1dc8 c232acbc 3e868fb8 -> bf800000 3f800000",
+ "c21bd61a 420121c2 3ff50b48 -> bf800000 3f800000",
+ "c1bda36b 4238566e 3ea8a6fc -> bf800000 3f800000",
+ "40d744c8 c22a36b8 3e62aee3 -> bf800000 3f800000",
+ "c237b5a8 420a09f0 3c44e6e9 -> 3f19dd46 3f4bcf4e",
+ "4086b5c8 c149463c 3fdf5848 -> bf800000 3f800000",
+ "c230c498 42276978 3ffa2427 -> bf800000 3f800000",
+ "421772ec 40970f98 3fa6b224 -> bf800000 3f800000",
+ "41c87ba8 c19c0843 3fd3fcc0 -> bf800000 3f800000",
+ "3de87800 4205042e 3f5ac99d -> bf800000 3f800000",
+ "c243e657 c04ab970 3f776fcb -> bf800000 3f800000",
+ "412880d8 40bd72b0 3f06d7a6 -> bf800000 3f800000",
+ "c1dfc3d2 c2125490 3f7ea824 -> bf800000 3f800000",
+ "c1228ed0 c2295cc4 3ff0d2e7 -> bf800000 3f800000",
+ "c187589c 4196cd04 3f769886 -> bf800000 3f800000",
+ "413093e0 40fe7120 3ae06ada -> bee3835e bed5482c",
+ "c224ef78 c0062990 3db27bb7 -> bf800000 3e7ffa0c",
+ "41c0b6d0 41b1a910 3e81bce1 -> bf800000 3f800000",
+ "41a23ebc 41882198 3f81a063 -> bf800000 3f800000",
+ "c0000d30 c1604fbc 3f84a2ee -> bf800000 3f800000",
+ "c21452ae 41d1741c 3e83d42d -> bf800000 3f800000"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_snoise(vec3, vec3, float)",
+ "tolerance": "ulp-bounded, reach 1e-6 to 1e-3",
+ "check": "the arguments are (cx, cy, cz, ax, ay, az, radius, ...) and the result is the form (x0, a, e). Enclosure: for eps in {-1, -0.5, 0, 0.5, 1} and d in {0, +-ex, +-ey, +-ez, (+-1, +-1, +-1) / sqrt(3)} (15 directions), form the point p = c + axis eps + radius d in double and round it to float32; the device's own reference value at p must lie in [x0 + a eps - e, x0 + a eps + e] with no tolerance, so a device whose gradient error exceeds the allowance fails. Tightness: with L = 7.9640074 and, for each octave (one for af_snoise), R = |axis| + radius, B = L R + 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R), the width |a| + e must be at most B + 2^-16 (1 + B). Report the least slack of each side, absolutely and as a fraction of e; only the two bounds fail the check. The reference value is cultmath_snoise(p). These cases have reach |axis| + radius of 1e-6 to 1e-3, where the float32 allowance is most of e and the second order remainder is not; the enclosure above fails a device whose gradient error exceeds the allowance. Centre leg, for every cultmath_af_snoise and cultmath_af_fbm family of this fixture, the earlier ones included: the fixture's own x0 in the result (C#'s value at the centre) must lie in [x0 - e, x0 + e] of the GPU's form, with no tolerance, so a device whose noise differs from C#'s by more than its e fails.",
+ "cases": [
+ "3de98ec0 3e5960a0 3e824700 b64c3554 36674e47 b629f5b3 37601e01 -> bee8782f 36405f94 38e47f80",
+ "3f2f1238 bf6d5b1d 3dc3cf20 b943c815 b9552ec5 390597fe 3791eb35 -> 3ebaf9fc 38759590 3903a998",
+ "c139b3a4 c1b8837e 41c4ffc0 38e3ec26 38dc4b8d 389176fa 395ca6ba -> 3e59bf01 b9c019c6 3aa3838f",
+ "beec548a bebdab10 3f1ff0f4 b5bb676f 35bed139 35f5b0c6 3911e058 -> be35088f 367641c8 39f059aa",
+ "c2091b3b 41f27428 c156f984 00000000 00000000 00000000 36ef2dcd -> 3e02aba0 00000000 3a2ee486",
+ "bf415a24 3e96f054 bec22aba 00000000 00000000 00000000 3979f5b4 -> 3f00ce18 00000000 3a7b5a27",
+ "c172a69c 41dbd6f0 c16ab350 375ab8b5 b70b7f01 359ff929 3a6d5e2c -> bd169e91 353c0390 3b08a588",
+ "bd8ca798 be54ffb4 be60513c b674cdf7 36c97804 3649905b 3646a75a -> 3f0e31c6 37195340 38983a7e",
+ "bf460e64 bf5d040d bf1b828d 3660aadc 35cca052 b66df0c7 39513c96 -> 3dbd40e3 b5bb6f1a 39c64322",
+ "c0e04328 40af6150 c1fa88dd 396b6d16 b96965b5 b9031a1e 3595385d -> beb2ac89 3a28b532 39d1bdd9",
+ "3e63bbf8 bebac5a0 be8fda88 b8724e47 392ef8ff 38801b83 37b225b5 -> bd469206 3a15fbc6 391151c2",
+ "42281202 c24198d2 c22f046a 00000000 00000000 00000000 36769265 -> 3dd08ee9 00000000 3a8ebaf1",
+ "40fb4bc0 41d9f458 c139afc4 00000000 00000000 00000000 3683c860 -> bd915b07 00000000 39dd7762",
+ "41504874 421674b2 c20b5de4 b6667f0c b574ab23 35408169 39116440 -> 3ec66a90 34c78fd0 3a93c57e",
+ "bee2441e bde396a0 3f70b70e 39c53600 3963ae74 b9f24965 3591be10 -> be52a73e 39db57bc 38b819c8",
+ "41eb0098 411db0ac c1f88cee b5d5548d 38cf478f 38735753 37c7eba0 -> 3ec4e662 39735a97 3a2a8349",
+ "c0806970 4207b82e 3fbb4dc0 37938dcc b5d15df2 b6eeda70 394876f3 -> 3e299ef9 3610b078 3a031d28",
+ "c1f2d8ed c1c343a1 c092bdf8 00000000 00000000 00000000 392a6aa0 -> be841b57 00000000 3a8b9908",
+ "bf04a494 be5b8028 3e11d388 381eae8f b8893bfa b9e5e3f6 380771e6 -> be0c82b1 37fe2d4c 38f45877",
+ "41957650 41be235c c1026468 00000000 00000000 00000000 38b2c682 -> bf485844 00000000 3a3177fd",
+ "3ee8d84c bf01f67b be1c98b0 366355ec 35a4befd b64f4484 36824a2f -> be305f08 b62249d8 389934d6",
+ "bf271ebc 3f069042 bf432953 b99449fe b990e5f2 391393bd 3927e7c0 -> be9b8b31 3a8f6452 3a40ecac",
+ "c219e9fe 3dd99800 422f887c 00000000 00000000 00000000 38de6c5d -> be66d34d 80000000 3a6bdfb7",
+ "3f1f6cce 3e9f8c24 3f17d57e b7179bf6 35057781 36021be1 382187fe -> bf496c88 b6edbe56 3906d627",
+ "41352b58 c1a236d5 419692dc b8a5fb2f b86dc7e0 38c9aa74 36e23fe4 -> bc78d716 b96082cc 39eed366",
+ "41d327e0 423a1498 421ae206 b6c534f3 351ea919 b2a20814 39468d10 -> be99d01b 373e6c27 3ab7bc9d",
+ "c19a2218 c10a5698 41d3a4d4 3809d622 b698a636 b6e3bbb1 398c0264 -> be308f7f 38434f83 3aa855a1",
+ "bf2f79f6 3f17e7c8 bf7b3ce9 34af4f09 b5861a9f b62ef6bb 36078865 -> be373174 3435f5e8 38ab890e",
+ "3ef533f0 bf0be5d1 3eef5408 3684116e 367886d9 3640d57f 389e1322 -> 3e46b642 b6b4b726 39753aa2",
+ "c23c9be7 c1728468 40c9bdf0 3746859f b714ce0f 3581890e 392f07e4 -> be63bedf b543e2e0 3ab4c727",
+ "3f5572b0 befe432c 3f4e7150 b98837cd 39f8a638 39f29b6b 3a7d3137 -> be1e0035 bae0ca24 3b572b8a",
+ "be9157a2 be9aa8de bf3073fd b564e7b7 b7e47e1b 3743ebc4 37a396ef -> 3d01088c 38264ae1 38e609f9",
+ "3ebc2358 bf2ab187 3f44b152 381a2fa6 38c9b21b b8adf22a 35abddae -> be1729da b9a229fe 38a5f3f6",
+ "420acfe0 41ecab00 c111f0ec 35f6037d b388ab51 b576402f 35a4f81c -> bf5e99ac 35f71757 3a22c8ec",
+ "3f47d23a 3f22ba9e beee49b2 b82384f5 3794ee57 b7fea625 39926a12 -> be5bdfbc b886d39f 3aad1fd4",
+ "3d22cc00 bf6a7da4 3f6ba68c b81a65c2 37dbf2d6 b768d528 3591854a -> 3e736ce9 366bcff0 38aa1ab0",
+ "41bae30c c1c8f478 4225fdb0 398f4069 385585ba 39bccb38 362d021a -> 3e813bc5 3a8f6cc4 3a4687e4",
+ "3f0397c4 3e1b5948 bda08d28 b9ca5a56 39bcd58c 39ce14bf 36af1af3 -> 3e8c0ed2 bad63992 38c4b500",
+ "3e6d2048 3ea41868 3f48943e 00000000 00000000 00000000 3996f19f -> be57c54d 00000000 3a278923",
+ "3f2bd122 3eaa1e44 bf422a0e 00000000 00000000 00000000 3619fab4 -> be437cda 00000000 38a29b37",
+ "bf50c330 3e41eb48 bf2a77b8 37fcc4ce 370c7b9e b7f4401d 392d38b3 -> 3f2a3a72 b8e82782 3a1c5ffa",
+ "c0cbd658 41fcfb70 c22ec733 365f9692 b63e42ce 36b9809f 39bb42c4 -> bd14aeb4 b6f7b921 3aa6089c",
+ "c190c5ba c22abb87 41ff83b8 00000000 00000000 00000000 3745a35b -> bda5b210 00000000 3a4d8025",
+ "3f2bd3d6 bf712a22 3ee816c0 39c82020 ba2f85b7 3a0ef5dd 37ecd8f8 -> be5828a7 bb42b998 39584fa8",
+ "be8d0096 bd897928 3f6d145c 36bf2f5a 366386f2 b6aef199 369d9d3c -> be38d5fd 38001fdd 38c38409",
+ "c20aeeef 42164ab8 c1dcf32f b8ba4961 38866176 b845b6f2 37b70f8d -> bf0a7584 3826e548 3a661091",
+ "41dc3c30 c2228583 c1ac76f5 00000000 00000000 00000000 395fb00d -> 3e400d51 00000000 3af6ceac",
+ "41fd8b10 c05e2a70 40861770 38d0d6f7 b8ccad21 b7172dd8 35d792ab -> 3dcf4a5d 38a1298e 39bd96b2",
+ "c1904117 40cb7c90 411efac8 36ab60a9 341cfc94 36a01fdb 3836fd90 -> 3e0a2dd7 375cebed 39dfdbd5",
+ "3f1c3e4e beb64e66 bf03c15f 378a7ea9 b799080f 363158a5 35fb591c -> bebaea08 b7927659 38a53e58",
+ "c1fe62b5 41cf8f3c 3f8d14c0 396078ee 390aa93f 391e2529 362e5013 -> be83cfd5 b969a1a1 3a06daa7",
+ "c1078380 3f5f42c0 c183212e 3749f1de 390108e4 b98bf39c 3636e04a -> 3ef1b783 ba44988a 398c8ec2",
+ "c1cc9256 c246d757 417b3620 b837ccc0 b5849e00 b86431f7 3895d183 -> be73a7c3 37f62b8a 3a70333e",
+ "3d54f2e0 3f7de9dc 3e7e8100 398a98dc 3809558c b97f0aeb 3933d47b -> bea586d2 b9f0a6d9 39dfb3bd",
+ "41c322f8 c23d3902 c20eaa17 359bbef9 b6b1d76a 37543f48 378d44bf -> bec5131e b7370d7a 3a733010",
+ "c2226a7d 41b20174 c1907ff6 b8ad4189 b869bf29 b890cd4b 37d8337f -> 3f13a6a2 38dd6069 3a44b396",
+ "3f909160 c20b3045 c1ec68a8 36bdce6d b70a5cc8 3824f333 39dfd1e1 -> bf2f9ae1 3759b222 3acc185c",
+ "3e8a6754 bf04eb40 bf5800ee 00000000 00000000 00000000 3818fd87 -> bd6a4378 80000000 395872f6",
+ "420fd2c0 c1f6a1ad c1b678ec 3546ed21 37eabe9f b7c936eb 38c3b026 -> 3f595d16 b86d98a6 3a6d7e74",
+ "3eb4c96c 3f189838 3f0d244e b63520a7 b7184ff3 b6fd2eb5 38a165f8 -> 3ea5f7f5 37173f60 39cca28d",
+ "3f2518ba 3f02f312 3f51eb52 00000000 00000000 00000000 37906e56 -> bf038b0c 00000000 3901eaa4",
+ "3e905500 c09de718 c07c0f80 3902c51b b9282f1b b930185e 37188c7a -> bf44fb9c 39bb6fe0 39207151",
+ "be1e7114 bc9fd000 3f3fcf6a 391d9da0 3880d283 38a333a9 3931747e -> 3f3c365a b911cb8a 3a210610",
+ "41d05878 c22c289f 3d0af800 3a037b44 399f465d b9357f0e 37805668 -> 3ca99dd3 3889b1ae 3a26e8bc",
+ "c1aea15d c20d4fb2 40da1758 00000000 00000000 00000000 372fee37 -> 3eded15e 00000000 3a14caaa",
+ "bf607798 3f1b2cf6 bf2e8aa4 b53ca5da 38377f2e b59b39df 3a27c39a -> 3ea53d0f b8e55b3b 3aee1dd3",
+ "bcdea220 3f6bc518 3e955588 00000000 00000000 00000000 359f53f2 -> bde0af67 00000000 3898d0e1",
+ "c13c3a04 c18b8a4a 41977a44 39c10126 b987a91f 39d43adf 3a2acc88 -> be486436 ba157e60 3af41bf5",
+ "c10ca7a0 c1e36336 414e6e70 363edeb1 360e96eb b59b804d 3898a8eb -> 3c47d632 36215d9b 3a188709",
+ "3e3ddfc0 be749268 3e4065c8 390c3107 3a41c0f6 b9874945 36a5198a -> bec28bbc ba9efe9e 38cca834",
+ "c1ada584 c1c43976 c2286978 00000000 00000000 00000000 394dea7d -> 3ef66c5c 00000000 3a7f7f01",
+ "c1501140 4222cbea 41f3ffcc 35dd42a7 b5c0bd08 b4d9af69 384416ed -> bec6093e b5569379 3a5251da",
+ "42273736 417f27d0 423bdd2e 35f5fd35 b526d71b 3490aaba 38507dce -> 3f0c77e8 354adfcb 3a84763b",
+ "41b94df0 421f0aa6 420c7d2c 37abe1ef b7ed240f 3745d1cc 36005407 -> 3b6424f5 37effa4f 3a53f5ea",
+ "c2114824 3f0cb000 3f93d9a0 b881b7f5 b8bb682f b907a43f 3619af99 -> 3e5d367a b93940e9 39bc0277",
+ "42368666 c00b1f30 c1d3e256 b8041083 374f2efa 380d3897 396adc5f -> bea6d948 b84310af 3a8f3e29",
+ "3ef0e534 3f76c88a 3dedc390 36dafa93 b78a3d7e b98ad4f3 35ac9137 -> 3e1eb420 b91184ec 389fd5da",
+ "3d8feec0 3f4de232 bf74d21b b6b0972b b5a9458d b6aa5ca2 369f8e31 -> bf00d467 3745f0bb 38c26014",
+ "c22c42d3 41dd8150 423eced4 00000000 00000000 00000000 35b7bdd3 -> be447b9f 00000000 3a7ccd2b",
+ "4181f7a4 40836f68 4238b7c2 00000000 00000000 00000000 35a6e636 -> 3ed0f20b 00000000 3a155b4d",
+ "41beff84 c1bb33d9 c0f935a8 00000000 00000000 00000000 3a36572e -> be15657f 00000000 3b28e9e0",
+ "bf29b1ce 3f722eb6 be89ee8a 3540e9fa b5152575 35986492 37c452e9 -> 3eb6df0e 363a945a 39031dde",
+ "bf26594c 3e7b48e0 3d8cbaa0 b9cf01ce 393388f5 3a210aea 358aea0c -> bf038f7a 3ad55a27 38b9e201",
+ "41adb20c c1c1efa8 41f7ea70 371fbc13 372dee6e 36e4b629 364f6fd8 -> 3efda2a8 b617df30 3a2bb0c4",
+ "3f744716 3f75e39c bd8ef7b0 b7a6591a b75969a9 37981f29 35dab19d -> 3f24d687 382071b6 38a60bcb",
+ "be784a14 3f7b87b4 3f18089c b6adb4ef b6d08a66 36a21fe9 3986a5fd -> 3f0dcef7 37a7ca75 3a32df1f",
+ "3f3fd680 c067f940 c20c12a8 b976f7d5 3958cf4d b931b7b0 39243938 -> 3e35e9ca 3a014c02 3a2e928a",
+ "3e3df470 be140aa4 3f481a86 35d2b9fe b5b3364c b5c91613 386f03bb -> 3dcf1e35 b67af167 39807bf0",
+ "41b4cae8 c1ba7374 421b13b4 3a526b07 39c83589 b88b91ad 363b79d5 -> bf1779c3 3a8d9341 3a408c30",
+ "befe1c54 be1d7680 3e424690 b9825e49 375d51c7 39ab2dc4 3753dc13 -> bd9316fa 39afb828 38b88ff1",
+ "c22429fa 42462e1e 41cff6d0 00000000 00000000 00000000 35b580ab -> 3d833059 00000000 3a78c816",
+ "bf4c92d3 bf4eab1f 3f6f7a0c 00000000 00000000 00000000 366b1b50 -> 3f6037b8 80000000 38b5e474",
+ "41bf90dc 41b1a608 c0bdba30 00000000 00000000 00000000 38604ee4 -> 3ea2f3f2 00000000 3a17328b",
+ "3e7428c0 bec6a8d6 bdcb6198 00000000 00000000 00000000 3905bc9d -> 3c9998be 00000000 39877870",
+ "40f7c328 c204251d 42052424 b5dbad63 b6b1b9ae b69bee46 395394cd -> be7161e1 37398358 3a9c2666",
+ "42449fb6 41b86eac 3f32b800 b68b3a85 b73d4f7a 36475ec3 359583fa -> 3de4bb19 376f917c 3a21aa87",
+ "beb29c04 3f06396e 3ebc1074 33ff620b b58c6666 3579776d 36bf3803 -> bf1178e7 b6247cdc 38b460b4",
+ "41d03308 4223ee26 c1a5258c 35a3ab4c 363aac60 b63e8a50 38b3733d -> be0ea413 b45ad3e0 3a5643f8",
+ "3f1d0964 3f4a427e 3ee2b58c 39beea9a 39ae13a6 39c176ab 37c455b9 -> 3ed721f3 bab8f22d 39165f09",
+ "3eb8ec60 bf53f036 bf2bf5fe 3a1c0507 39f6946b b7af6eeb 372d82c0 -> 3f16cdef bb0e652c 3908ed57",
+ "c112ec2c c193caa9 c23a3029 3960f554 ba4d9a7e b8f7d9b1 3a67fcf7 -> 3eb311d1 bb01a775 3b4ddfba",
+ "42223180 c1016684 41b025a0 b6af89f8 b59431a6 b6f4f115 3633572b -> befb19f6 367ea1e8 3a1f04df",
+ "bee73566 bf7c2701 3e3de280 b79ddac1 37e62524 38224da3 38aa35db -> bd6a6a9a b7293717 39222c93",
+ "be653a44 bf2f078c 3f3c750c 00000000 00000000 00000000 36933d83 -> bce7a14a 00000000 38a3f2e1",
+ "4210341c c2425044 41c84f74 b4dfb2e2 35013626 355cab6a 38f67c33 -> 3eaff8b6 b5a54c72 3aab8f6b",
+ "c15699ec 41d89f88 40aae458 3780f554 b79c611c 3795462f 365988aa -> be4d3646 b7c487ee 39d81b23",
+ "41b208dc c142f9f0 c18aace6 b57e9353 360ebbb0 b580031c 35ceffc3 -> bccbed00 b54b1472 39ef4e26",
+ "3dd113c0 3d284020 bf243704 3692fa13 b7f86bbd 368fb48e 385afecb -> 3f564ca8 b81df745 393a4a51",
+ "bf614131 3e325378 3f6ec39e 00000000 00000000 00000000 370d2593 -> 3f24fbd2 00000000 38d6852d",
+ "bf77df2f bf29f860 bf5a021c 00000000 00000000 00000000 373027f6 -> 3e028310 00000000 38cf970d",
+ "c23c3dd1 41fabf38 41d7207c 36fdf273 3751f9fd b6fd914c 37a0185c -> becbad8e 3716fa1e 3a6fe6b2",
+ "3f62c6fe 3f62aba8 3ed77868 37f2f373 38f83662 39043628 3883185a -> 3e6ecb33 b8102384 3965b693",
+ "4227eddc 417ce0d0 c17f0690 00000000 00000000 00000000 37903eb4 -> 3f11eb04 80000000 3a315b54",
+ "41530afc c15e2d60 420cba4a 00000000 00000000 00000000 35ca4cf7 -> 3e6c046b 00000000 3a0d2c23",
+ "be3e9384 bf2634d6 bc9120e0 39064732 b906df4c b852aa80 366a0038 -> bda9f02d b92f4216 38982629",
+ "c225e0df c1cb0dd1 4166a360 00000000 00000000 00000000 378d2046 -> bf36a909 00000000 3a41f501",
+ "c13a90b0 c20f3d12 c1b84b87 36550372 b752ada3 b599d22e 37dbde7a -> 3eb92688 b7f8b44d 3a2e13b7",
+ "bf5bded6 bd2422b0 bf24ba24 34a3bbe4 b5b72634 35c209c1 3829d03f -> 3e6a4f2f b661f522 393bc6f3",
+ "be954e3a bf0c740f 3f6d491c b80a03c0 3901042a b9072c39 385b3a3a -> be9c867b b9c326fb 397e7adb",
+ "bf5e2e00 c132e824 41ef2a78 00000000 00000000 00000000 3a60c8fa -> 3ed2ebd7 00000000 3b57ce7a",
+ "3f4b7f58 3eeec058 bf0fa160 36298746 b692cce6 3697be80 35970a65 -> bf00117f 34e6ed10 38a3ccbe",
+ "3e23e8d8 bf0aa220 3e684268 b89fc1fa 39cf2baf b8ea307a 360e4787 -> 3ed20b27 ba7bae10 38a7811b",
+ "c2009e2f c08388b0 4226e7ac 372480c1 36b34490 3703c66b 36331d7c -> bf240e71 b73368b9 3a2cfbf3",
+ "3eb959c8 bf7b36e9 3f729aec b5205113 b60b6163 35de45ac 399295f2 -> 3e1692ce 34a53ab8 3a5a1b1f",
+ "c185ddac 41951744 41eae9a4 b8925c42 38fce9c1 b8dc3e3f 3886d399 -> bee6257e 37443750 3a3d9ad3",
+ "3f4cf886 3f59c8d6 bf613635 36061b5c b682f33c 37a8520d 381634c1 -> be67bb7a 37cab0f6 39458d9f",
+ "c18f0bda 3fbb05e0 c212035c b9278403 38131a37 b8fe8450 37cda4c2 -> 3ea773dd 391759f2 3a04fcf9",
+ "41810c8c c17b6fc0 c230c39b 373d10e8 b493329c 36c03d88 381a02a4 -> be465588 b6e4363e 3a333d4c",
+ "3e02a228 bf65b51d 3f0d2658 00000000 00000000 00000000 3968ac4b -> 3ef6e600 00000000 3a7cef3b",
+ "3f65ff4c bf313f1b bec032cc b96cc8ea b8338bd9 38cc2630 3a0feee3 -> bde475bb b99408b5 3ac1cee4",
+ "3dd28510 bda83aa8 be832172 35b26240 b5926755 b5f28b00 36f3aad1 -> 3f51a74d b698faa6 38aa0d9e",
+ "3f3c0ae4 bf20e606 3f7d6ccc 00000000 00000000 00000000 395b0955 -> be834045 00000000 39fa9e0c",
+ "42265ba8 40be2620 c0978e98 3712fa29 3787b209 360195bd 38997ae0 -> 3d95c29b 36ad4dd6 3a237090",
+ "c0888720 407bd570 c1bc056b 00000000 00000000 00000000 39134bd8 -> 3e8dfd12 00000000 3a17f0ec",
+ "423878f6 c24533a4 4230472e 00000000 00000000 00000000 3a7de13d -> 3dacf968 00000000 3b06147f",
+ "beccffe8 bf1c9e9c 3f08d446 3904ee39 b8b404a5 38fdd5f2 36490e02 -> bf170f4e 39ff5d10 38ad7ee0",
+ "c20bce18 41cd77b4 4034e1b0 00000000 00000000 00000000 3737ad25 -> 3eb45863 00000000 3a154125",
+ "bf577c7d 3e61bae8 3f5001ee b90178fe 37893485 38f74148 39d1b43e -> 3f13cea6 3853e0e8 3a944d11",
+ "4208a5a0 412d38cc c1dc5952 b5eac9ee 349cbd67 b45aeb37 36c9a68d -> bd0ee186 b5fc8f2b 3a240371",
+ "3e84dd80 c221c63c c23a3d40 3464b906 36168e31 363a2fd5 377635a4 -> 3e94f1f7 34583ba8 3a437c20",
+ "3ec16c90 3e97db38 3f533b62 359d066a b4f8dbcf b512c0ad 394d2df0 -> becb69c4 b603dc24 3a1d0a89",
+ "bedf7be0 bf747cc9 3f0d5244 b5cada72 b63e89c1 3506d8a9 365fa6b6 -> be19df97 b5b67dec 38a5f15c",
+ "bec91a98 bde3de50 3f1daba8 00000000 00000000 00000000 36317570 -> 3ef2e4b5 00000000 38a0f351",
+ "3e1b4670 3e2016b0 be2ce340 00000000 00000000 00000000 38923b77 -> 3f27da87 80000000 39839a56",
+ "be938fa2 be902c22 be73c528 00000000 00000000 00000000 39002547 -> 3e82907b 00000000 39839309",
+ "bf613992 3f09514c beeead2e b7233328 3576e97a 37d83379 371887e4 -> 3efb900b b837f226 38d449ed",
+ "42320f02 c1c4e544 c190b818 b6893f7f 362b1ac4 b625910f 39ae0651 -> beb973d4 b571a1b4 3aaf807e",
+ "bf255adb 3f637bb4 3f026274 377beb4a 36cfc5f6 b833df15 38d199fb -> b8998fbf b797c5dc 39489cc5",
+ "c08cfd40 c1f84bdd 41070e9c b9e22bbd b8da53af b95524d6 361e6467 -> 3e1ea9ad bacfe659 39d71258",
+ "c21b8ca8 418087c4 418336f4 38b028e2 b96000c1 39817740 39154bfe -> 3ec36410 b97dc33d 3a8d2d67",
+ "bf30ce29 bf3a235d be968e26 377b9b5c b7d26904 b8053549 39610eab -> 3d312315 38195905 39f4d844",
+ "be638f98 be1dbd50 3f2085e4 38954ba8 389dedda 38517da4 38c9ce60 -> 3f3dbe50 394cda26 39a4a622",
+ "bcb81c80 bec43e12 bf427489 371d2335 3540d8d1 b721b0eb 35f7fc12 -> 3a6af6bf b732b05f 3896c313",
+ "41821dc4 c1ab9509 42066502 00000000 00000000 00000000 36cd3052 -> bf25728f 00000000 3a222736",
+ "4206a998 41aab0d0 4220fa66 b63216b6 36e0feb6 b71ddae0 3a054157 -> 3e01eccb b7d58e42 3af96abc",
+ "3f31bc88 3f05c706 3e8c1010 b3285be2 b5c8670f b5d7b4dd 35cda96c -> 3e915989 b57bb94e 38a0c224",
+ "bf77aed4 3f1b6c54 bf2f5992 00000000 00000000 00000000 39a85142 -> 3e7ae68d 00000000 3a87ee6b",
+ "bdb39958 bec3dd1e bf4ae67d 00000000 00000000 00000000 3871e685 -> 3d207825 00000000 39076d03",
+ "3e8ff964 be1fa0cc 3f5674ec 38c12ad2 38619cd4 b8c3da29 3678540d -> be4731d8 b9038f82 38ad2866",
+ "3e96e6b0 bf730168 3ead4c64 371d6f0f b73db148 379c8165 3609aab5 -> 3eec467e 36b26518 38a8d766",
+ "bf6437a7 be2c6988 bec97974 00000000 00000000 00000000 384311f8 -> 3c6b7233 00000000 3968fbe2",
+ "bf2e5e27 3f02b84a bebd0422 b5a6ee51 35cae3a8 b6077689 361a774a -> 3e7c269c 3606a660 38a31a72",
+ "42377524 40673380 c100a384 36aa0882 b603678c 3604a9f9 364568f7 -> bed05b86 36a43053 3a0540e7",
+ "408d19c8 c192c8e9 421f10b8 00000000 00000000 00000000 3726c1af -> be5ad31f 00000000 3a127afc",
+ "3f7faa7a 3f3ac114 3e92a6d0 00000000 00000000 00000000 36187a51 -> 3dbfd921 00000000 38ac4777",
+ "be4c42e8 bf4f2973 3c5bbe00 b9684627 b98ed699 37972acb 3a1b50ac -> be2edde8 38e62bbc 3a45b66a",
+ "be503f7c 3d4b5ea0 befd363a b8e50aba 37b02a65 389efc19 39464d8a -> 3e40c7e7 b9824e21 3a279316",
+ "4216c272 c0f425e8 c20dfde4 383433d6 b858571c b63349dc 398317d7 -> 3e00173c b8f3664c 3aa62cde",
+ "3f251c40 421e5c0c c221a25c 00000000 00000000 00000000 362b8a59 -> 3ef0c750 00000000 3a32a4b7",
+ "c24489a3 c0ace358 42311f00 3536ec85 b50f1f6d b5592e8a 3a14fc9b -> be48c024 3495ee1a 3a99e2a8",
+ "4244d33e 421cec3c 4129f5b0 b59ceeaf 3595700c b3bc32fa 358eb201 -> 3e8971ea b4ed92cc 3a55ea2d",
+ "3f669668 3ea7b7cc 3e49e5c8 3886af32 3885d571 b8973246 3592f404 -> bd464715 b8aa6edf 3899aa76",
+ "be119720 bf23eb72 bec86976 36f3d431 b73fecc2 37cb5a54 370846ce -> 3f00dc89 b87a6054 38cf6716",
+ "bf11842c bf424ded 3f59746c b71d9ea8 35ffae75 b739ef1f 367c3e84 -> 3eacfb89 b3935d00 38bc4ebf",
+ "be0f5008 bf72821c bf5f39d4 00000000 00000000 00000000 375df434 -> beebc205 00000000 38fd123e",
+ "420af4b2 4132a340 c145fa94 b7037292 352ebc71 b784cabf 3a31f599 -> 3e79d34e b7e294ef 3b75bff7",
+ "3e3444c8 3f487238 3f2950be b7344ed9 3783152a 37100fd0 3948de64 -> 3e3754ca b7375245 398e577c",
+ "3ef4cef4 bf45bfb8 befd5956 37a2a1bf 3703fabb b44ab961 35dd4e50 -> be1eec36 b828f137 38a8120e",
+ "c219aac4 c20e01d0 c17e9734 00000000 00000000 00000000 381f77f4 -> bd10b912 00000000 3a541ab8",
+ "c21e05de c08c6490 c197082e b6d20bdd 341992df 352fc00d 3a80c45d -> 3da1c5f8 b772c0de 3b633c80",
+ "40b97050 40068930 c115ff48 b8155a08 379b0049 b77c989b 3889ba86 -> 3e851f34 b865cd5d 39e0dc2d",
+ "be9052a8 bf612380 3f66f184 b8260019 36c696cf b75a70bf 3900c0de -> bdcb98e4 36316184 39c2feb5",
+ "40a1f840 4118e724 c20e67ad 00000000 00000000 00000000 39e46dd5 -> bd9c9842 00000000 3a67c3c4",
+ "c214b0c2 c22df86c 41b09cec 00000000 00000000 00000000 385b7177 -> 3e52b499 00000000 3a7f4c1b",
+ "beb9cc8c 3f11c1c6 bf4b6453 b7c1bbf5 36d33e9d b79498e6 3935f30e -> bee2d810 b79cd727 3a391a2b",
+ "3e846f84 3f160b22 3f17a332 00000000 00000000 00000000 38095bf3 -> 3e655111 00000000 3932068b",
+ "3eafdec8 3d9b49e0 bf2b3e3f 3a03a379 39ccb0ad 39e49c07 3762e499 -> 3f13f29f b6935c80 3905f143",
+ "40d20100 4233ed7c bebfc980 3712ed16 b6621752 b71a3977 393019c5 -> beb4bb2f b7cf0e34 3a6251c8",
+ "bf071a40 c2347826 406e4650 b8520c30 b91912f8 38cc1337 3a4f9ae0 -> beee008a b92a82de 3b2efcba",
+ "c1e3c92a 42060632 41f41bf4 b72b16b7 b7fe537d b82e942c 3794c6ed -> 3f41bc50 38d6a88c 3a51ba4a",
+ "bf0d589c bf382218 3e48e270 b72eed10 b6f51ce3 37457258 3a5a92dd -> beb7f6c4 38411231 3b7b1353",
+ "4153b794 c0f54810 c19da49c b73318e7 369cb2b9 b79f215a 3884f3c8 -> bf2a0286 37b6dd68 39fa4610",
+ "420f1f04 41f5a054 4246760a 00000000 00000000 00000000 3667f7bc -> bdaa055c 00000000 3a790b5f",
+ "bf35ec26 bf56291c 3f615906 b9a912c8 391c595e 3a4c441d 3a302615 -> 3f49d560 3ad953d2 3ae68df2",
+ "c09da300 421f3c5a 4177e530 00000000 00000000 00000000 368f2aeb -> 3d78a56b 00000000 3a099c5c",
+ "41e005fc 41aa0c3c 41aee374 37b314ae b7bb159d b9543c48 366c357c -> 3e422c3d b9a00ae0 3a202770",
+ "3f720358 bf65ae71 3f500e82 b720a65e 36020531 b591f711 35bb088c -> bebf59ff b79c7779 38b294cd",
+ "bd5e5500 beaaacae 3f629e22 00000000 00000000 00000000 37d2ed4b -> bf0522b1 00000000 39297da7",
+ "c1260454 4211dce4 c2032074 00000000 00000000 00000000 397d2536 -> 3ededdd1 00000000 3aa979c5",
+ "c20a0fb1 40ed7568 c23d32d3 b8693ba7 b808237c b8b6aafa 39eede20 -> 3d6ec4ef 396cb143 3b044bf9",
+ "c085cc30 419c85b0 41377c44 b9bbbf53 37b2f61d b97dd1d2 37ad740b -> bc6039a6 ba49b4fe 39c6b6f5",
+ "c208c553 c1a2a407 41f896fc 364eaf37 3604f3f4 b605e89e 35d9fe49 -> be2a71d2 b6b0757a 3a3bb647",
+ "411d2754 c2282b0b 420075d4 39b29abe b91730e0 b8c65b50 36d09152 -> 3f162e3a 39486164 3a3e3c91",
+ "c2130a79 c1505028 c23d2531 38266946 b7e07f60 b6f767f7 36c23c6d -> 3db69226 b6d4225c 3a547395",
+ "3e9e3848 bed38654 3ea8087c b7eb82e7 38200e75 37eb7d1c 3811bf09 -> 3e3d692c b895fe51 390c5356",
+ "bf5ffc7a 3f7bc398 3e5d3a28 34770c17 b4d1b1e5 35a1bb36 358e688f -> bed267c8 35168803 38a90a64",
+ "bf3a8c2e be9a15c6 3e69fc80 b7b33f0d 37a797e3 b785f8bc 3859731c -> be1476f0 38917912 394ae529",
+ "bf0365f0 3f06df42 3f67b238 00000000 00000000 00000000 38e03a4c -> be0422e8 00000000 39bcf61c",
+ "c107396c c16e6ee0 c17d71f8 00000000 00000000 00000000 38552a8e -> be8662eb 00000000 3a2107de",
+ "be9cb308 3e85cb10 bf7b2b7e 00000000 00000000 00000000 394a4746 -> be86b896 00000000 3a0b7472",
+ "41b94ca8 beb1b900 c14c1150 35f2b738 350a7fe3 37064752 38e4a6ed -> bd865874 b758f515 3a0fd310",
+ "c1b13687 c0a5a400 410dbc90 b6b921c2 36b8e729 b5a5173f 35aff3cd -> 3e54d044 b76caee8 39b24eed",
+ "4217975a c1ba9fea 42393fde 364d3082 36f764da b6ad7434 35889b10 -> bda6bdbb 3746212d 3a66c1fd",
+ "be925392 bf65e129 bf72707e 3926698a b9801f74 b952b9a3 368f72c7 -> be8bf82d ba1b3472 38beb937",
+ "c0635e70 c14dcfbc 4148f85c 00000000 00000000 00000000 35dd75e3 -> 3e1552b5 80000000 39959f44",
+ "bdcd85b8 bebfab4c 3f1a0ab0 b6c05d82 369bb8ef b7138756 387bd9ba -> 3e6fc248 37a85ac9 39680818",
+ "4055caf0 420b92f0 419efbf0 b894be03 b82e709b b8bd57eb 3a2dbded -> 3d7fa498 390f95a8 3b15ed42",
+ "c0fa64f0 41e8a9bc c000c190 382a4e0f 36a387c1 b84de54d 3a3215f2 -> 3e17d679 b8d9c22a 3af83688",
+ "3e907fe4 3f30bda6 bdc897a0 36a51cfd 38b55f65 36cc74de 39322c9e -> be706181 b7ecc166 3a140d02",
+ "3f662a2e 3eb15cd4 bf17138b 3703e63e b81d25bf b88a3e49 35fe6c76 -> be7b142a 370cccfd 38a21679",
+ "c22c6cfe 422c01de c20102df b8008f03 3933fad2 39bc7130 3814535d -> be0a50bf b8cc0bc8 3a9430dd",
+ "3e78e9a0 ba320400 be39db1c 00000000 00000000 00000000 399b383e -> 3f170b06 00000000 3a4b8d06",
+ "be5115cc 3f4b521c bf5ff324 369faa82 3601f4f7 36bc1bfb 36e4d6ce -> 3ec89075 b5d920f4 38c3934d",
+ "3e2fec30 bf29924a be5d0d48 b9e46737 b9201758 38193ba4 37adaa63 -> bee241f9 b6a84ec0 38fe0b45",
+ "3eabc018 3e591600 beae116a b58ae8c8 34b8b0e1 b558304f 359fc6e3 -> 3e3dbda8 363a692c 389726e2",
+ "c1bcd5e2 c2181d88 bfa2c4a0 386839ec b80d9f56 37150ddb 365bb1ff -> bd4a07a7 b963a8e8 3a108ba2",
+ "423f2358 42198438 40d6b9b0 ba515e5c 39a0fec4 b843605b 370e421d -> be07524e 3ae307fc 3a545fba",
+ "42442bc4 40047ea0 416a77f0 00000000 00000000 00000000 359a9e31 -> be6527f2 00000000 3a13aadb",
+ "3e096b40 bf18f5b2 bd98e2c0 00000000 00000000 00000000 381ee26e -> bebaca3f 00000000 392c8f80",
+ "beed1c7a 3f27f5ba bcfc7860 3607f25f 34e782fb 35c9fb80 3a005e1e -> 3f1a1254 3623632d 3ae76164",
+ "3ede1284 bf72b8f1 3eeed8ec b7285989 361c30e6 36d27bc2 366d6f8a -> 3e6ea6ad 37a14c3c 38b53ae4",
+ "41bbafd8 42120b4e c081c068 b42ec4c6 b54c39b5 36078a7e 38f0dd17 -> bec2ad26 b592aa58 3a28205e",
+ "c20ef158 42325c5e 421aa3f6 00000000 00000000 00000000 38931e2c -> 3d67c8d8 00000000 3a8c978f",
+ "bf05e71c 3e5af218 3f77191a b5313775 b5b81ddd b585513e 39873afd -> 3dfca400 36144135 3a2c5ebf",
+ "be76e3c4 bf06e2fc 3f018ab4 b5fc2761 b7101bd5 b7259d67 365e7ab3 -> be45b561 b7d130bc 38abbe7a",
+ "c1523fe8 41c111d8 4245352c 3820f0f5 3690661c b71e7064 394990e3 -> 3e6e025c b795c530 3a85d934",
+ "bf38a988 3ea770bc bf29aec0 b6046e94 b6a06e4b b5f60232 398cb975 -> 3ea4592e 37141908 3ada3e5e",
+ "3e502098 be821bd4 3f60fb76 3915e8c5 37e9782b b82b0a63 3a3a4308 -> be474176 b8cadc02 3aa0be3a",
+ "422137e6 3fa4a5c0 421e7df6 00000000 00000000 00000000 3758d26e -> bdb0433e 00000000 3a3d179d",
+ "41363870 418c8ab8 c1d7641e 354e49a5 35542aa5 b520f2f5 37e91740 -> 3f16355e b655cfb4 3a14d08a",
+ "bf5d343c bdbfd1d0 3e3bbd78 00000000 00000000 00000000 391c37e1 -> 3e14f3cd 00000000 3a1dea64",
+ "3e035ae8 3e65e800 3f1a79de 35aa776a b5cafff2 b554856a 3650c79d -> 3ca348d8 b505c934 389cd11e",
+ "3e292228 3ee22618 3f3c5ff4 3929218f 3990748f 3987d9aa 38535d5d -> bdbb7cc9 b8c3fb7c 391bf985",
+ "bf77f631 3f7acfd2 3f2caca4 b6a7faef 3696fd38 b5bf38cc 38216ae6 -> 3ea91cd3 372ef9e0 394a906e",
+ "bf3aef12 3ee020d8 bebc5e48 00000000 00000000 00000000 3a37f4cf -> 3ecd6001 80000000 3b03f2fb",
+ "c10f85bc c1484eb4 419c2c1c b4aad798 b56d8d7e 34c3139e 363a4566 -> 3e970871 b5b39dd4 39c68a55",
+ "bf2b8bb2 3f35a9a8 3f65b4fe 00000000 00000000 00000000 381c52bb -> bd1ae63c 00000000 39193c58",
+ "3ea822c0 bf74a083 3f0fb74c 394e06c4 39a13ead 39a7cc1d 3954e1f7 -> 3e87707a ba222e99 3a406c74",
+ "410167c8 c1c1093b 410ca9fc b70860cf 37bb24a6 377ea164 383699bc -> bd1c1a10 b887b7de 3a0d8e4b",
+ "bf25d255 bf4fdb43 bea59878 b7081d38 378a25df 3737b702 392ff411 -> 3e19831c b7977800 39c9cc89",
+ "bead8206 be29e268 be720d98 b73ea051 b6b0816a b6950153 380d1c66 -> 3e2a8494 b7ec677b 391451b8",
+ "c0ea0fb8 41efe068 41a365d0 36099420 b6af1783 b6930cfd 36853437 -> be8de572 b7272324 3a064fd3",
+ "c2012c68 c05de050 40d052c0 38d1a9ea 39266e82 39da2387 36afe53f -> 3ec17651 39915561 39d6c14a",
+ "bf160490 3c181b00 bf314502 35a51676 b60958c5 3619fc40 398c2bb8 -> be3247a0 b5d4e0c4 3a217856",
+ "c0ceff28 c19d5e2b 423dbd36 00000000 00000000 00000000 362227e0 -> 3e99f27a 00000000 3a2496dd",
+ "c13058d4 c2453334 c16a1f68 b642d5a7 b6190007 b721b7ad 372ef509 -> 3d248017 b80dd421 3a2fd796"
+ ]
+ },
+ {
+ "glsl": "vec3 cultmath_af_fbm(vec3, vec3, float, int, float, float)",
+ "tolerance": "ulp-bounded, reach 1e-6 to 1e-3",
+ "check": "the arguments are (cx, cy, cz, ax, ay, az, radius, ...) and the result is the form (x0, a, e). Enclosure: for eps in {-1, -0.5, 0, 0.5, 1} and d in {0, +-ex, +-ey, +-ez, (+-1, +-1, +-1) / sqrt(3)} (15 directions), form the point p = c + axis eps + radius d in double and round it to float32; the device's own reference value at p must lie in [x0 + a eps - e, x0 + a eps + e] with no tolerance, so a device whose gradient error exceeds the allowance fails. Tightness: with L = 7.9640074 and, for each octave (one for af_snoise), R = |axis| + radius, B = L R + 2^-14 + 2^-12 R + L 2^-20 (|c|_1 + R), the width |a| + e must be at most B + 2^-16 (1 + B). Report the least slack of each side, absolutely and as a fraction of e; only the two bounds fail the check. The reference value is cultmath_fbm_grad(p, octaves, lacunarity, gain).w, and B is the sum over octaves i of gain^i B_i, where B_i is B for the centre lacunarity^i c, the axis lacunarity^i axis and the radius lacunarity^i radius. These cases have reach |axis| + radius of 1e-6 to 1e-3, where the float32 allowance is most of e and the second order remainder is not; the enclosure above fails a device whose gradient error exceeds the allowance. Centre leg, for every cultmath_af_snoise and cultmath_af_fbm family of this fixture, the earlier ones included: the fixture's own x0 in the result (C#'s value at the centre) must lie in [x0 - e, x0 + e] of the GPU's form, with no tolerance, so a device whose noise differs from C#'s by more than its e fails.",
+ "cases": [
+ "3f34327a be330120 3f3da1b8 3774dae1 b706c4b2 b84b80f6 36dcf110 00000004 40000000 3f000000 -> 3c5e7638 3909beed 397d0650",
+ "3e9594c8 bdc680d0 3e845a64 3415e1fb b5f5b7b4 b43c93e2 3a52b06c 00000004 40000000 3f000000 -> be5f5b71 b5158925 3c160240",
+ "bc93b780 bb2fb800 3f2ed8b0 00000000 00000000 00000000 36694e2d 00000004 40000000 3f000000 -> 3f66201d 00000000 392e9ae8",
+ "3d863eb0 becaa00a 3d040d80 b90dd6fa 393b6325 39753445 3710aa74 00000004 40000000 3f000000 -> beb877c6 39df7941 3993e965",
+ "c19d9f93 c18c6396 3dd97200 b64b03f0 b56a8741 3633e5c5 3922a3ab 00000004 40000000 3f000000 -> 3f2c7106 36299b78 3b33a96e",
+ "be7a5ec8 3f743008 be282e30 00000000 00000000 00000000 3a4ce666 00000004 40000000 3f000000 -> 3eb11f0e 00000000 3c2b72d0",
+ "c150b7fc c05bfb60 c1493628 392182bc 39e5f647 b9de781c 3a09a353 00000004 40000000 3f000000 -> 3e4503d7 3b226c9c 3bedd68e",
+ "bf6464e8 3c2b6100 3ea52a00 33e53557 355b28ea b5a30c56 3a2995aa 00000004 40000000 3f000000 -> 3f58aef7 b5ea5135 3bad1852",
+ "410c1850 423d0648 41a41564 00000000 00000000 00000000 3908b42d 00000004 40000000 3f000000 -> bf014dc1 00000000 3b965487",
+ "bdff2b60 bf0406c7 becda42a 35cf24bf b533cf68 35a37ef2 37b70f66 00000004 40000000 3f000000 -> 3eb9dae2 b6b26ccf 3a00bb48",
+ "c06f95a0 42377004 421d47c4 b7012f36 3592b3fa b6dd5d35 373cc137 00000004 40000000 3f000000 -> 3e85ed76 371f6f46 3b423262",
+ "408d7948 421ffe80 c11ffa20 396d3819 b89e7c4d b91241c1 38537c62 00000004 40000000 3f000000 -> bed52d26 3ae20321 3b16fe9c",
+ "41d06b34 c1a9f1dc 416d2a30 b6ad129d b7212019 3644e1cb 3a375b08 00000004 40000000 3f000000 -> 3ecc0274 b8235f0a 3c2a3122",
+ "3ececc64 3de336b0 be6dba50 00000000 00000000 00000000 3723d0c2 00000004 40000000 3f000000 -> 3eb91274 00000000 397bddec",
+ "c2071164 c182d8e2 c213efff 00000000 00000000 00000000 39ea70f4 00000004 40000000 3f000000 -> beca3b2e 00000000 3bcd3578",
+ "41bd065c c1054b48 c2234971 37f67a85 379a153c 374f2b36 35f54979 00000004 40000000 3f000000 -> 3d165d2a 38a2e227 3b19ef94",
+ "3d9ccbe0 bf66c09a 3ebfa574 00000000 00000000 00000000 370f28a3 00000004 40000000 3f000000 -> 3f1aecc4 00000000 3982ea9c",
+ "bea831ca 3f6ab10a 3f5e5a38 ba0d96e7 3a23dcea 39da5a1a 3814335c 00000004 40000000 3f000000 -> 3f3cda9e bb10d2e4 3a682c11",
+ "c1c3a880 41f4a380 c1effc06 37721df0 367d7962 358e675c 383d06e9 00000004 40000000 3f000000 -> bf15b177 b76deea6 3b5374bd",
+ "42095436 41b5a25c c1e01948 38e7caac b824d694 38954c7a 35972458 00000004 40000000 3f000000 -> 3df85f0b b95e142f 3b3228d7",
+ "c11a8fcc c20a0c0a 41ecb8d0 00000000 00000000 00000000 3586dcbb 00000004 40000000 3f000000 -> 3e4f4b3a 00000000 3b1b737d",
+ "c225ec12 c20de114 4240668a 00000000 00000000 00000000 39a253c3 00000004 40000000 3f000000 -> bf2ef7d7 00000000 3bd65e65",
+ "c23f569f 40510720 c084f958 b9d1b4e1 ba3dab5a b9e495a0 3829dc2e 00000004 40000000 3f000000 -> bf0d0d76 3af367c9 3b2874a4",
+ "4145eec0 c22877e5 c21a1738 3985edae ba085a54 ba03a84c 3a7f897e 00000004 40000000 3f000000 -> 3dfd2569 bb1d9d5e 3c411be3",
+ "3f716e94 bf231891 3f4fe75a 00000000 00000000 00000000 358fb6ac 00000004 40000000 3f000000 -> beb3237b 00000000 394e1096",
+ "3f514f24 3cc26e80 bd981660 b8d82cb8 b885aed7 b8eebcf7 390903ac 00000004 40000000 3f000000 -> 3f3f2547 3a3af2a6 3acf86c7",
+ "bd9dc4e0 3f3cfe4a bf4a8123 b4ba22e6 b5ebc07d 3594eb62 382481b3 00000004 40000000 3f000000 -> 3e01d8e7 b6ad1ebb 39eaddd8",
+ "bf523222 be5d350c be08aa44 00000000 00000000 00000000 3613b968 00000004 40000000 3f000000 -> beb68223 00000000 39337cb0",
+ "c21be42c 423687e4 c21366a7 36551035 b66f2684 370a0a4a 36d7203f 00000004 40000000 3f000000 -> be5bdf57 b87d0c0c 3b7fc1ea",
+ "3d600720 bf2a2ee2 3f4519f2 00000000 00000000 00000000 38e21d4c 00000004 40000000 3f000000 -> 3d83969a 00000000 3a8ea9b0",
+ "42215390 c2337bf7 40a930d8 00000000 00000000 00000000 39c35ac9 00000004 40000000 3f000000 -> 3eeb5095 00000000 3bd96bd6",
+ "bd85e0a8 3f639ee2 be70535c 36b3354c b785cda5 380335bb 35e6fef9 00000004 40000000 3f000000 -> bf80f8b4 b90f092c 3938f5da",
+ "c1c4d1d5 c12e243c c18472ba 34cd5fa9 35ac5d88 b5cf627a 35b23677 00000004 40000000 3f000000 -> bee1e211 3619a83d 3adffc60",
+ "bf2071e1 3e66ba10 ba430000 b8918e3a b81b4882 b8f1de4f 37f54e42 00000004 40000000 3f000000 -> bf370b6e 38a85e98 39d87864",
+ "3fe5fe60 4234e8d2 c2070f7e b73232b8 b99eaa64 b82c1e97 397353e0 00000004 40000000 3f000000 -> 3f09468d 39bfed9f 3baf774a",
+ "be2451e0 3f011b78 3edc8afc 00000000 00000000 00000000 3a105c24 00000004 40000000 3f000000 -> be28a946 00000000 3ba45044",
+ "4209d296 c1d5e556 41d4925c 00000000 00000000 00000000 3a75c916 00000004 40000000 3f000000 -> 3f602435 00000000 3c4bbf61",
+ "c217a314 c228861b c1698070 b577050e 368d0794 35a905bb 36c10fcf 00000004 40000000 3f000000 -> 3ee068d2 3738920a 3b47d6ec",
+ "c23cbde4 419d4b7c 42159fd2 b70d6f02 370a2255 376dc7c3 378c27e7 00000004 40000000 3f000000 -> bf20135f b8886e3c 3b643788",
+ "c193f598 3f13fd40 c16231c4 390795f0 b8393bc0 38947e38 380bce49 00000004 40000000 3f000000 -> 3eb49fb1 3a877674 3abd2ba2",
+ "3f66044a bdca91e8 be5e9a2c 00000000 00000000 00000000 39a38e8a 00000004 40000000 3f000000 -> be1ad0cc 00000000 3b6e5249",
+ "c1e395f6 4156f874 41c19604 b66e2d24 35899935 b6524aaf 391bd47c 00000004 40000000 3f000000 -> bdeebd14 b80aff3f 3b79497c",
+ "c1befe77 41331818 c1bc0235 00000000 00000000 00000000 36e2eaf4 00000004 40000000 3f000000 -> 3f898542 00000000 3b013707",
+ "4150c7c8 41cebee0 c2124dd4 351c918f 359543d6 35a2b424 35a9a590 00000004 40000000 3f000000 -> 3e8301f7 35b318dc 3b1eaa9e",
+ "3ed69998 bddb6358 bf040aad b5c40026 3619b869 b46ee9fd 383a810a 00000004 40000000 3f000000 -> 3e2c42ff 35dfb117 3a124bf5",
+ "418fe5cc 41a13f10 423faed2 b976afc8 b9a52766 393bfca6 3608c0c3 00000004 40000000 3f000000 -> bca01ea2 3a832d8f 3b38fcaa",
+ "c065da00 c0e6a320 404117a0 362c225c 358eed60 3669a6a7 374ec7c3 00000004 40000000 3f000000 -> be0277a2 371f9874 3a22c12c",
+ "418d96e0 4181143c 4189bc94 35c0b512 35b2b813 360185a9 3910dace 00000004 40000000 3f000000 -> be66976c 377e46e6 3b536e0a",
+ "c20f5c57 c21810ed 40424260 3697fda3 3746c652 370165fe 377a60e9 00000004 40000000 3f000000 -> 3ea75939 388fcbbe 3b273f0d",
+ "bf14eb68 bf57a258 3f74858a b7a5d393 b819aaff 38927973 39447106 00000004 40000000 3f000000 -> 3efd3e97 38d4316e 3b329c4e",
+ "3f3dec9c befbce40 3f102862 3737bb02 b818f687 b81582f7 39e7f43d 00000004 40000000 3f000000 -> 3e9f7627 393e9a77 3b9eda58",
+ "c20e6ec8 40cce9e8 c205f730 3823e385 b75c09a0 380c6b78 3a2ee242 00000004 40000000 3f000000 -> 3e179330 b8de69ea 3c26e920",
+ "3f3511b0 3db3dac0 3f265f78 b91f9b64 3817a3aa 388df655 359f0e30 00000004 40000000 3f000000 -> 3e621513 ba1fa011 393ffdb8",
+ "3f56a6ac be9a05c0 be639760 00000000 00000000 00000000 386e79f7 00000004 40000000 3f000000 -> bedfb649 00000000 3a578037",
+ "bea59ad2 bee46b28 bec1fd02 355cdb93 b52215a3 3297d5c8 37b69540 00000004 40000000 3f000000 -> 3f31858e 357d2929 39c705dd",
+ "3f53d77e beadaac6 3f6db504 00000000 00000000 00000000 376e322c 00000004 40000000 3f000000 -> bec64cc0 00000000 399a6ca6",
+ "419c3fcc 4212912a 41ff0730 b42f20dc b598134c b54e006a 37296dc3 00000004 40000000 3f000000 -> 3eab18c9 33e7f5c0 3b3ead91",
+ "40992a80 c19e8b3b c045da20 b55f67dc b581452f b5968801 358bdf6f 00000004 40000000 3f000000 -> bf5b7096 36f7e17c 3a7eb51e",
+ "bef12dde bed0f58a 3f7bb0ec b78b6a62 374134fc b6ce9f48 38ed08c4 00000004 40000000 3f000000 -> bee98d9c 38540eca 3adf397f",
+ "41dfaf6c 4242a89e c1f32879 3641048e 34e0bd5d b6adc411 37c6f3e8 00000004 40000000 3f000000 -> bf169582 b6f14f60 3b6a3fb0",
+ "c21be13e c1bcb33d c1976ec3 38332936 b8a54bc4 3718c9a3 37d788b1 00000004 40000000 3f000000 -> bf12dc10 39c81aef 3b39f032",
+ "beed6928 3f46878e bf6fa323 b6222fa9 b51a3e0c 360fa338 36fbb2aa 00000004 40000000 3f000000 -> 3ea93587 b3cf7520 39863926",
+ "3eb84a8c 3ee65b30 be8d4572 36e9e9a7 3897a09e b9f41d1e 363094bd 00000004 40000000 3f000000 -> be7679c6 ba1f2766 398d5ddb",
+ "3f4dbfcc 3f1bd4b6 3e7200b8 3458463e b7235561 371e9e77 3a713649 00000004 40000000 3f000000 -> 3e254c45 35d69708 3c0444d2",
+ "bed8fc5c 3eb477e8 3f718752 b73d5e79 3732e5dc 374f95a7 3805c730 00000004 40000000 3f000000 -> be1c02d6 b64aac70 3a0e1ca1",
+ "416c3150 c233e073 423a7918 365d112d b6286a83 3713a713 360da2d1 00000004 40000000 3f000000 -> bf380b26 b71f1b0a 3b5d248b",
+ "c21f9a0a 41647ab0 3f93afc0 3728acff b57beff2 b6c86d4d 36c0c4fb 00000004 40000000 3f000000 -> be6aeb55 38a27f7e 3af6c508",
+ "c1095ea4 be8b1d00 c1fcd481 b702c1d9 b7b352c2 37370026 39ffecb3 00000004 40000000 3f000000 -> 3de1e4e9 3903b932 3bca0998",
+ "3e5a2c30 3eb14df8 be619bd0 b9155479 38d42515 38cc136c 359f8485 00000004 40000000 3f000000 -> bd3e752c 3a4a0ac2 392f838d",
+ "c220b1ce 41797550 c1b876f1 35ce4893 3583b5ff b617f858 358cc3fe 00000004 40000000 3f000000 -> be62150f b6d8a542 3b252f49",
+ "3e7a66a0 3e492d30 bf241599 379739f9 b79b2d88 37a294ef 382594a6 00000004 40000000 3f000000 -> 3f516f1c 38ec20f3 39ed7cfa",
+ "3e874ad4 be059b08 be08ef74 b62e3c79 b7b1f3f8 b89851df 398f3799 00000004 40000000 3f000000 -> 3ee3fe36 b90e7436 3b83b694",
+ "4148fea8 3e857a80 c186d56c 00000000 00000000 00000000 3a616b4d 00000004 40000000 3f000000 -> be87056e 00000000 3c1389f9",
+ "bf0b5572 bed33e2c 3ef13bf4 36d5a1e2 35f8d14a b5477d2b 3a77adb5 00000004 40000000 3f000000 -> be81b1c3 368eb8e2 3c24588a",
+ "bf232ac0 423a0134 c2363e26 374063ac b682bd5c b6d242d6 37fc8729 00000004 40000000 3f000000 -> bd272e15 b88cedf4 3b4f9760",
+ "bf0df084 3f0cf8f4 be4eac80 b9eca763 3928717f ba2d41cb 3a7ea28d 00000004 40000000 3f000000 -> 3e8cafb0 bbb4c5d1 3c4c5fa9",
+ "c1ba94ec c2336e7a c0aaa1d0 00000000 00000000 00000000 3a1972af 00000004 40000000 3f000000 -> bf1cb1db 00000000 3c08c9dc",
+ "3f08efe0 3f37796c 3f1d8f84 00000000 00000000 00000000 3a5b8ecb 00000004 40000000 3f000000 -> bd20ade1 00000000 3c2d7bd4",
+ "3e6b7800 bfdb42a0 422db02a 357d5ef9 36b0ace0 b6ad67c3 36d54b47 00000004 40000000 3f000000 -> 3f85a57d 3729211f 3acb5f04",
+ "3e8a7958 bebdcc7e 3d913c90 36e7fbc3 b596d247 b6807d6d 36c528b7 00000004 40000000 3f000000 -> bdaffb50 3644e5c8 393147d9",
+ "c1b0d231 4214d97a 41c13888 35066c98 3753a56e 37461679 3853b226 00000004 40000000 3f000000 -> bed16622 38a1688e 3b645bb7",
+ "40e19628 c081b288 419754e0 00000000 00000000 00000000 36dd3d40 00000004 40000000 3f000000 -> 3e0c974e 00000000 3a955ad4",
+ "be89ba6a bf4a8d21 3f69a2fa 36d1f6a4 364d7f85 36b01e7c 3794af6e 00000004 40000000 3f000000 -> 3e2fae58 3842180e 39b8d324",
+ "40969e40 c0405710 418e6960 36ff0446 353a1f63 37e5a063 39e3e8a9 00000004 40000000 3f000000 -> 3f1bcfd6 b7be6902 3b835054",
+ "3ef722f4 bc82d280 3f0a0ad8 b9d87a9e 38fc9120 394b2032 376c000b 00000004 40000000 3f000000 -> be14263f baa3122c 39ba62e3",
+ "4148c6bc c0394060 c2003448 b9a59140 b978eac2 b8efdaff 385780c7 00000004 40000000 3f000000 -> 3e67316e 38797528 3b076d16",
+ "bf75a754 be137f5c bf72ae7b b5e7770c b54caa10 369f4c41 398353dd 00000004 40000000 3f000000 -> 3e096f03 354b5040 3b322b84",
+ "4191eff8 c1ec4aa6 c1fbfea5 b6d5298d 36f4dd70 b658a583 374983d6 00000004 40000000 3f000000 -> 3ec2196e 37d0fc81 3b2efbfb",
+ "42410138 42384688 422c5384 00000000 00000000 00000000 380ac47f 00000004 40000000 3f000000 -> 3f2bfe90 00000000 3b9a00c1",
+ "c1a7a252 419faf54 c1bf031d b68b76af 36a7b0fa 36ab3efa 388dc0df 00000004 40000000 3f000000 -> be779d18 b746f16c 3b2fa0f7",
+ "c0599540 c13ab534 c1ebbce0 36d60c20 b4615afa b6d86141 37fd56c1 00000004 40000000 3f000000 -> 3f03f077 b7f92e65 3ae92a1f",
+ "c1ab2967 406a6ad0 41f2d490 00000000 00000000 00000000 39b05644 00000004 40000000 3f000000 -> 3f450922 00000000 3b90e878",
+ "3f937560 c1a89c93 4111d7ac 00000000 00000000 00000000 38021002 00000004 40000000 3f000000 -> bee9cfb0 00000000 3ab2bb8b",
+ "3f427064 bea51598 bf280012 00000000 00000000 00000000 3a5c5846 00000004 40000000 3f000000 -> 3e365e53 00000000 3bccf912",
+ "422057c8 41dd67b8 c1a7b400 ba127a0e 39e2b97c b8e818d9 3625b90b 00000004 40000000 3f000000 -> bda7125f bb45adf6 3b482f1c",
+ "be7bc658 bc098900 3f3cf508 38a81cf7 b90cf016 38c54795 39ffb9d3 00000004 40000000 3f000000 -> 3f49f3d9 ba22e0a1 3bde13d8",
+ "40b867b8 c20a3b6d c1295e30 38806351 377179b8 38bd3016 3807ec2b 00000004 40000000 3f000000 -> be712daf 38c00d06 3afc47c0",
+ "be5f6da8 3f3cf0ba 3cc23a80 b65099a4 370a6844 b76c2514 380819e4 00000004 40000000 3f000000 -> 3e9ee5ea 37a1e69e 3a18aa18",
+ "3f142b6a 3f48154a 3f4131e6 39959f96 b992e4a3 b960bb55 35af16a2 00000004 40000000 3f000000 -> be54aa7b bacc1804 39911aa3",
+ "3dc7f660 be27d824 bf38e58e 38a26e32 386a07a7 b7def4e2 3651571d 00000004 40000000 3f000000 -> 3e3ba09d b7ca7b00 3941caf0",
+ "c235e0b6 41b5a584 c0a6a298 b52da694 336e1180 365feee6 367ed96b 00000004 40000000 3f000000 -> bef78bbe 36b38d12 3b1c34be",
+ "423615f4 c13ae4f4 c1c7ec62 b8904027 3855e49c b88ee431 39104491 00000004 40000000 3f000000 -> 3e9f5b91 3a11c47b 3b87c482",
+ "be8f5f96 3f5c7784 3e915908 b7aef875 3862f42a 37dced1d 39b9d08c 00000004 40000000 3f000000 -> 3df346c0 b83ee280 3b5f4cdf",
+ "beaa03e6 bd8ecd10 bf040d94 00000000 00000000 00000000 3a007214 00000004 40000000 3f000000 -> be041893 00000000 3b4b1219",
+ "c0b6d858 4134d094 c1996509 b52915ad b553c221 34a775e1 39ac3df4 00000004 40000000 3f000000 -> bee21217 36a0d390 3bc13362",
+ "c204d206 c1fc214b 4158d8fc 00000000 00000000 00000000 37d6a836 00000004 40000000 3f000000 -> 3e80bdb7 00000000 3b36659d",
+ "3f67ac32 3dba31c0 bf414d32 00000000 00000000 00000000 35f1a2b8 00000004 40000000 3f000000 -> bf508b91 00000000 3947920c",
+ "3f64a8d6 be088f54 3f0e4768 b7a2f6a9 36201d8c 37b976d9 3631de8e 00000004 40000000 3f000000 -> 3f5bc4bc 37c6c3c4 39494d04",
+ "c231137a c1e5e564 c1dcd13e b6cd180f b718967d 34c7f167 36ade128 00000004 40000000 3f000000 -> be5360a8 36a2ef96 3b52cfc9",
+ "3f3dc17e bf322078 3f1c1d36 3883ce8a 37c59a6c b8284bb0 3810bf78 00000004 40000000 3f000000 -> be111927 b92ab8c4 3a0cdcb9",
+ "3f4c3398 3f1064f2 3f7455fc 3879d0e8 390cb72a 383d856e 38efb936 00000004 40000000 3f000000 -> 3e52dc6c 39ffbfa0 3ab33847",
+ "c196dcf4 c171f460 c23e3111 b92c6590 b80ebdd2 3950ddc4 37259ac3 00000004 40000000 3f000000 -> 3f198afe ba71e74a 3b312c54",
+ "bf6cbc65 3f0d3546 3f40c9de 367bfefe 3649c213 35aff100 37954481 00000004 40000000 3f000000 -> 3de824a6 b6edd21f 399ad0c6",
+ "beb9bfc4 bf5e7983 3f747152 b785930a b7b08963 b7cfdda1 3a80fa3f 00000004 40000000 3f000000 -> be9bfaad b83a2a42 3c179488",
+ "4191fb90 41df374c 418081d8 00000000 00000000 00000000 371bbb7d 00000004 40000000 3f000000 -> bf166ef6 00000000 3b0a72e0",
+ "bf3eae76 3f3b45f4 be286020 39954258 b9093ce8 b985ed35 38c6e631 00000004 40000000 3f000000 -> 3f06db46 b9805e5a 3ab65c1b",
+ "42223128 4026e240 4206a0e2 b5809c48 b4d7ce2b b53eb980 39bd6b75 00000004 40000000 3f000000 -> bf75367a b525c6d9 3be1dd6c",
+ "c14dd67c 41001060 412eaab4 b96c190b b84e6919 3968647d 3a48a0d0 00000004 40000000 3f000000 -> bf6a8e7d 3a411014 3c16d4d2",
+ "c219ef4d 41f7ad70 c2149064 39256891 39821fe3 399bf60a 3a20f2e7 00000004 40000000 3f000000 -> 3d239b30 bac4e44e 3c2462bf",
+ "3f081f38 bf486da1 3f122a64 00000000 00000000 00000000 3757d92f 00000004 40000000 3f000000 -> 3d8250b8 00000000 3993b829",
+ "3ebb6440 bf3f9bde bf000162 b43f74e6 353878d2 b5cef6b4 363dc6a5 00000004 40000000 3f000000 -> bd639822 36dbd10b 39509de4",
+ "bef93d80 3e063dc0 be940722 36647601 b5b3dd11 3781bbe4 358db7a1 00000004 40000000 3f000000 -> 3e7b7e28 b514fa80 391f2d2e",
+ "c12405dc bf7153c0 c1ec052a 38fbfed6 b8c55a22 ba1e29c7 37e72ac6 00000004 40000000 3f000000 -> be44003b 3b2d5198 3af97aa3",
+ "41eba5f4 c11c708c bfe0eac0 38a9e145 38786d67 37e81958 39789beb 00000004 40000000 3f000000 -> be16637a 3a3df8f8 3b94fc07",
+ "41186f68 c233355e c1f39762 00000000 00000000 00000000 380a497e 00000004 40000000 3f000000 -> be80094f 00000000 3b3fa8f0",
+ "3feb5ac0 415c67f4 c186c294 b69774ca b5e8c9ec b6986668 3710a248 00000004 40000000 3f000000 -> be048d6c 37d75534 3a9a3991",
+ "422850d0 41d4e258 41a7f1ac 00000000 00000000 00000000 381be1a9 00000004 40000000 3f000000 -> 3dd59176 00000000 3b6576d8",
+ "411a73a8 421b11dc 41ca6144 b9cd20a7 39b9a56d 38290019 39e4712c 00000004 40000000 3f000000 -> 3f2e97aa ba6053f1 3bca8a4a",
+ "412e02e8 40002510 3d7a5800 b649a211 b6cbde50 36eb11b9 3a16adfb 00000004 40000000 3f000000 -> becbf2fd 372959fc 3baf5245",
+ "411fac00 c20070fd c22f3fa2 b7d9c997 b7d5dd47 b7f4d333 39494313 00000004 40000000 3f000000 -> 3d9db5fd 388f7320 3b9f0143",
+ "3f6cd2b0 3f069a92 3f6dcf08 b78d6fac b89881ce b854072a 36536c14 00000004 40000000 3f000000 -> 3d59c98a 39650bef 396e0180",
+ "bf4f7394 be1c5348 be20e088 3a062979 39addccc 3a04b32d 3a010339 00000004 40000000 3f000000 -> bef19934 ba7bc30f 3bba797f",
+ "3f139704 be7528a0 bf483de6 00000000 00000000 00000000 38eb1042 00000004 40000000 3f000000 -> bd87374a 00000000 3a927a04",
+ "4202517c c17a6718 4171f440 35075a87 359c1a89 b5629205 36dc8c5c 00000004 40000000 3f000000 -> 3f44e95b b63ef035 3b0a9871",
+ "3de38b00 bf1f949f 3f47b5fe 36668604 b636d510 b6b0f73d 375a2cb1 00000004 40000000 3f000000 -> 3e2962b4 36b36aa8 39981c49",
+ "41cdf5b8 c2219208 41550a40 b8eb9b86 ba08566d 399069ab 35a5c91a 00000004 40000000 3f000000 -> bdf13c9e baf759b2 3b3067c5",
+ "3e9db0ec 3f50864e 3e843498 00000000 00000000 00000000 37ea524b 00000004 40000000 3f000000 -> 3f492ae1 00000000 3a0648af",
+ "c247d29e c1a6cb7d 422c0b6e 00000000 00000000 00000000 36e321b4 00000004 40000000 3f000000 -> 3f5058f4 00000000 3b70ad67",
+ "419a9378 422c2fe0 c2169a14 b775d912 376df81e b75ec6b5 36960019 00000004 40000000 3f000000 -> 3e110264 38a5c3cb 3b51afd9",
+ "3ebe4b48 3c675300 3ea407c8 378b4383 b7f6dfa2 b6a06742 37216e97 00000004 40000000 3f000000 -> 3cf24616 3842f5c2 39883c3d",
+ "c23bdfa1 41984444 c1f6824a 37aa8f5e 38fda980 35eef92e 371f31bf 00000004 40000000 3f000000 -> 3f25be5e b9ec1769 3b4f2f0c",
+ "be9b0126 bef27b0a 3f4c6ed2 b9134376 39999f73 b916a9a0 361db112 00000004 40000000 3f000000 -> bf07ea37 b919405a 397f37b6",
+ "3f1e9dec 3e0c47d8 be89c218 b8d98fe7 b913986e b83f2807 37115b8d 00000004 40000000 3f000000 -> 3ea7949d 3a0f7266 398c35ce",
+ "3f34434e be25b720 3f0f90e8 00000000 00000000 00000000 37243865 00000004 40000000 3f000000 -> 3f00d28d 00000000 3986809a",
+ "41bee20c c01e9ba0 c23dafc2 00000000 00000000 00000000 378993f6 00000004 40000000 3f000000 -> 3da53402 00000000 3b2294b3",
+ "c211761c c1785c68 bfec5c60 34c342bf b5566d92 b51cd554 391e876a 00000004 40000000 3f000000 -> 3e3523b4 b670e7e3 3b6f82d8",
+ "be66b480 3e21c4d8 be35e5f0 b782342a b74438a4 b6d99179 37de9eac 00000004 40000000 3f000000 -> 3eeaef8a b7d36886 39c05b99",
+ "be6e3f6c bdc2f0c0 bf75cbae b5043fe8 37250907 b7503ed7 3a4c89fd 00000004 40000000 3f000000 -> 3d16389c 38002c80 3b92bf60",
+ "3f2618b2 3f4c9e00 be9fef06 b80b41b9 b975eebb b8a1d5ae 38126081 00000004 40000000 3f000000 -> 3ea654f2 b8641ad0 3a2ab97b",
+ "c0ee8ea8 c19c1314 c20d4508 b9ac602f b95bd3ed 38d5089b 38e2d4a9 00000004 40000000 3f000000 -> 3f770c57 3a1b8c1c 3b5d9b6b",
+ "c234a5da 410dca38 41c786e0 b8269ad5 37842177 b77ba477 3a2cfec8 00000004 40000000 3f000000 -> 3e6455be b8caa9e6 3c31ebdc",
+ "bf1b53ea 3f5a92c2 bf69aef7 355b9e13 b32317c3 b55b9cb2 35a4bf70 00000004 40000000 3f000000 -> be02add9 36824ebf 394da6cc",
+ "c23db4ef 414cd848 42292856 b8888e1d b926a650 b899d4c5 3a01694c 00000004 40000000 3f000000 -> bea1b46f 3a8e3b05 3c0545d1",
+ "c1f10183 c1f1671f 41b18df0 38a298fd b863e5aa b896d89e 3741529e 00000004 40000000 3f000000 -> beaaf135 b94587cc 3b3369d6",
+ "3ec88d78 3f14a342 3f37cbee 371ead77 b30d049a b6b55629 3802d1b3 00000004 40000000 3f000000 -> beaa51f6 b7bb4ff9 3a06b739",
+ "3f6eb6fa 3e7ce7b8 3f2d701e b71f11dd b6a34f04 3729e667 371e0723 00000004 40000000 3f000000 -> bee29caa b8ae05c0 3992cc6b",
+ "be791f50 3e0ac070 3e9de130 362936b4 37a0aa23 b73e3a60 3a1b2d22 00000004 40000000 3f000000 -> bf187d3f b90daed8 3be0f1b6",
+ "bea66d46 3db1f440 3eab5a10 3574a453 b61564d8 3617ebc3 37b268da 00000004 40000000 3f000000 -> bc214646 3689f612 39c1c491",
+ "3f2287ae 3f6b7356 bef6b104 b70cb1b1 36651b33 b6d5df30 36baf607 00000004 40000000 3f000000 -> 3f0ec4e2 b81c4f1c 3987e8a2",
+ "40e03430 41d0e408 c154b580 b582241a b639f061 b635ed0d 366fb678 00000004 40000000 3f000000 -> 3dd98a45 b7848c5d 3acae0aa",
+ "bed35c9c 3f1f5abe be2084c0 b7d3103e b6de1f62 38240b65 394f99ba 00000004 40000000 3f000000 -> 3f401dac b7b2d06c 3b1872eb",
+ "41721550 bf39ae00 42329e32 b6e76d27 b5d18c21 b675f679 3733ba43 00000004 40000000 3f000000 -> beaae468 b6a671a0 3b08018e",
+ "3e8e3628 3f36b7f4 bf18e050 36b07d45 356ae656 b678df77 3a0e5a09 00000004 40000000 3f000000 -> 3e8d3006 37e4293e 3baebacf",
+ "c220480e 40db4188 4243783a 350d7e1e b6f798b7 351966fe 36398f2e 00000004 40000000 3f000000 -> bf0ab4a3 b688a510 3b4874b2",
+ "3e73eb08 3f1abbcc 3e290c30 00000000 00000000 00000000 3988a97e 00000004 40000000 3f000000 -> 3f1bd6f7 00000000 3b47bf52",
+ "41fba7a0 42148020 c1c2c42a 360be14a 361303a0 361c6db5 36e8de8f 00000004 40000000 3f000000 -> 3e1ccfb6 b781dc6e 3b43fa44",
+ "412fb890 4235acda c244021f b6b069fe 3680e6a3 364aaf0a 358fef26 00000004 40000000 3f000000 -> be137b1e 368918b2 3b5a5afc",
+ "3ed08700 c0f56f68 4238367e 00000000 00000000 00000000 39e54208 00000004 40000000 3f000000 -> 3e87c341 00000000 3bbca0c1",
+ "c20abc77 c09cf968 c14dfcc8 b9497f91 b9c3786e 3910b6d4 394a4a5f 00000004 40000000 3f000000 -> 3f1fab35 baad420d 3b7903d2",
+ "c242460c 4238198a 41809d90 357c005a 35afc3ac b59963e0 3781aa02 00000004 40000000 3f000000 -> be56d902 b6d815ca 3b70561f",
+ "bee11ffc 3d0b9e20 3e957358 b8c297de b865c867 b8d21e05 385bfbfc 00000004 40000000 3f000000 -> 3eb8d70e ba32572e 3a76b751",
+ "422449a2 c216e05c c22b8eae 372bc9e7 b6b05959 3797cfb3 364e0a2e 00000004 40000000 3f000000 -> bf1249d1 b7c9b4f6 3b7c54cb",
+ "bed4e02e bf3e4d68 3f3c9ed2 38dd5765 38f00c54 38a1404f 375a62be 00000004 40000000 3f000000 -> be736564 b9083e60 3995812c",
+ "bf2393e2 3f39553c 3ef30d98 37481458 36e47ee0 377fff1e 38e6274a 00000004 40000000 3f000000 -> bedc16a6 37f3b0ec 3a917330",
+ "3f5db59e 3f610616 bec42da8 b895a2f2 398ab793 3989e123 386811b7 00000004 40000000 3f000000 -> 3f12693b b9f1b7c2 3a5b951e",
+ "423cd10a 41ef3314 422e7720 b883574b b8dbc8ed 383bab14 36ce2c09 00000004 40000000 3f000000 -> be961e6a 392deec2 3b7cb2a1",
+ "418a1ee0 c13be004 c16e4850 b8e9c169 b9365813 b8392507 35cebce5 00000004 40000000 3f000000 -> bf8b03f0 3a8d3148 3ac38730",
+ "412210e0 c1379fa4 41d2edb0 00000000 00000000 00000000 389266bb 00000004 40000000 3f000000 -> 3e909095 00000000 3b102c4f",
+ "41ffeab8 be59ac00 4095ea50 357274f9 35589d2a b588d5bd 392acece 00000004 40000000 3f000000 -> 3ed5aaf9 36656892 3b49c238",
+ "422a5378 421b7534 c2464c2e 364364d4 b6203483 b6026b8a 3709712a 00000004 40000000 3f000000 -> bdc9d08c 36f9ccc7 3b88e57e",
+ "3e3518b8 bde33f70 bf2e3296 3505ef81 b8055719 37cd8944 39076d9b 00000004 40000000 3f000000 -> 3ee96c76 b8938fa8 3ab41bf0",
+ "bf6de812 3f0074b2 bf082782 b719bb28 b79fba1a b79c7f30 38dddd41 00000004 40000000 3f000000 -> 3edc47bb 38b23134 3a8fe73c",
+ "bf10e469 bedc9aac bf3f2ea0 b7b69202 b445d49b 37830b41 35c9bacf 00000004 40000000 3f000000 -> bee5b836 b916385c 3945d934",
+ "bf142af4 3ddfcb20 3f42f910 00000000 00000000 00000000 394daaa8 00000004 40000000 3f000000 -> 3ea652ff 00000000 3aee1442",
+ "c181844e c1ef1049 c1b54417 362fda3a 354537f6 b54e7a28 37375576 00000004 40000000 3f000000 -> 3e5d9855 b67070da 3b1839dc",
+ "41775048 c22e0740 c1c45182 376daea1 36cd7bc1 3592fbcb 3727e590 00000004 40000000 3f000000 -> 3eef2cc0 b7a08a5a 3b37cffd",
+ "c191a98a c18793b8 c1ddcc4a 00000000 00000000 00000000 373413b6 00000004 40000000 3f000000 -> be7a33b8 00000000 3b0b7592",
+ "c01c8ae0 c1edd11f c14615fc 39f271e8 b9d84315 b9d4d1b3 398fbc8a 00000004 40000000 3f000000 -> 3b919eee 392695d0 3b88dd8c",
+ "bf14831f 3f7c4bc6 3f6190bc 39f2a8c3 3a08f623 b79bdfc5 39b04fb9 00000004 40000000 3f000000 -> 3e2d1d46 3a1d9137 3b721c75",
+ "bf0ea593 bf0e30ce 3def9240 b7b5a98c b53e7f95 372ed160 35c79b16 00000004 40000000 3f000000 -> bf31c38d b88a0e36 39337225",
+ "423f5e00 c1bca9ce c1813880 b9803171 b97cfbda 394c24cd 3709cc42 00000004 40000000 3f000000 -> 3f057674 3a95e14b 3b3f55e3",
+ "421bea88 c1a191a1 c23e629c b8583435 38effbcd b8ff05bb 376af87a 00000004 40000000 3f000000 -> 3e74ecf3 385f4110 3b65fd3c",
+ "420afc0c c1b432d9 c2053234 b99eb565 b943c488 38e4e19a 37c99a59 00000004 40000000 3f000000 -> 3f22b924 3ac7b7ec 3b51819b",
+ "c0c2c570 41abd938 421fa4bc 36b6acf3 36aa4526 35ebbd6f 37a415da 00000004 40000000 3f000000 -> 3eb8be7d b7ee78e1 3b19dffc",
+ "bf18ad93 3e70d598 3e929888 37e39359 381879fa b7d95c51 35ae8317 00000004 40000000 3f000000 -> 3ec345c8 b91b438c 392dca39",
+ "c23cac06 42414f12 c228b536 b89f7d78 383f2398 b8bd07c9 38366a2e 00000004 40000000 3f000000 -> 3f0607c1 372a7dc0 3b9dc0e4",
+ "3d01b980 3f55bb10 be4224b0 b673bca8 b62e521f b558d490 358d6eb0 00000004 40000000 3f000000 -> bf88ba65 b7873c70 392ed8ab",
+ "3f463828 bf2d53ae bebb5fd2 b957dc31 b921fc01 389dd11c 399939d7 00000004 40000000 3f000000 -> bea112d4 ba2a6210 3b3c2b91",
+ "c231ff08 c22b5ed0 41ff14e8 b627efdc b55009b1 3620efe5 38b488c9 00000004 40000000 3f000000 -> be1d7973 b6a12279 3b93ff77",
+ "420b712a 4235780c 41c6b030 b8b40bc7 b898c444 b8cbbfeb 3710c789 00000004 40000000 3f000000 -> bea628d6 b99afb59 3b60275e",
+ "3d481480 3f7566da 3e054bd8 36b048b1 37b00686 371f8c64 385f9cfe 00000004 40000000 3f000000 -> beea8788 392523d5 3a485dc5",
+ "bf5b190d bed96500 3f41e4c0 374c1b03 b6030d49 b76bf288 384aee1e 00000004 40000000 3f000000 -> 3e7df1c4 37b78ac5 39f754f1",
+ "3d9d48b0 bf11aff1 3e177d90 38bde962 395c280a b8308519 375f0c92 00000004 40000000 3f000000 -> 3ed31132 3988be59 39a442f9",
+ "bf770d83 3f50a056 bba62500 00000000 00000000 00000000 38bdb583 00000004 40000000 3f000000 -> 3f3bad12 00000000 3aabfade",
+ "3f261800 c192de5a c130ea4c 38bde695 b8d2a46d 380d74ab 3687e988 00000004 40000000 3f000000 -> bcba75ce 39faafd1 3a8d2ae5",
+ "bf599d02 be7835e0 3eb9517c b8b1f11f 38a3595c b8bf15f0 360848bc 00000004 40000000 3f000000 -> becb254e 39707e86 3940507b",
+ "c11778a8 4204d562 41fc6160 b746c900 38cabcb4 b8dfd754 3a0f806d 00000004 40000000 3f000000 -> bd34b5d5 ba49b778 3c0e9ddb",
+ "41e8304c 419e2f80 41adec5c 35894c43 3530ff2a b591fe59 3983c5b6 00000004 40000000 3f000000 -> bec909eb 36a0b8c5 3ba1e417",
+ "412c2570 420fb23e 40433220 00000000 00000000 00000000 39c5466e 00000004 40000000 3f000000 -> be340cf4 00000000 3be0054b",
+ "c21cde3f 40e98188 4187ea94 00000000 00000000 00000000 39340858 00000004 40000000 3f000000 -> 3eb997e2 00000000 3b5e92fa",
+ "bf57da78 bea0948e 3eae77c0 3584b6cb 397f2c71 b9ffb94d 3601cdbe 00000004 40000000 3f000000 -> bea9b05d bae6f95b 399e6814",
+ "3f1a9a1a bf6c9825 3f0a9514 369a173d 374373e6 372dabbc 393fa3ef 00000004 40000000 3f000000 -> beeb8c03 37db203e 3b2363db",
+ "4228e33c 41c2555c 41a11a34 b71476ef 370dbb5d 37606102 3955880e 00000004 40000000 3f000000 -> 3ead9f3c b89b33f3 3b9d59a7",
+ "bf665f41 3ebc2ba0 be247ca8 00000000 00000000 00000000 389736bf 00000004 40000000 3f000000 -> bec37dc5 00000000 3ad229cb",
+ "c21f8a3e c1bd4e00 c1af028a b8d8a177 38b45a55 b85b500c 35c75edd 00000004 40000000 3f000000 -> bf284978 39e3f3ed 3b33cbe7",
+ "c1676090 bfefe300 c14b58f0 00000000 00000000 00000000 390ca00f 00000004 40000000 3f000000 -> 3eb6fcca 00000000 3b1344ad",
+ "c01fae60 417544d8 420d2d40 38c00663 b97e6228 b8ac386b 3a22f6fc 00000004 40000000 3f000000 -> 3e1a996c ba8959c1 3beb8bbd",
+ "bf370584 3e2e84b8 3f2cfbd2 00000000 00000000 00000000 389610f0 00000004 40000000 3f000000 -> 3f354951 00000000 3a511119",
+ "3f040e46 bed9ede0 3f1dd900 b55c1086 b3e6ad61 b580e75b 37e51a9e 00000004 40000000 3f000000 -> bf02f954 36a94e78 3a0a8706",
+ "bcb76700 3f1e3388 bea9f47a b9427646 37f462ed 39012235 368dddea 00000004 40000000 3f000000 -> be99bdc2 395930fa 395fe3ff",
+ "bf2cfce6 bedd5cb0 3eedfe50 378d503e b5af5255 b6b8e1c3 39349fd2 00000004 40000000 3f000000 -> be7bf26a b8b2a4de 3aea1c5b",
+ "3f437dd6 3f60d002 3f3faebc 35836c96 b5f3c7a9 b5015b8e 36356610 00000004 40000000 3f000000 -> 3f0b024b b68545f7 395d4cbc",
+ "41192298 41feebb0 420eaf78 38811c8b 37f352e5 b72b96d0 385881b8 00000004 40000000 3f000000 -> 3ede9b87 b8d90cd1 3b441a7e",
+ "3f1172f8 bf644bda 3f51a834 39894fc2 b8983c5b 3920ea29 390d595c 00000004 40000000 3f000000 -> beae05ee ba1a2217 3b1a66e7",
+ "bf57ee9f 3e906340 bed82ae2 b8e1ba6f 37606486 38f52f2e 38801278 00000004 40000000 3f000000 -> 3f56e2c6 399ff76c 3a452aec",
+ "bf23404c 3ec50b70 3e8f2758 00000000 00000000 00000000 365a2f59 00000004 40000000 3f000000 -> 3f2462fe 00000000 3944b54c",
+ "c0e93d60 c22b1379 c17dcb8c 3627d72c 35b11956 35ebb7b6 39fd9169 00000004 40000000 3f000000 -> 3e2768c0 b7948410 3be789a2",
+ "bf70d831 bf7473e0 bf7cc1b1 00000000 00000000 00000000 3824452b 00000004 40000000 3f000000 -> bebf5e98 00000000 3a3934a8",
+ "be4f3cd8 bc8e4d60 3f647e1c 3400e47c b5eff9f9 34827484 38a1ec3e 00000004 40000000 3f000000 -> 3ea8d853 b6db3b82 3a9f7d49",
+ "bf7724d0 3e6192c0 be60f9b8 00000000 00000000 00000000 3792c3b1 00000004 40000000 3f000000 -> bd980765 00000000 39d7ae76",
+ "3eb97e10 bf0002d0 bf67f1e2 b4f29cd0 b6b2275a 36f4a323 397f155f 00000004 40000000 3f000000 -> bd0c3e22 b670f794 3b45c0d5",
+ "422201d0 c1b643a6 4000c200 38783523 b827b02c b798da04 36ff08f4 00000004 40000000 3f000000 -> 3e340876 b801bf9e 3b0ec1ca",
+ "c1d1ad5b c1e3382a 41fafbf4 346665f3 b6919af6 366b547b 3930eaf0 00000004 40000000 3f000000 -> bf3d83b3 3794f08e 3b9b6004",
+ "41e327dc 41f28cd4 c10a8f3c b50c79fb 356312f6 b583dd9b 35d792ba 00000004 40000000 3f000000 -> bf1fd62e 3753a8eb 3b0fc820",
+ "42045c48 414c53e8 c2084311 b8fab05b b8989b5a 37bd1150 35953e5d 00000004 40000000 3f000000 -> bf3a3f73 390b05ab 3b28550d",
+ "bf23adb0 3f090980 3f189854 b7999ce9 b8546635 b8c26136 3a559f3d 00000004 40000000 3f000000 -> bf3a4764 37e8e94e 3c054a90",
+ "41948d70 c10dae1c 40f3c610 b5b3622c b65324af 363e3ff0 385811fb 00000004 40000000 3f000000 -> be868c52 b69e2677 3ad75a6b",
+ "bf366356 be731154 3ddcc9a0 b6c38d75 366c447e b76da5c4 3697b5cf 00000004 40000000 3f000000 -> 3e20c7d8 b87c199e 39410c08",
+ "4197f990 42402090 c1d51e68 00000000 00000000 00000000 35c47ffe 00000004 40000000 3f000000 -> 3f40a8d6 00000000 3b435025",
+ "c245f097 c20cf86c 41fd8298 b9029a47 37944eeb b999227b 3723e207 00000004 40000000 3f000000 -> 3e3a1983 ba9de308 3b79c553",
+ "c23363c8 411f2c9c c2265dab 00000000 00000000 00000000 37a2c2ac 00000004 40000000 3f000000 -> bde807a5 00000000 3b542dbb",
+ "c20d6394 c23678d5 402ff150 b9717972 37874d62 39bd1009 378d072c 00000004 40000000 3f000000 -> bdcdfad4 b98c8268 3b3d5ddd",
+ "c0856e40 41c51268 408e5180 b7135728 3413e99b 3408e663 3602dd0d 00000004 40000000 3f000000 -> 3f5c0f59 37f3828e 3a96ca1e",
+ "be4ef964 3ec71244 3e9b1188 b93e59b1 3954847a 39d8a685 3846eb99 00000004 40000000 3f000000 -> bdff5c6c 3aece48a 3a533135",
+ "c1943db8 c204a252 41ebcb4c 368f9709 b6857325 35162ae0 39860849 00000004 40000000 3f000000 -> bebc9453 36ad23bb 3bb156e7",
+ "c1f0891f 422fdf66 c04eb6e0 b8851f40 b7cef3ad b80164a0 36b20e8b 00000004 40000000 3f000000 -> bf2cc29f b92011da 3b25577b",
+ "bf4f7576 3f09fe4a 3f681a80 3a0781ec b8663a5b b9015e79 3800deb2 00000004 40000000 3f000000 -> be66c4e6 39b04e1b 3a0d1dbb",
+ "40e66580 c233f488 c1912c76 35e0c4df b5d4005e 3663d444 39d7ee87 00000004 40000000 3f000000 -> be623c26 377a08a4 3bafd2df",
+ "3f6c3efe bf00c570 3cc4f180 35131e9d b5fc996e b753cbdd 383ca8da 00000004 40000000 3f000000 -> be43affb b7957f83 3a0a217f",
+ "be0f355c beb4c064 3ea0490c 00000000 00000000 00000000 374cfe3f 00000004 40000000 3f000000 -> bd079e71 00000000 397c5e44",
+ "bf11e006 bf58c11b be62c77c 36c96bbd 36360796 36b05511 3a0fd451 00000004 40000000 3f000000 -> 3e0bd010 b7f82fa7 3ba95053",
+ "4141d688 3fd0c200 40bf9bd0 b5b9323b b6a04234 36438d71 386eaf13 00000004 40000000 3f000000 -> 3eb30e9b 379b6cb8 3aabd806",
+ "bef85282 bea20c86 bf16698b b797e38f b803c3bb b71cd356 35d0b9bf 00000004 40000000 3f000000 -> bea63cce b95142cd 393f2053",
+ "c12a4440 c19aef27 410e7b9c 00000000 00000000 00000000 35e103c3 00000004 40000000 3f000000 -> 3d9ae607 00000000 3aac2e7d",
+ "3f214f36 bca54120 bf1e6058 b4da5b13 b72a9f47 36e46766 39ab5a96 00000004 40000000 3f000000 -> 3ec02a86 37f9278f 3b8889c5",
+ "3f1e29d6 3f0c1d76 3e3ab140 3794e381 b7ccdd57 b799db12 36f4cadc 00000004 40000000 3f000000 -> 3e9615aa b934f110 397ece3d"
+ ]
}
]
}
diff --git a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl
new file mode 100644
index 00000000..f165148b
--- /dev/null
+++ b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl
@@ -0,0 +1,132 @@
+#ifndef CULTMATH_AFFINE_HLSL
+#define CULTMATH_AFFINE_HLSL
+
+// Reduced affine forms with one shared symbol over float3(x0, a, e): the set { x0 + a eps + e delta :
+// delta in [-1, 1] } at the region's shared eps in [-1, 1], e >= 0. Every cultmath_af_* function mirrors
+// math.Affine.cs bit for bit; see that file and docs/design.md ("Affine forms") for each op's enclosure
+// and the float32 rounding allowance it folds into e. Included by CultMath.hlsl after
+// CultMath.Interval.hlsl, whose CULTMATH_SNOISE_LIPSCHITZ it shares, and after its own
+// definition of cultmath_snoise_grad.
+
+// An upper bound on the spectral norm of the Hessian of cultmath_snoise(float3); provenance in
+// math.Affine.cs (SNOISE_HESSIAN).
+static const float CULTMATH_SNOISE_HESSIAN = 56.050385;
+
+float3 cultmath_af_point(float value) { return float3(value, 0.0, 0.0); }
+float3 cultmath_af_symbol(float x0, float a) { return float3(x0, a, 0.0); }
+
+float3 cultmath_af_from_iv(float2 interval)
+{
+ float x0 = interval.x * 0.5 + interval.y * 0.5;
+ float e = interval.y * 0.5 - interval.x * 0.5;
+ return float3(x0, 0.0, e + (abs(x0) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// An endpoint that would be NaN is the infinity on its side. NaN is found by its bit pattern: dxc marks
+// compares fast, so a test that needs NaN to make `lo == lo` false is deleted under its default flags.
+float2 cultmath_af_range(float3 x)
+{
+ float r = abs(x.y) + x.z;
+ float w = abs(x.x) * 9.5367431640625e-7 + r * 9.5367431640625e-7;
+ float lo = x.x - r - w;
+ float hi = x.x + r + w;
+ return float2((asuint(lo) & 0x7fffffffu) > 0x7f800000u ? asfloat(0xff800000u) : lo,
+ (asuint(hi) & 0x7fffffffu) > 0x7f800000u ? asfloat(0x7f800000u) : hi);
+}
+
+float3 cultmath_af_add(float3 x, float3 y)
+{
+ float x0 = x.x + y.x;
+ float a = x.y + y.y;
+ float e = x.z + y.z;
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+float3 cultmath_af_sub(float3 x, float3 y)
+{
+ float x0 = x.x - y.x;
+ float a = x.y - y.y;
+ float e = x.z + y.z;
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7);
+}
+
+float3 cultmath_af_neg(float3 x) { return float3(-x.x, -x.y, x.z); }
+
+float3 cultmath_af_scale(float3 x, float s)
+{
+ float x0 = x.x * s;
+ float a = x.y * s;
+ float e = x.z * abs(s);
+ return float3(x0, a, e + (abs(x0) + abs(a) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+float3 cultmath_af_add_iv(float3 x, float2 interval) { return cultmath_af_add(x, cultmath_af_from_iv(interval)); }
+
+float3 cultmath_af_mul(float3 x, float3 y)
+{
+ float x0 = x.x * y.x;
+ float p = x.x * y.y;
+ float q = y.x * x.y;
+ float a = p + q;
+ float e = abs(x.x) * y.z + abs(y.x) * x.z + (abs(x.y) + x.z) * (abs(y.y) + y.z);
+ return float3(x0, a, e + (abs(x0) + abs(p) + abs(q) + e) * 9.5367431640625e-7 + 1.17549435e-38);
+}
+
+// The narrower of the Lipschitz form and the centred (Taylor) form over every p = centre + axis eps + w,
+// |w| <= radius, from one cultmath_snoise_grad at the centre; the allowance for the float32 evaluation is
+// in math.Affine.cs.
+float3 cultmath_af_snoise(float3 centre, float3 axis, float radius)
+{
+ float4 g = cultmath_snoise_grad(centre);
+ float3 gradient = float3(g.x, g.y, g.z);
+ float reach = length(axis) + radius;
+ float lipschitz = CULTMATH_SNOISE_LIPSCHITZ * reach;
+ float a = dot(gradient, axis);
+ float remainder = length(gradient) * radius + 0.5 * CULTMATH_SNOISE_HESSIAN * reach * reach;
+ float allowance = 6.103515625e-5 + 2.44140625e-4 * reach
+ + CULTMATH_SNOISE_LIPSCHITZ * 9.5367431640625e-7 * (abs(centre.x) + abs(centre.y) + abs(centre.z) + reach);
+ bool centred = abs(a) + remainder < lipschitz;
+ float slope = centred ? a : 0.0;
+ float e = (centred ? remainder : lipschitz) + allowance;
+ return float3(g.w, slope, e + (abs(g.w) + abs(slope) + e) * 9.5367431640625e-7);
+}
+
+// Octave sum of cultmath_af_snoise, compounding frequency and amplitude as the value-and-gradient fBm does.
+float3 cultmath_af_fbm(float3 centre, float3 axis, float radius, int octaves, float lacunarity, float gain)
+{
+ octaves = clamp(octaves, 0, 16);
+ float amplitude = 1.0;
+ float frequency = 1.0;
+ float3 sum = float3(0.0, 0.0, 0.0);
+ for (int i = 0; i < octaves; i++)
+ {
+ sum = cultmath_af_add(sum, cultmath_af_scale(cultmath_af_snoise(centre * frequency, axis * frequency, radius * abs(frequency)), amplitude));
+ frequency *= lacunarity;
+ amplitude *= gain;
+ }
+
+ return sum;
+}
+
+// The axis of a screen tile's slice over the depth segment [z0, z1]; camera frame of
+// cultmath_iv_frustum_ball.
+float3 cultmath_af_frustum_axis(float2 centreSlope, float z0, float z1)
+{
+ float h = (z1 - z0) * 0.5;
+ return float3(centreSlope.x * h, centreSlope.y * h, h);
+}
+
+// The affine slice of a screen tile over [z0, z1]: centre xyz, radius w. Derivation in math.Affine.cs.
+float4 cultmath_af_frustum_ball(float2 centreSlope, float z0, float z1, float footprintPerDepth, float warpVariation)
+{
+ float zm = (z0 + z1) * 0.5;
+ float h = (z1 - z0) * 0.5;
+ float cx = centreSlope.x * zm;
+ float cy = centreSlope.y * zm;
+ float spread = (abs(centreSlope.x) + abs(centreSlope.y) + 1.0) * h;
+ float radius = z1 * footprintPerDepth + warpVariation;
+ radius += (abs(cx) + abs(cy) + abs(zm) + spread + radius) * 9.5367431640625e-7;
+ return float4(cx, cy, zm, radius);
+}
+
+#endif
diff --git a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl.meta b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl.meta
new file mode 100644
index 00000000..9cf91737
--- /dev/null
+++ b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Affine.hlsl.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5dbcf0fdd66a4a74b22f5ca1c8e33058
+ShaderIncludeImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Interval.hlsl b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Interval.hlsl
index 22c19221..bc084ace 100644
--- a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Interval.hlsl
+++ b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.Interval.hlsl
@@ -9,6 +9,9 @@
// Lipschitz constant of cultmath_snoise(float3); provenance in math.Interval.cs (SNOISE_LIPSCHITZ).
static const float CULTMATH_SNOISE_LIPSCHITZ = 7.9640074;
+// Lipschitz constant of cultmath_snoise(float2); provenance in math.Interval.cs (SNOISE2_LIPSCHITZ).
+static const float CULTMATH_SNOISE2_LIPSCHITZ = 8.117002;
+
float2 cultmath_iv_point(float value) { return float2(value, value); }
float2 cultmath_iv_add(float2 a, float2 b) { return float2(a.x + b.x, a.y + b.y); }
float2 cultmath_iv_sub(float2 a, float2 b) { return float2(a.x - b.y, a.y - b.x); }
@@ -87,6 +90,14 @@ float2 cultmath_iv_snoise_ball(float3 centre, float radius)
return float2(max(n - e, -1.0), min(n + e, 1.0));
}
+// The 2D overload: [n - L2 r, n + L2 r] intersected with [-1, 1], n = cultmath_snoise(centre). One snoise, value only.
+float2 cultmath_iv_snoise_ball(float2 centre, float radius)
+{
+ float n = cultmath_snoise(centre);
+ float e = CULTMATH_SNOISE2_LIPSCHITZ * radius;
+ return float2(max(n - e, -1.0), min(n + e, 1.0));
+}
+
// Octave sum of cultmath_iv_snoise_ball, compounding frequency and amplitude as the value-and-gradient fBm does.
float2 cultmath_iv_fbm_ball(float3 centre, float radius, int octaves, float lacunarity, float gain)
{
diff --git a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl
index e40cf0b6..6856a000 100644
--- a/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl
+++ b/packages/cultmath/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl
@@ -509,6 +509,7 @@ CultCellular cultmath_cellular(float3 p)
#include "CultMath.Phacelle.hlsl"
#include "CultMath.Interval.hlsl"
+#include "CultMath.Affine.hlsl"
float cultmath_value_noise(float2 position)
{