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