cusvna 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.
cusvna-1.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-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,2 @@
1
+ include LICENSE README.md pyproject.toml setup.py
2
+ include cusvna/*.cuh
cusvna-1.0.1/PKG-INFO ADDED
@@ -0,0 +1,384 @@
1
+ Metadata-Version: 2.4
2
+ Name: cusvna
3
+ Version: 1.0.1
4
+ Summary: Header-only CUDA C++17 library for rigorous affine and interval arithmetic with guaranteed error bounds.
5
+ Author-email: Jean-Baptiste Keck <jbkeck@hotmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/keckj/cusvna
8
+ Project-URL: Issues, https://github.com/keckj/cusvna/issues
9
+ Keywords: cuda,gpu,affine arithmetic,interval arithmetic,range analysis,nvrtc,header-only
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: C++
12
+ Classifier: Environment :: GPU :: NVIDIA CUDA
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Dynamic: license-file
19
+
20
+ <p align="center">
21
+ <img src="https://raw.githubusercontent.com/keckj/cusvna/main/logo/cusvna-logo.svg" alt="cusvna" width="600">
22
+ </p>
23
+
24
+ <p align="center">
25
+ <a href="https://github.com/keckj/cusvna/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
26
+ <a href="#installation"><img src="https://img.shields.io/badge/CUDA-11%2B-76B900?logo=nvidia&logoColor=white" alt="CUDA 11+"></a>
27
+ <a href="#installation"><img src="https://img.shields.io/badge/C%2B%2B-17-00599C?logo=cplusplus&logoColor=white" alt="C++17"></a>
28
+ <a href="#installation"><img src="https://img.shields.io/badge/NVRTC-supported-76B900?logo=nvidia&logoColor=white" alt="NVRTC supported"></a>
29
+ <img src="https://img.shields.io/badge/header--only-yes-brightgreen" alt="Header-only">
30
+ <img src="https://img.shields.io/badge/precision-float%20%7C%20double-orange" alt="float and double">
31
+ </p>
32
+
33
+ **cusvna** (CUDA Self-Validated Numerical Analysis) is a header-only C++17 library for CUDA providing
34
+ computations with **guaranteed error bounds**. It implements [affine arithmetic](https://en.wikipedia.org/wiki/Affine_arithmetic)
35
+ (AA), a model that keeps track of the correlations between quantities and therefore yields much tighter
36
+ bounds than interval arithmetic on long computations. Two models are available: full affine arithmetic
37
+ (`cusvna::AA`) and the cheaper fixed-size AF1 forms (`cusvna::AF1`), see [AF1 forms](#af1-forms).
38
+
39
+ * **Rigorous**: the exact real result of a computation always lies within the computed bounds,
40
+ including floating point rounding errors.
41
+ * **GPU friendly**: no dynamic allocation, affine forms live in registers. Works in `__device__` code
42
+ compiled with nvcc or at runtime with NVRTC, and in host code compiled with nvcc.
43
+ * **Complete**: arithmetic, all usual elementary functions of the CUDA math API, signed distance
44
+ helpers (`min`, `max`, `hypot`, `smooth_min`, ...) and rigorous predicates, in `float` and `double`.
45
+
46
+ Typical applications are robust root isolation and subdivision schemes (quadtrees, octrees), ray tracing
47
+ of implicit surfaces and level sets, and any numerical method that must not miss a solution. A Vulkan and
48
+ Slang port of the AF1 forms is available as [vusvna](https://github.com/keckj/vusvna), see
49
+ [vusvna](#vusvna).
50
+
51
+ <p align="center">
52
+ <img src="https://raw.githubusercontent.com/keckj/cusvna/main/figures/levelset.jpg" alt="Level sets ray traced with affine arithmetic" width="800">
53
+ </p>
54
+
55
+ ## Getting started
56
+
57
+ The examples compile their CUDA kernels at runtime with [CuPy](https://cupy.dev) (NVRTC) and only need an
58
+ NVIDIA GPU, the CUDA toolkit and Python. The ray tracing examples (`04_raytracing.py` and `05_levelset.py`)
59
+ also need the [OptiX 7.4 SDK](https://developer.nvidia.com/designworks/optix/downloads/legacy) for
60
+ [python-optix](https://github.com/mortacious/python-optix).
61
+
62
+ ```sh
63
+ git clone --recursive https://github.com/keckj/cusvna.git
64
+ cd cusvna
65
+ python3 -m venv .venv
66
+ source .venv/bin/activate
67
+ python3 -m pip install -r examples/requirements.txt
68
+ python3 examples/02_quadtree.py # adaptive quadtree around a 2D curve
69
+ python3 examples/05_levelset.py # interactive ray tracing of animated level sets (needs OptiX)
70
+ ```
71
+
72
+ See [Examples](#examples) for the other scripts, [Installation](#installation) to use cusvna in your own
73
+ kernels and [Tests](#tests) to check it on your GPU.
74
+
75
+ ## Example
76
+
77
+ ```c++
78
+ #include <cusvna/aa.cuh>
79
+
80
+ using Interval = cusvna::Interval<float>;
81
+ using AA = cusvna::AA<float>;
82
+
83
+ /* returns false only if the unit circle certainly does not cross the box X x Y */
84
+ __device__ bool may_contain_root(const Interval& X, const Interval& Y) {
85
+ const auto x = AA::from_interval<0>(X); /* input noise symbols are numbered by the user */
86
+ const auto y = AA::from_interval<1>(Y);
87
+ const auto f = sqr(x) + sqr(y) - 1.0f; /* f(x, y) is guaranteed to lie in f.interval() */
88
+ return possibly_zero(f);
89
+ }
90
+ ```
91
+
92
+ Functions are found by argument dependent lookup, so the same templated code can be evaluated on floating
93
+ point numbers and on affine forms. Replacing `cusvna::AA<float>` by `cusvna::AF1<float, 2>` (from
94
+ `<cusvna/af1.cuh>`) evaluates the same code with AF1 forms.
95
+
96
+ ## Installation
97
+
98
+ cusvna is header-only: add the root of this repository to your include paths and include `<cusvna/aa.cuh>`
99
+ and/or `<cusvna/af1.cuh>`.
100
+
101
+ The headers are also available as a Python package, for instance to compile kernels at runtime with NVRTC:
102
+
103
+ ```sh
104
+ python3 -m pip install cusvna
105
+ python3 -m cusvna --include # include directory to pass as -I to nvcc or NVRTC
106
+ ```
107
+
108
+ ```python
109
+ import cusvna
110
+ options = ("--std=c++17", f"-I{cusvna.get_include()}") # plus the CUDA include directory
111
+ ```
112
+
113
+ Requirements:
114
+
115
+ * CUDA 11 or newer (the library uses `cuda::std` from libcu++, shipped with the CUDA toolkit),
116
+ * C++17 (`nvcc -std=c++17`, `nvrtc --std=c++17`),
117
+ * **no fast math**, even with `CUSVNA_IGNORE_ROUNDING`, see [Guarantees](#guarantees) and
118
+ [Rounding modes](#rounding-modes).
119
+
120
+ With NVRTC (for instance through CuPy), pass the CUDA include directory and the root of this repository
121
+ as include paths, see `examples/utils.py`.
122
+
123
+ ## Affine arithmetic in cusvna
124
+
125
+ An affine form represents an unknown real quantity as
126
+
127
+ x = b + x_1 e_1 + ... + x_N e_N + err e_err, e_i, e_err unknown in [-1, 1]
128
+
129
+ The noise symbols `e_i` are shared between forms and carry correlations: `x - x` is exactly zero, while
130
+ interval arithmetic would return `[-2r, 2r]`. Nonlinear operations approximate their result by an affine
131
+ function of their input and attach the approximation error to a new noise symbol. The error term
132
+ `err` accumulates rounding errors and is independent from everything else.
133
+
134
+ In cusvna, noise symbols are identified at compile time by types: `cusvna::AA<T, Is...>` stores exactly
135
+ `sizeof...(Is)` coefficients and the type of the result of an operation is computed at compile time from
136
+ the types of its operands.
137
+
138
+ * Input symbols are created by `AA::from_interval<K>(interval)`, where `K` identifies the input.
139
+ Two forms created with the same `K` represent the same quantity. The macro `new_aa_from_interval(interval)`
140
+ uses a unique `K` for each line of code (not available with NVRTC).
141
+ * Since the types of the symbols created by nonlinear operations only depend on the types of the operands,
142
+ each of them also carries a 64-bit runtime tag: a hash of the content of the operands. Symbols with equal
143
+ tags represent the same quantity, symbols with different tags are merged conservatively.
144
+
145
+ ## AF1 forms
146
+
147
+ `cusvna::AF1<T, N>` implements the AF1 model of Messine: a form has exactly `N` input noise symbols and a
148
+ single error term,
149
+
150
+ x = b + x_1 e_1 + ... + x_N e_N + err e_err
151
+
152
+ Affine operations are exact up to rounding as in AA, but nonlinear operations (products of forms, elementary
153
+ functions) add their approximation error to `err` instead of creating a new noise symbol. Forms have a
154
+ constant size of `N + 2` scalars and need no symbol types, tags or merges, which makes them cheaper. The
155
+ price is that correlations between results of nonlinear operations are lost: on `x = [0.1, 0.3]`,
156
+ `sin(x) - sin(x)` has a radius of `1e-3` (twice the approximation error of `sin`) with AF1, and `2e-8`
157
+ (rounding errors only) with AA.
158
+
159
+ * Input symbols are created by `AF1::from_interval<K>(interval)` with `0 <= K < N` (checked at compile
160
+ time), or `AF1::variable(k, interval)` with a runtime index. `AF1::constant(interval)` encloses an
161
+ interval without any symbol.
162
+ * All the operations listed below are available with the same names and the same guarantees, forms of
163
+ different models cannot be mixed.
164
+
165
+ AF1 is a good default when nonlinear subexpressions are not reused, which is the case of most signed
166
+ distance functions. AA is tighter when the results of nonlinear operations appear several times in an
167
+ expression. See [Performance](#performance).
168
+
169
+ ## Supported operations
170
+
171
+ | Operations | Notes |
172
+ |---|---|
173
+ | `+`, `-`, `*`, `/` between forms and with scalars | |
174
+ | `reciprocal(x)` | min-range approximation, entire if `0` belongs to `x` |
175
+ | `sqrt(x)`, `exp(x)`, `log(x)` | Chebyshev approximations |
176
+ | `sqr(x)`, `pow(x, int n)` | `sqr(x)` is tighter than `x*x` |
177
+ | `pow(x, T y)` | for `x >= 0` (`x > 0` if `y < 0`) |
178
+ | `pow(x, y)`, `pow(c, y)` with an affine exponent | `exp(y*log(x))`, for `x > 0` |
179
+ | `rsqrt(x)`, `cbrt(x)`, `rcbrt(x)` | |
180
+ | `exp2(x)`, `exp10(x)`, `expm1(x)`, `log2(x)`, `log10(x)`, `log1p(x)` | |
181
+ | `sin(x)`, `cos(x)`, `tan(x)`, `cot(x)` | entire if a pole belongs to `x` |
182
+ | `sinpi(x)`, `cospi(x)` | `sin(pi*x)` and `cos(pi*x)` without rounding `pi*x`, exact at integers and half-integers |
183
+ | `atan(x)`, `asin(x)`, `acos(x)`, `atan2(y, x)` | `atan2` returns `[-pi, pi]` when the input box meets the branch cut `y = 0, x <= 0` |
184
+ | `sinh(x)`, `cosh(x)`, `tanh(x)`, `asinh(x)`, `acosh(x)`, `atanh(x)` | |
185
+ | `erf(x)`, `erfc(x)`, `normcdf(x)` | |
186
+ | `tgamma(x)`, `lgamma(x)` | for `x > 0` only (entire otherwise) |
187
+ | `abs(x)`, `positive_part(x)` | `positive_part(x) = max(x, 0)` |
188
+ | `min(x, y)`, `max(x, y)`, `fmin`, `fmax`, `clamp(x, lo, hi)` | `min(x, y) + max(x, y)` cancels to `x + y` |
189
+ | `hypot(x, y)`, `hypot(x, y, z)`, `norm3d`, `rhypot`, `rnorm3d` | |
190
+ | `fma(x, y, z)`, `lerp(a, b, t)`, `smoothstep(e0, e1, x)` | |
191
+ | `smooth_min(a, b, k)`, `smooth_max(a, b, k)` | polynomial smooth minimum of distances |
192
+ | `floor`, `ceil`, `trunc`, `round`, `rint`, `fract`, `modf(x, &ip)` | exact when no discontinuity is crossed, else the range of the result |
193
+ | `fmod(x, y)`, `remainder(x, y)` | `y` may be a scalar or a form, exact and correlated with `x` and `y` when the integer quotient is known |
194
+ | `remquo(x, y, &quo_lo, &quo_hi)` | returns the range of the whole integer quotient `rint(x/y)` (not only its low bits as in C), `quo_lo == quo_hi` when it is known |
195
+ | `certainly_lt`, `certainly_le`, `certainly_gt`, `certainly_ge`, `possibly_zero` | rigorous predicates |
196
+ | `x.interval()`, `x.sign()`, `x.radius()`, `x.is_entire()` | conversions back to intervals |
197
+ | `hull`, `intersect`, `contains`, `subset`, `is_empty` | on `cusvna::Interval` |
198
+
199
+ These cover all the operations of [libaffa](https://github.com/ogay/libaffa), which is used as a reference
200
+ in the tests (`inv` is `reciprocal`, `cotan` is `cot` and `half_plane` is `positive_part`).
201
+
202
+ ## Guarantees
203
+
204
+ For any operation, the exact real result of the computation belongs to the range of the computed form,
205
+ including rounding errors. In particular `x.interval()`, `x.sign()` and the predicates are rigorous.
206
+ Bounds are never NaN.
207
+
208
+ * **Rounding**: bounds are rounded outward, with the directed rounding instructions of the hardware in
209
+ device code and with emulated directed rounding in host code, and the rounding errors of affine
210
+ operations are accumulated in the error term, see [Rounding modes](#rounding-modes).
211
+ * **Nonlinear functions**: the residual `f(x) - alpha*x` is bounded with outward rounding by splitting
212
+ the input range into pieces where `f` is convex or concave. The results of math library functions are
213
+ assumed to be within twice the maximum error documented in the CUDA math API (see `cusvna/approx.cuh`).
214
+ `tgamma` and `lgamma` are restricted to positive inputs where this assumption holds; CUDA does not bound
215
+ the relative error of `lgamma` for negative inputs close to its zeros.
216
+ * **Domains**: if an input range is not entirely inside the domain of a function, the result is entire
217
+ (its interval is `[-inf, inf]`), except for `sqrt`, `pow(x, T y)`, `acosh`, `asin` and `acos` which are
218
+ evaluated on the part of their input inside their domain when it is not empty. Overflows produce entire
219
+ forms. Entire forms propagate through all operations, except through bounded functions such as `sin`.
220
+
221
+ These guarantees hold under the following assumptions:
222
+
223
+ * IEEE-754 binary32 (`float`) or binary64 (`double`) arithmetic in round-to-nearest mode,
224
+ * **no fast math**: do not compile with `--use_fast_math` (nvcc, nvrtc) or `-ffast-math` (host),
225
+ `-ftz=true`, `-prec-div=false` or `-prec-sqrt=false`,
226
+ * host code must not contract floating point operations into fused multiply-adds (`-ffp-contract=off`,
227
+ which is the default of gcc with `-std=c++17`). Device code uses non-contractible intrinsics,
228
+ * **hash collisions** (AA only): a collision between the runtime tags of two different values would wrongly
229
+ correlate them. For non-adversarial inputs the probability is about `2^-64` per comparison of two generated
230
+ symbols of the same type.
231
+
232
+ ## Rounding modes
233
+
234
+ The rounding errors are handled in one of three ways, selected at compile time:
235
+
236
+ | Mode | Selected by | Rigorous | Speed on GPUs | Use |
237
+ |---|---|---|---|---|
238
+ | native | default in device code | yes | reference | GPU code |
239
+ | emulated | host code, or `CUSVNA_EMULATED_ROUNDING` in device code | yes | 2 to 6 times slower | host code, tests |
240
+ | ignore | `CUSVNA_IGNORE_ROUNDING` | **no** | up to 2.5 times faster | visualization |
241
+
242
+ * **native**: device code uses the directed rounding instructions of the hardware (`__fadd_ru`,
243
+ `__dmul_rd`, ...), which are exact and as fast as round-to-nearest ones. The rounding errors of affine
244
+ operations are computed exactly (TwoSum, fused multiply-add residuals) and accumulated in the error term,
245
+ and the results of math library functions are enclosed by twice their documented maximum error.
246
+ * **emulated**: host code has no directed rounding instructions, so everything runs in the default
247
+ round-to-nearest mode and outward rounding is emulated with error-free transformations (TwoSum, TwoProd):
248
+ they detect exact operations and the sign of the rounding errors, and inexact bounds are moved outward by
249
+ at least one ulp. This is the only mode of host code. Defining `CUSVNA_EMULATED_ROUNDING` selects it in
250
+ device code too, which gives the same results as host code but is only useful for testing.
251
+ * **ignore**: when `CUSVNA_IGNORE_ROUNDING` is defined, cusvna ignores all floating point rounding errors:
252
+ directed operations become round-to-nearest operations, the error terms of affine operations are not
253
+ computed, the results of math library functions are taken as exact, and operations may be contracted
254
+ into fused multiply-adds. Approximation errors of nonlinear functions are still bounded. The results are
255
+ **no longer rigorous**: enclosures may miss the exact result by a few ulps, and deep subdivisions may
256
+ discard cells that contain zeros. This mode is meant for visualization.
257
+
258
+ The examples select the mode with `--rounding native|emulated|ignore`, `--fast` being a shortcut for
259
+ `--rounding ignore`. See [Performance](#performance) for the timings of the three modes.
260
+
261
+ **Fast math is strictly discouraged, even with `CUSVNA_IGNORE_ROUNDING`.** Its approximate math functions
262
+ (`__sinf`, `__expf`, ...) are far less accurate than the CUDA math library and break the enclosures: with
263
+ `--use_fast_math`, `05_levelset.py` misses most surfaces and runs 5 times slower because interval marching
264
+ cannot conclude.
265
+
266
+ ## Examples
267
+
268
+ The `examples` directory contains Python scripts that compile CUDA kernels at runtime with CuPy (NVRTC):
269
+
270
+ | Script | Description |
271
+ |---|---|
272
+ | `00_1d.py` | enclosures of a 1D function on refined subdivisions |
273
+ | `01_2d.py` | sign classification of a 2D function on refined grids |
274
+ | `02_quadtree.py` | adaptive quadtree refinement around the zero level set of a 2D function |
275
+ | `03_octtree.py` | adaptive octree refinement around an implicit surface, meshed with marching cubes |
276
+ | `04_raytracing.py` | ray tracing of implicit surfaces with OptiX |
277
+ | `05_levelset.py` | interactive OptiX viewer of level sets |
278
+
279
+ With the virtual environment of [Getting started](#getting-started) activated:
280
+
281
+ ```sh
282
+ python3 examples/02_quadtree.py # AF1 forms
283
+ python3 examples/02_quadtree.py aa # AA forms
284
+ python3 examples/02_quadtree.py --rounding emulated # AF1 forms, emulated rounding
285
+ python3 examples/02_quadtree.py --fast # AF1 forms, rounding errors ignored
286
+ ```
287
+
288
+ `02_quadtree.py` to `05_levelset.py` take an optional `af1` (default) or `aa` argument selecting the affine
289
+ forms, and a `--rounding` option selecting the [rounding mode](#rounding-modes) (`--fast` for
290
+ `--rounding ignore`). The examples never use fast math. The OptiX examples require the OptiX SDK and the
291
+ `python-optix` submodule.
292
+
293
+ `05_levelset.py` opens a window, or renders offscreen with `--output image.png` (see `--help` for the time,
294
+ mode, method, samples and size). `05_levelset.py --benchmark` times the rendering offscreen at 1 spp over the
295
+ animation, with the same protocol as the level set example of vusvna. The level sets are found by marching
296
+ along the rays with affine forms of the ray parameter, either by a sign test on the interval of the function
297
+ or with a root window that skips the parts of the ray where the affine form proves that there is no root.
298
+ The shapes cast shadows and are antialiased by accumulating jittered samples while the scene is paused.
299
+
300
+ | Key | Action |
301
+ |---|---|
302
+ | `ENTER` | rendering mode: shaded, normals, marching steps |
303
+ | `M` | marching method: sign test, root window |
304
+ | `A` | samples per pixel |
305
+ | `SPACE` | pause the animation (images accumulate while paused) |
306
+ | `+`/`-`, `UP`/`DOWN` | animation speed |
307
+ | left / right mouse button, wheel | orbit, look around, zoom |
308
+ | `Q`, `ESC` | quit |
309
+
310
+ ## Performance
311
+
312
+ Time of the evaluations on an RTX 5090 (float) in the three [rounding modes](#rounding-modes), for AF1 and
313
+ AA forms. `05_levelset.py` is timed with `--benchmark` (1024x768, 1 sample per pixel, root window marching,
314
+ median over the animation).
315
+
316
+ | Benchmark | AF1 native | AF1 emulated | AF1 ignore | AA native | AA emulated | AA ignore |
317
+ |---|---|---|---|---|---|---|
318
+ | `02_quadtree.py`, level 22 | 0.24 ms | 0.58 ms | 0.12 ms | 0.29 ms | 0.64 ms | 0.12 ms |
319
+ | `02_quadtree.py`, level 25 | 2.4 ms | 6.3 ms | 0.70 ms | 2.9 ms | 7.0 ms | 0.74 ms |
320
+ | `03_octtree.py`, level 11 (20M active cells) | 1.7 ms | 9.4 ms | 0.70 ms | 4.2 ms | 12 ms | 3.2 ms |
321
+ | `03_octtree.py`, level 12 (81M active cells) | 7.0 ms | 37 ms | 2.8 ms | 17 ms | 48 ms | 13 ms |
322
+ | `05_levelset.py`, shaded | 7.2 ms | 22 ms | 6.3 ms | 8.3 ms | 24 ms | 6.9 ms |
323
+ | `05_levelset.py`, marching steps | 4.4 ms | 13.3 ms | 3.7 ms | 5.1 ms | 14.6 ms | 4.2 ms |
324
+
325
+ Both models produce the same numbers of active cells up to a few cells and the same images. Marching with
326
+ the sign test instead of the root window is about 1.5 times slower.
327
+
328
+ Ignoring rounding errors keeps fewer cells in the quadtree (8.4M instead of 9.5M at level 22, 57M instead
329
+ of 126M at level 25): in single precision, the rounding errors of deep levels are larger than the cells.
330
+ The octree keeps 0.02% fewer cells and the images of `05_levelset.py` are the same.
331
+
332
+ ## vusvna
333
+
334
+ [vusvna](https://github.com/keckj/vusvna) is a port of cusvna to Vulkan, as a [Slang](https://shader-slang.org)
335
+ module usable in any shader stage, with the same examples run by [slangpy](https://github.com/shader-slang/slangpy).
336
+ It is a partial port:
337
+
338
+ * it only provides the AF1 forms (Slang generics cannot express the symbol types of `cusvna::AA`),
339
+ * it works in single precision only,
340
+ * Vulkan has no directed rounding and the driver may fuse operations, so vusvna bounds rounding errors with
341
+ the standard model of floating point arithmetic instead of exact error terms; `VUSVNA_IGNORE_ROUNDING`
342
+ ignores them as `CUSVNA_IGNORE_ROUNDING` does,
343
+ * some functions are missing (`asin`, `acos`, the hyperbolic functions, `erf`, `tgamma`, ...).
344
+
345
+ The two libraries give the same images and nearly the same cells. On the same RTX 5090, with the same
346
+ scenes and benchmark protocol:
347
+
348
+ | Benchmark | vusvna | cusvna AF1 | cusvna AA | vusvna, ignore | cusvna AF1, ignore | cusvna AA, ignore |
349
+ |---|---|---|---|---|---|---|
350
+ | `03_octtree.py`, level 11 | 1.0 ms | 1.7 ms | 4.2 ms | 0.69 ms | 0.70 ms | 3.2 ms |
351
+ | `03_octtree.py`, level 12 | 4.2 ms | 7.0 ms | 17 ms | 3.0 ms | 2.8 ms | 13 ms |
352
+ | `05_levelset.py`, shaded | 2.2 ms | 7.2 ms | 8.3 ms | 1.6 ms | 6.3 ms | 6.9 ms |
353
+ | `05_levelset.py`, marching steps | 1.5 ms | 4.4 ms | 5.1 ms | 1.1 ms | 3.7 ms | 4.2 ms |
354
+
355
+ ## Tests
356
+
357
+ The tests compare cusvna against libaffa, which must be cloned in `ext/libaffa`
358
+ (`git submodule update --init ext/libaffa`), and check the soundness of all operations against extended
359
+ precision evaluations, for AA and AF1 forms, in float and double, in host code (emulated rounding) and in
360
+ device code (hardware rounding and CUDA math library).
361
+
362
+ ```sh
363
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build && ctest --test-dir build
364
+ ```
365
+
366
+ Add `-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc` if `nvcc` is not in your `PATH`.
367
+
368
+ ## Defects found in libaffa
369
+
370
+ The following libaffa functions do not return enclosures, they have been fixed in cusvna:
371
+
372
+ | Function | Input | libaffa | Exact range |
373
+ |---|---|---|---|
374
+ | `exp` | `[0, 1]` | `[0.682, 2.612]` | `[1, 2.718]` |
375
+ | `sin` | `[-4.41, 1.21]` | `[-0.951, 0.996]` | `[-1, 0.955]` |
376
+ | `abs` | `[-1, 1]` | `[-0.5, 0.5]` | `[0, 1]` |
377
+
378
+ In addition, `exp` only uses the tangent intercept instead of the mean of the secant and tangent
379
+ intercepts, `sin` estimates its approximation error from 8 samples, `atanh` is not implemented (no return
380
+ value) and no operation accounts for rounding errors.
381
+
382
+ ## License
383
+
384
+ cusvna is released under the [MIT License](https://github.com/keckj/cusvna/blob/main/LICENSE).