vusvna 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vusvna might be problematic. Click here for more details.

vusvna-1.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jean-Baptiste Keck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include LICENSE README.md pyproject.toml setup.py
2
+ include vusvna/*.slang
3
+ include tests/kernels.slang
vusvna-1.0.1/PKG-INFO ADDED
@@ -0,0 +1,395 @@
1
+ Metadata-Version: 2.4
2
+ Name: vusvna
3
+ Version: 1.0.1
4
+ Summary: Slang module for rigorous affine arithmetic with guaranteed error bounds in Vulkan shaders.
5
+ Author-email: Jean-Baptiste Keck <jbkeck@hotmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/keckj/vusvna
8
+ Project-URL: Issues, https://github.com/keckj/vusvna/issues
9
+ Keywords: vulkan,slang,slangpy,gpu,shaders,affine arithmetic,interval arithmetic,range analysis
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Dynamic: license-file
18
+
19
+ <p align="center">
20
+ <img src="https://raw.githubusercontent.com/keckj/vusvna/main/logo/vusvna-logo.svg" alt="vusvna" width="600">
21
+ </p>
22
+
23
+ <p align="center">
24
+ <a href="https://github.com/keckj/vusvna/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
25
+ <a href="#installation"><img src="https://img.shields.io/badge/Vulkan-ray%20tracing-AC162C?logo=vulkan&logoColor=white" alt="Vulkan"></a>
26
+ <a href="#installation"><img src="https://img.shields.io/badge/Slang-module-4B6BFB" alt="Slang module"></a>
27
+ <a href="#examples"><img src="https://img.shields.io/badge/slangpy-examples-3776AB?logo=python&logoColor=white" alt="slangpy examples"></a>
28
+ <img src="https://img.shields.io/badge/source--only-yes-brightgreen" alt="Source-only">
29
+ <img src="https://img.shields.io/badge/precision-float-orange" alt="float">
30
+ </p>
31
+
32
+ **vusvna** (Vulkan Self-Validated Numerical Analysis) is a [Slang](https://shader-slang.org) module
33
+ providing computations with **guaranteed error bounds** in Vulkan shaders. It implements
34
+ [affine arithmetic](https://en.wikipedia.org/wiki/Affine_arithmetic) (AA), a model that keeps track of the
35
+ correlations between quantities and therefore yields much tighter bounds than interval arithmetic on long
36
+ computations. It is the partial Vulkan port of the CUDA library [cusvna](https://github.com/keckj/cusvna).
37
+
38
+ * **Rigorous**: the exact real result of a computation always lies within the computed bounds, including
39
+ floating point rounding errors, under the weak guarantees of the Vulkan specification (no directed
40
+ rounding, no infinities nor NaNs, denormals flushed, possible fused multiply-adds).
41
+ * **GPU friendly**: no dynamic allocation, affine forms are small fixed-size structs living in registers.
42
+ Works in any shader stage: compute, ray tracing (intersection shaders), fragment...
43
+ * **Generic**: functions written once for a type `T : IReal` are evaluated on affine forms to bound them
44
+ and on floats to compute their values.
45
+
46
+ Unlike cusvna, vusvna:
47
+
48
+ * works in single precision (`float`) only, there is no `double` version,
49
+ * only implements reduced affine arithmetic (AF1, also available in cusvna as `cusvna::AF1`): the errors of
50
+ nonlinear operations are accumulated in a single error term instead of creating new noise symbols, which
51
+ makes forms small and fast but gives slightly wider bounds on long computations; cusvna also provides
52
+ standard affine arithmetic (`cusvna::AA`),
53
+ * does not provide `asin`, `acos`, the hyperbolic functions and their inverses, `expm1`, `log1p`, `erf`,
54
+ `erfc`, `normcdf`, `tgamma` and `lgamma`: SPIR-V either does not have them or does not give usable error
55
+ bounds for them, so they would have to be reimplemented with validated polynomials.
56
+
57
+ See [Differences with cusvna](#differences-with-cusvna) for details.
58
+
59
+ Typical applications are robust root isolation and subdivision schemes (quadtrees, octrees), ray tracing
60
+ of implicit surfaces and level sets, and any numerical method that must not miss a solution.
61
+
62
+ <p align="center">
63
+ <img src="https://raw.githubusercontent.com/keckj/vusvna/main/figures/levelset.jpg" alt="Level sets ray traced with affine arithmetic" width="800">
64
+ </p>
65
+
66
+ ## Getting started
67
+
68
+ The examples and the tests only need a Vulkan GPU and Python: they compile the Slang shaders at runtime with
69
+ [slangpy](https://github.com/shader-slang/slangpy).
70
+
71
+ ```sh
72
+ git clone https://github.com/keckj/vusvna.git
73
+ cd vusvna
74
+ python3 -m venv .venv
75
+ source .venv/bin/activate # on Windows: .venv\Scripts\activate
76
+ python3 -m pip install -r examples/requirements.txt
77
+ python3 examples/02_quadtree.py # adaptive quadtree around a 2D curve
78
+ python3 examples/05_levelset.py # interactive ray tracing of animated level sets (needs ray tracing)
79
+ python3 tests/test_vusvna.py # check the enclosures on your GPU
80
+ ```
81
+
82
+ See [Examples](#examples) for the other scripts and [Installation](#installation) to use vusvna in your own
83
+ shaders.
84
+
85
+ ## Example
86
+
87
+ ```slang
88
+ import vusvna;
89
+
90
+ typealias AA2 = AA<2>;
91
+
92
+ /* the unit circle, generic over the number type */
93
+ T circle<T : IReal>(T x, T y) { return sqr(x) + sqr(y) - 1.0; }
94
+
95
+ /* returns false only if the unit circle certainly does not cross the box X x Y */
96
+ bool may_contain_root(Interval X, Interval Y) {
97
+ const AA2 x = AA2::variable(0, X); /* input k gets noise symbol k */
98
+ const AA2 y = AA2::variable(1, Y);
99
+ return possibly_zero(circle(x, y)); /* circle(x, y) is guaranteed to lie in its interval() */
100
+ }
101
+
102
+ /* the same function evaluated on floats */
103
+ float circle_value(float x, float y) { return circle(Real(x), Real(y)).v; }
104
+ ```
105
+
106
+ The generic operators and functions are not defined for `float`, so that they never shadow the builtin
107
+ functions: floats are wrapped into `Real` (field `v`) to call generic code.
108
+
109
+ ## Installation
110
+
111
+ vusvna is distributed as Slang source: add the `vusvna` directory of this repository (the directory that
112
+ contains `vusvna.slang`) to the include paths of the Slang compiler and write `import vusvna;`.
113
+
114
+ With [slangpy](https://github.com/shader-slang/slangpy):
115
+
116
+ ```python
117
+ import slangpy as spy
118
+
119
+ device = spy.Device(type=spy.DeviceType.vulkan,
120
+ compiler_options=spy.SlangCompilerOptions({"include_paths": ["path/to/vusvna/vusvna"]}))
121
+ ```
122
+
123
+ The Slang module is also available as a Python package:
124
+
125
+ ```sh
126
+ python3 -m pip install vusvna
127
+ python3 -m vusvna --include # directory to add to the include paths of the Slang compiler
128
+ ```
129
+
130
+ ```python
131
+ import slangpy as spy
132
+ import vusvna
133
+
134
+ device = spy.Device(type=spy.DeviceType.vulkan,
135
+ compiler_options=spy.SlangCompilerOptions({"include_paths": [vusvna.get_include()]}))
136
+ ```
137
+
138
+ Requirements:
139
+
140
+ * a Vulkan device, with hardware ray tracing for examples 04 and 05,
141
+ * Slang (tested with the compiler shipped with slangpy 0.43),
142
+ * single precision only: all computations are done in `float`, there is no `double` version,
143
+ * **no fast math** options, see [Guarantees](#guarantees).
144
+
145
+ ## Affine arithmetic in vusvna
146
+
147
+ An affine form represents an unknown real quantity as
148
+
149
+ x = b + x_1 e_1 + ... + x_N e_N + e, e_i unknown in [-1, 1], |e| <= err
150
+
151
+ The noise symbols `e_i` are shared between forms and carry correlations: `x - x` is exactly zero, while
152
+ interval arithmetic would return `[-2r, 2r]`.
153
+
154
+ vusvna uses **reduced affine arithmetic** (AF1): `AA<N>` stores exactly `N` coefficients, one per input
155
+ variable created with `AA<N>::variable(k, interval)`. Nonlinear operations approximate their result by an
156
+ affine function of their input, and their approximation errors, as well as all rounding errors, are
157
+ accumulated in the independent term `err`. Forms therefore never grow and cost `N + 2` floats, but the
158
+ correlations of these errors are lost: `sqr(x) - sqr(x)` is not zero but an interval whose radius is twice
159
+ the error term of `sqr(x)`. AF1 is the only mode of vusvna. cusvna provides the same reduced forms
160
+ (`AF1<T, N>`) and standard affine forms (`AA<T, N>`).
161
+
162
+ * `AA<N>::variable(k, I)`: the input variable of symbol `k` (`0 <= k < N`), taking all values of `I`.
163
+ * `AA<N>::from_interval(I)`: a quantity taking any value of `I`, uncorrelated with everything else.
164
+ * `AA<N>(c)`, `AA<N>::entire()`: constants and the form representing any real number.
165
+ * `x.interval()`, `x.sign()`, `x.affine_range()`, `x.radius()` (sum of the `|x_i|`, without `err`),
166
+ `x.magnitude(k)`, `x.is_entire()`: conversions back to intervals.
167
+
168
+ ### Differences with cusvna
169
+
170
+ vusvna follows the design of cusvna and its examples, but it is not exactly equivalent to it and
171
+ the bounds computed by the two libraries differ:
172
+
173
+ * **Model**: cusvna provides reduced affine arithmetic (`cusvna::AF1`, the model of vusvna) and standard
174
+ affine arithmetic (`cusvna::AA`), where each nonlinear operation creates a new noise symbol, identified at
175
+ compile time by the types of its operands and at runtime by a tag. AA forms grow with the computation and
176
+ keep the correlations of all the approximation errors. This relies on C++ template metaprogramming (the
177
+ symbols of a form are part of its type) that Slang generics cannot express, so vusvna only provides the
178
+ reduced model, whose forms are much smaller and cheaper but whose bounds are a bit wider on long
179
+ computations or wide inputs.
180
+ * **Rounding**: on the GPU, cusvna uses the directed rounding instructions of the hardware (`__fadd_ru`,
181
+ `__dmul_rd`, ...) and computes the rounding errors of affine operations exactly; in host code it emulates
182
+ outward rounding with error-free transformations (TwoSum, TwoProd). Vulkan has neither directed rounding
183
+ nor reliable error-free transformations (the driver may fuse operations), so vusvna bounds rounding errors
184
+ with the standard model of floating point arithmetic, which is more pessimistic (see
185
+ [Guarantees](#guarantees)).
186
+ * **Ignoring rounding errors**: both libraries can ignore rounding errors for speed (`CUSVNA_IGNORE_ROUNDING`
187
+ and `VUSVNA_IGNORE_ROUNDING`, `--fast` option of the examples), the results are then no longer rigorous.
188
+ * **Precision**: vusvna only supports single precision (`float`), cusvna supports `float` and `double`.
189
+ Vulkan has optional 64-bit floats (`shaderFloat64`), but the transcendental functions of SPIR-V
190
+ (`GLSL.std.450`) are only defined for 16 and 32-bit floats, so a double precision vusvna would have to
191
+ implement all of them itself.
192
+ * **Functions**: vusvna implements a subset of the functions of cusvna (see below).
193
+
194
+ ## Supported operations
195
+
196
+ | Operations | Notes |
197
+ |---|---|
198
+ | `+`, `-`, `*`, `/` between forms and with floats | |
199
+ | `sqr(x)`, `pown(x, int n)` | `sqr(x)` is tighter than `x*x` |
200
+ | `reciprocal(x)` | min-range approximation, entire if `0` belongs to `x` |
201
+ | `sqrt(x)`, `rsqrt(x)`, `cbrt(x)` | `sqrt` is evaluated on the part of its input where `x >= 0` |
202
+ | `pow(x, float y)` | for `x >= 0` (`x > 0` if `y < 0`) |
203
+ | `pow(x, y)` with an affine exponent | `exp(y*log(x))`, for `x > 0` |
204
+ | `rcbrt(x)` | `1/cbrt(x)`, entire if `0` belongs to `x` |
205
+ | `exp(x)`, `exp2(x)`, `exp10(x)`, `log(x)`, `log2(x)`, `log10(x)` | |
206
+ | `sin(x)`, `cos(x)`, `tan(x)`, `cot(x)`, `atan(x)` | `tan` and `cot` are entire if a pole belongs to `x` |
207
+ | `sinpi(x)`, `cospi(x)` | `sin(pi x)` and `cos(pi x)`, with an exact argument reduction |
208
+ | `atan2(y, x)` | `atan(y/x)` for `x > 0`, `+-pi/2 - atan(x/y)` for `y > 0` or `y < 0`, else `[-pi, pi]` |
209
+ | `abs(x)`, `positive_part(x)` | `positive_part(x) = max(x, 0)` |
210
+ | `floor(x)`, `ceil(x)`, `trunc(x)`, `round(x)`, `rint(x)` | `round` rounds ties away from zero, `rint` to even |
211
+ | `fract(x)`, `modf(x, out ip)` | `x - floor(x)`, and `x - trunc(x)` with `ip = trunc(x)` |
212
+ | `fmod(x, y)`, `remainder(x, y)`, `remquo(x, y, out lo, out hi)` | `y` float or affine, entire if `0` belongs to `y` |
213
+ | `min(x, y)`, `max(x, y)`, `clamp(x, lo, hi)` | `(x + y -+ abs(x - y))/2` |
214
+ | `hypot(x, y)`, `hypot(x, y, z)`, `rhypot` | |
215
+ | `lerp(a, b, t)`, `smoothstep(e0, e1, x)` | |
216
+ | `smooth_min(a, b, k)`, `smooth_max(a, b, k)` | polynomial smooth minimum of distances |
217
+ | `certainly_lt`, `certainly_le`, `certainly_gt`, `certainly_ge`, `possibly_zero` | rigorous predicates |
218
+ | `join`, `intersect`, `contains`, `subset`, `is_empty`, `+`, `-`, `*`, `/`, `sqr`, `sqrt`, `abs` | on `Interval` |
219
+
220
+ All of them are generic over `T : IReal` and also work on `Real`.
221
+
222
+ The discontinuous functions (`floor` to `remquo`) are evaluated on the whole range of their input. When the
223
+ range does not cross a discontinuity, the result is exact and stays correlated with the input (`fract(x)` is
224
+ then `x - n`), otherwise it is the range of the function, uncorrelated with the input. `fmod(x, y)` is
225
+ `x - trunc(x/y) y` and `remainder(x, y)` is `x - rint(x/y) y`; `remquo` also returns the range `[lo, hi]` of
226
+ the integer quotient `rint(x/y)` (the full quotient, not only its low bits as in C), saturated to the `int`
227
+ range. `lo == hi` means that the quotient is known.
228
+
229
+ The following functions of cusvna are not available, because SPIR-V either does not provide them or gives no
230
+ usable error bounds for them, so vusvna would have to implement them with validated polynomials as it does
231
+ for `sin` and `cos`:
232
+
233
+ * `asin`, `acos`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`: the precision of the SPIR-V
234
+ functions is only inherited from their defining formulas (for instance `asin(x)` from
235
+ `atan2(x, sqrt(1 - x*x))`), which gives very loose bounds near `0` or near the ends of their domains,
236
+ * `expm1`, `log1p`, `erf`, `erfc`, `normcdf`, `tgamma`, `lgamma`: these functions do not exist in SPIR-V.
237
+
238
+ ## Guarantees
239
+
240
+ For any operation, the exact real result of the computation belongs to the range of the computed form,
241
+ including rounding errors. In particular `x.interval()`, `x.sign()` and the predicates are rigorous.
242
+
243
+ Vulkan gives few guarantees on floating point arithmetic, and vusvna only relies on the following ones:
244
+
245
+ * additions, subtractions and multiplications are correctly rounded to nearest, divisions, square roots and
246
+ transcendental functions are within the error bounds of the Vulkan specification ("Precision and
247
+ Operation of SPIR-V Instructions"),
248
+ * denormals may be flushed to zero on input and output of any instruction,
249
+ * the compiler may contract `a*b + c` into a fused multiply-add,
250
+ * the implementation may assume that **no infinity nor NaN** is ever produced. Drivers do exploit it: on
251
+ NVIDIA `isinf(+inf)` is false and `NaN == NaN` is true.
252
+
253
+ As a consequence:
254
+
255
+ * **No infinities nor NaNs**: all magnitudes are kept below `2^60`, so that products and sums of products
256
+ cannot overflow, and larger quantities mean "any real number" (entire forms). Entire forms propagate
257
+ through all operations, except through bounded functions such as `sin`.
258
+ * **Rounding**: error-free transformations (TwoSum, TwoProd) cannot be trusted when the driver may fuse
259
+ operations. Rounding errors are bounded with the standard model `|r - x| <= k ulp(x) + 2^-126`, where
260
+ `k = 1/2` for correctly rounded operations, `k` is the documented bound otherwise, and `2^-126` accounts
261
+ for flushed denormals. A fused multiply-add only removes a rounding, the bounds remain valid.
262
+ * **Nonlinear functions**: the residual `f(x) - alpha*x` is bounded with outward rounding by splitting the
263
+ input range into pieces where `f` is convex or concave, from rigorous enclosures of `f` and `f'` at
264
+ points. These enclosures use the bounds of the specification for `exp`, `exp2`, `log`, `log2` and `atan`.
265
+ `sin` and `cos` (only guaranteed to `2^-11` by the specification) are computed by vusvna with a
266
+ Cody-Waite reduction and Taylor polynomials, `cbrt` (not in SPIR-V) with a Newton step validated by
267
+ cubing its bounds. The functions missing from SPIR-V are built from these enclosures: `exp10` and `log10`
268
+ from `exp2` and `log2` with rigorous bounds of `log2(10)` and `log10(2)`, `sinpi` and `cospi` from `sin`
269
+ and `cos` after an exact reduction to `[0, 1/4]`.
270
+ * **Integer valued functions**: `floor`, `ceil` and `trunc` are exact in SPIR-V. The tie breaking rule of
271
+ the builtin `round` is implementation defined, so `round` and `rint` are computed from `floor` and
272
+ `trunc`. Denormal bounds are moved outward to `-+2^-126` before evaluating these functions, since the
273
+ driver may flush them to zero.
274
+ * **Domains**: if an input range is not entirely inside the domain of a function, the result is entire,
275
+ except for `sqrt` and `pow(x, float y)` which are evaluated on the part of their input inside their domain
276
+ when it is not empty.
277
+
278
+ Do not compile vusvna code with the fast floating point mode of the Slang compiler (`-fp-mode fast`).
279
+
280
+ ### Rounding modes
281
+
282
+ vusvna has two rounding modes, selected at compile time:
283
+
284
+ | Mode | Selected by | Rigorous | Speed | Use |
285
+ |---|---|---|---|---|
286
+ | rigorous | default | yes | reference | everything |
287
+ | ignore | `VUSVNA_IGNORE_ROUNDING` | **no** | up to 1.5 times faster | visualization |
288
+
289
+ In the default mode, rounding errors are bounded with the standard model as described above. cusvna has a
290
+ third mode: on CUDA devices it uses the directed rounding instructions of the hardware and computes exact
291
+ rounding errors, and it emulates them with error-free transformations in host code (or with
292
+ `CUSVNA_EMULATED_ROUNDING`); neither is possible in Vulkan.
293
+
294
+ #### Ignoring rounding errors
295
+
296
+ Defining the preprocessor macro `VUSVNA_IGNORE_ROUNDING` drops all the bounds of rounding errors: directed
297
+ operations become plain round to nearest operations, the error bounds of the builtin functions and the safety
298
+ margins are ignored, and the error term `err` only accumulates the approximation errors of the nonlinear
299
+ operations. The same option exists in cusvna (`CUSVNA_IGNORE_ROUNDING`).
300
+
301
+ ```python
302
+ compiler_options = spy.SlangCompilerOptions({
303
+ "include_paths": ["path/to/vusvna/vusvna"],
304
+ "defines": {"VUSVNA_IGNORE_ROUNDING": "1"},
305
+ })
306
+ ```
307
+
308
+ **The results are then estimates, not guaranteed bounds**: the values may lie slightly outside of them, by
309
+ rounding errors that are amplified by cancellations and near poles, and a sign test may miss a root. Large
310
+ arguments of `fmod` and `remainder` (quotients beyond `2^24`) give meaningless results. This mode is meant for
311
+ applications where speed matters more than rigor, such as visualization: the examples run up to 1.5 times
312
+ faster and produce almost the same images, but deep quadtree levels keep fewer cells, because in single
313
+ precision the rounding errors become larger than the cells. Fast math is not needed and not recommended.
314
+ The tests check that the estimates stay within `1e-2` of the sampled values, relative to the magnitude of
315
+ the inputs and of the values.
316
+
317
+ ## Examples
318
+
319
+ The `examples` directory contains Python scripts that compile the Slang shaders of `examples/shaders` at
320
+ runtime and run them with slangpy:
321
+
322
+ | Script | Description |
323
+ |---|---|
324
+ | `00_1d.py` | enclosures of a 1D function on refined subdivisions |
325
+ | `01_2d.py` | sign classification of a 2D function on refined grids |
326
+ | `02_quadtree.py` | adaptive quadtree refinement around the zero level set of a 2D function |
327
+ | `03_octree.py` | adaptive octree refinement around an implicit surface, meshed with marching cubes |
328
+ | `04_raytracing.py` | ray tracing of implicit surfaces with Vulkan ray tracing (procedural primitives) |
329
+ | `05_levelset.py` | interactive viewer of animated level sets |
330
+
331
+ With the virtual environment of [Getting started](#getting-started) activated:
332
+
333
+ ```sh
334
+ python3 examples/02_quadtree.py
335
+ ```
336
+
337
+ `02_quadtree.py` to `05_levelset.py` take a `--fast` option that ignores rounding errors (see
338
+ [Ignoring rounding errors](#ignoring-rounding-errors)), for instance `python3 examples/03_octree.py --fast`.
339
+ `05_levelset.py --benchmark` times the rendering offscreen at 1 spp over the animation, with the same
340
+ protocol as the level set example of cusvna.
341
+
342
+ `04_raytracing.py [output.png]` saves the image when a file name is given. `05_levelset.py` opens a window,
343
+ or renders offscreen with `--output image.png` (see `--help` for the time, mode, method, samples and size).
344
+ The level sets are found by marching along the rays with affine forms of the ray parameter, either by a
345
+ sign test on the interval of the function or with a root window that skips the parts of the ray where the
346
+ affine form proves that there is no root. The shapes cast shadows and are antialiased by accumulating
347
+ jittered samples while the scene is paused.
348
+
349
+ | Key | Action |
350
+ |---|---|
351
+ | `ENTER` | rendering mode: shaded, normals, marching steps |
352
+ | `M` | marching method: sign test, root window |
353
+ | `A` | samples per pixel |
354
+ | `SPACE` | pause the animation (images accumulate while paused) |
355
+ | `+`/`-`, `UP`/`DOWN` | animation speed |
356
+ | left / right mouse button, wheel | orbit, look around, zoom |
357
+ | `Q`, `ESC` | quit |
358
+
359
+ ### Comparison with cusvna
360
+
361
+ On an RTX 5090, with the same scenes and settings as the cusvna examples, for the reduced (AF1) and standard
362
+ (AA) affine forms of cusvna, with rounding errors bounded (rigorous) and ignored (`--fast`). `05_levelset.py`
363
+ is timed with `--benchmark` in both libraries (1024x768, 1 spp, root window marching, median over the
364
+ animation):
365
+
366
+ | Example | vusvna | cusvna AF1 | cusvna AA | vusvna `--fast` | cusvna AF1 `--fast` | cusvna AA `--fast` |
367
+ |---|---|---|---|---|---|---|
368
+ | `03_octree.py`, level 11 (20M active cells) | 1.0 ms | 1.7 ms | 4.2 ms | 0.69 ms | 0.70 ms | 3.2 ms |
369
+ | `03_octree.py`, level 12 (81M active cells) | 4.2 ms | 7.0 ms | 17 ms | 3.0 ms | 2.8 ms | 13 ms |
370
+ | `05_levelset.py`, shaded | 2.2 ms | 7.2 ms | 8.3 ms | 1.6 ms | 6.3 ms | 6.9 ms |
371
+ | `05_levelset.py`, marching steps | 1.5 ms | 4.4 ms | 5.1 ms | 1.1 ms | 3.7 ms | 4.2 ms |
372
+
373
+ The images of `04_raytracing.py` match those of cusvna (no pixel differs by more than 8/255). In
374
+ `05_levelset.py`, 0.001% of the pixels of the shaded image and 0.6% of the pixels of the marching steps
375
+ image differ by more than 16/255: both libraries need the same number of marching steps. The quadtree has the
376
+ same active cells as cusvna up to level 12 (deeper levels keep more cells because the coordinates of the
377
+ cells are single precision floats), the octree keeps 0.05% more cells at level 12. With rounding errors
378
+ ignored, the octree runs at the same speed in both libraries: the rigorous gap comes from the rounding
379
+ errors, which cusvna computes exactly with more instructions per operation. The level set example is 3 to 4
380
+ times faster in vusvna in both modes.
381
+
382
+ ## Tests
383
+
384
+ The tests check on the GPU that the enclosures of all operations contain the values of the functions,
385
+ computed in double precision on many sample points of random input intervals (narrow, wide and
386
+ degenerate), and report the median ratio between the computed and sampled widths
387
+ (between 1.0 and 1.2 for most operations).
388
+
389
+ ```sh
390
+ python3 -m pytest tests # or: python3 tests/test_vusvna.py for a report
391
+ ```
392
+
393
+ ## License
394
+
395
+ vusvna is released under the [MIT License](https://github.com/keckj/vusvna/blob/main/LICENSE).