beamgrad 2.0.0__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.
Files changed (49) hide show
  1. beamgrad-2.0.0/CHANGELOG.md +264 -0
  2. beamgrad-2.0.0/CMakeLists.txt +259 -0
  3. beamgrad-2.0.0/LICENSE +21 -0
  4. beamgrad-2.0.0/MANIFEST.in +8 -0
  5. beamgrad-2.0.0/PKG-INFO +259 -0
  6. beamgrad-2.0.0/README.md +223 -0
  7. beamgrad-2.0.0/VERSION +1 -0
  8. beamgrad-2.0.0/abi/baseline-v0.5.symbols +72 -0
  9. beamgrad-2.0.0/abi/libdbs.symbols +78 -0
  10. beamgrad-2.0.0/cmake/beamgradConfig.cmake.in +7 -0
  11. beamgrad-2.0.0/cmake/dbs.map +4 -0
  12. beamgrad-2.0.0/cuda/dbs_cuda.cu +1395 -0
  13. beamgrad-2.0.0/cuda/dbs_cuda_stub.cpp +64 -0
  14. beamgrad-2.0.0/cuda/emulation/cuda_emulation.hpp +342 -0
  15. beamgrad-2.0.0/include/dbs.h +460 -0
  16. beamgrad-2.0.0/include/dbs_cuda.h +199 -0
  17. beamgrad-2.0.0/pkgconfig/dbs.pc.in +11 -0
  18. beamgrad-2.0.0/pyproject.toml +66 -0
  19. beamgrad-2.0.0/python/beamgrad/__init__.py +48 -0
  20. beamgrad-2.0.0/python/beamgrad/_build_info.py +4 -0
  21. beamgrad-2.0.0/python/beamgrad/_ctypes.py +205 -0
  22. beamgrad-2.0.0/python/beamgrad/_options.py +132 -0
  23. beamgrad-2.0.0/python/beamgrad/_search.py +424 -0
  24. beamgrad-2.0.0/python/beamgrad/_torch.py +468 -0
  25. beamgrad-2.0.0/python/beamgrad/_version.py +2 -0
  26. beamgrad-2.0.0/python/beamgrad/estimators.py +244 -0
  27. beamgrad-2.0.0/python/beamgrad/hf.py +187 -0
  28. beamgrad-2.0.0/python/beamgrad/jax.py +216 -0
  29. beamgrad-2.0.0/python/beamgrad/losses.py +128 -0
  30. beamgrad-2.0.0/python/beamgrad/py.typed +0 -0
  31. beamgrad-2.0.0/python/beamgrad.egg-info/PKG-INFO +259 -0
  32. beamgrad-2.0.0/python/beamgrad.egg-info/SOURCES.txt +47 -0
  33. beamgrad-2.0.0/python/beamgrad.egg-info/dependency_links.txt +1 -0
  34. beamgrad-2.0.0/python/beamgrad.egg-info/requires.txt +9 -0
  35. beamgrad-2.0.0/python/beamgrad.egg-info/top_level.txt +1 -0
  36. beamgrad-2.0.0/python/csrc/cpu_ops.cpp +445 -0
  37. beamgrad-2.0.0/python/csrc/cuda_ops.cpp +354 -0
  38. beamgrad-2.0.0/python/csrc/libdbs_module.cpp +13 -0
  39. beamgrad-2.0.0/setup.cfg +4 -0
  40. beamgrad-2.0.0/setup.py +130 -0
  41. beamgrad-2.0.0/src/c_api.cpp +1188 -0
  42. beamgrad-2.0.0/src/common.hpp +280 -0
  43. beamgrad-2.0.0/src/cpu_features.cpp +147 -0
  44. beamgrad-2.0.0/src/decoder.cpp +844 -0
  45. beamgrad-2.0.0/src/decoder.hpp +170 -0
  46. beamgrad-2.0.0/src/kernels.hpp +139 -0
  47. beamgrad-2.0.0/src/kernels_scalar.cpp +216 -0
  48. beamgrad-2.0.0/src/kernels_x86.cpp +206 -0
  49. beamgrad-2.0.0/src/penalty.hpp +124 -0
@@ -0,0 +1,264 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0 (2026-09-25)
4
+
5
+ The project is renamed **beamgrad** (previously `differentiable-beam-search-cuda`
6
+ and the `dbs-torch` Python package). The C library keeps its name, `libdbs`,
7
+ and C ABI version 10. Every symbol of the 0.5 baseline is still exported;
8
+ three functions are added and one no-op stub is removed (see below).
9
+
10
+ ### Highlights
11
+
12
+ - **Training a model through beam search.** `beamgrad.beam_search(step_fn,
13
+ options, max_steps)` runs an autoregressive model inside the search: each
14
+ step asks the model for the next-token distributions of the beams chosen so
15
+ far (with each beam's parent slot, to reorder a key/value cache), and the
16
+ returned scores are differentiable with respect to the model. Driving
17
+ Qwen2.5-0.5B and Qwen3-0.6B, it returns the same beams with bit-identical
18
+ scores as `transformers`' `generate(num_beams=...)` in float32, at the same
19
+ speed (`benchmarks/hf_beam_search.py`).
20
+ - **Training in bounded memory.** `beam_search`'s backward hands each step
21
+ only its own `[B, K]` path gradient, never a dense `[B, T, K, V]` one, and
22
+ `rescore_fn` takes the same gradient from one teacher-forced pass after a
23
+ search without an autograd graph. With activation checkpointing, a
24
+ Qwen2.5-0.5B training step at batch 8, 8 beams and 128 steps needs 1.7 GiB
25
+ above the weights instead of running out of memory on 16 GB
26
+ (`benchmarks/hf_training_memory.py`).
27
+ - **Losses, estimators and a controlled experiment.** `beamgrad.losses`
28
+ (structured margin, minimum risk) and `beamgrad.estimators`
29
+ (selected-beam softmax, relaxed top-k) in PyTorch, and a Multi30k
30
+ translation experiment comparing them with continued MLE over three seeds
31
+ (`experiments/multi30k`): minimum-risk training on the search's beams
32
+ improved test BLEU on every seed (+0.55 on average), and a margin against
33
+ the reference made it worse.
34
+ - **Wheels for every Python.** The extensions use only CPython's limited API,
35
+ so one wheel per PyTorch version and CUDA variant serves Python 3.10+.
36
+ Releases build them for PyTorch 2.13 and 2.14 on Linux (CPU, CUDA 12.6,
37
+ CUDA 13.0), macOS and Windows.
38
+ - **Native CUDA engine.** Beam search and its backward pass run entirely on
39
+ the GPU for beams up to 1024, with GNMT length penalty, EOS carry-forward,
40
+ `min_length` and variable-length batches. It selects the same beams, with
41
+ the same scores, as the CPU decoder. The PyTorch API no longer falls back
42
+ to the CPU for any option or beam size.
43
+ - **`beamgrad` Python package** with one device-agnostic API:
44
+ `final_scores` (autograd), `decode` (full trace, now on CPU too),
45
+ `backtrack`, and `steps=` for variable-length batches.
46
+ - **Tests that test.** The C++ tests used `assert()`, which Release builds
47
+ compile out, so CI had been running empty test bodies. They now always run.
48
+ The CUDA kernels are verified without a GPU by running the unmodified kernel
49
+ source through a CPU emulation layer, checked bit for bit against the CPU
50
+ decoder under several thread schedules.
51
+ - **Constraints everywhere.** Banned tokens, n-gram blocking and a repetition
52
+ penalty are available from Python on CPU, CUDA and JAX. Their per-beam token
53
+ sets are computed once per step instead of scanning the prefix for every
54
+ candidate (n-gram blocking at T=32, K=4, V=32k: 57 ms to 0.7 ms on CPU).
55
+ - **PyTorch integration.** The operators are registered with `torch.library`
56
+ (fake tensors, autograd, vmap), so `torch.compile`, `torch.export` and
57
+ `torch.vmap` work, and `final_scores` works under the `torch.func`
58
+ transforms (`grad`, `vjp`, `jacrev`, per-example gradients). Input
59
+ validation runs inside the decode kernels.
60
+
61
+ ### Added
62
+
63
+ - `beam_search(..., rescore_fn=, return_log_probs=)`: gradients by
64
+ teacher-forced re-scoring of the final beams, and control over keeping
65
+ the rows. `beamgrad.search` (scores, sequences and trace from one decode),
66
+ `sequence_scores`, `length_penalty`, and `BeamSearchResult.trace`.
67
+ - `beamgrad.losses`: `structured_margin`, `minimum_risk`, `matches`.
68
+ - `beamgrad.estimators`: `path_scores`, `selected_softmax` and
69
+ `relaxed_topk` (with each pool candidate's parent, token and origin),
70
+ matching the C library's surrogates on CPU and CUDA.
71
+ - `beamgrad.hf`: `CausalLMStep` (a step function for Hugging Face causal LMs,
72
+ with a key/value cache that follows the beams) and `CausalLMRescorer`
73
+ (chunked, checkpointed vocabulary projection; optional gradient
74
+ checkpointing).
75
+ - Operators `final_scores_path_gradient` and `length_penalty` (CPU and
76
+ CUDA), and their C/CUDA counterparts `dbs_cuda_path_gradient` and
77
+ `dbs_cuda_length_penalty`.
78
+ - `experiments/multi30k`, `benchmarks/hf_training_memory.py`, and the
79
+ guides `docs/training.md`, `docs/installation.md` and `docs/benchmarks.md`.
80
+ - Wheel builds (`.github/workflows/wheels.yml`), attached to GitHub releases;
81
+ `BEAMGRAD_PIN_TORCH` and `BEAMGRAD_LOCAL_VERSION` for building them.
82
+ - CI builds the CUDA operators with CUDA 12.4 (with PyTorch 2.4), 12.6 and
83
+ 13.0 (with Blackwell architectures), and tests transformers with a
84
+ key/value cache, 384-step searches and autocast (bfloat16, float16).
85
+ - `beamgrad.beam_search`, `BeamState`, `BeamSearchResult`: beam search that
86
+ drives a model step by step, on CPU or CUDA, without stacking or copying the
87
+ per-step rows. `torch.ops.beamgrad.decode_step` (one step from an explicit
88
+ beam state), the C++ `BeamSearchDecoder::step`, and the CUDA C API's
89
+ `dbs_cuda_decode_step` / `DBSCudaBeamState` /
90
+ `dbs_cuda_decode_step_workspace_size` underneath; stepping through the rows
91
+ of a tensor selects exactly what the full decode selects.
92
+ - `examples/train_lm.py`: a GRU language model trained so that reference
93
+ sequences win beam search by a margin, and
94
+ `benchmarks/hf_beam_search.py`: parity, speed and training on a Hugging
95
+ Face causal LM against `generate`.
96
+ - `dbs_cuda_decode` / `dbs_cuda_backward` with workspace-size queries,
97
+ per-example metadata, constraints, NaN/`+inf` flags, optional trace outputs,
98
+ and asynchronous execution (`DBS_CUDA_SYNC_CHECK=1` synchronizes for
99
+ debugging).
100
+ - `dbs_decode_model_steps_ex`: incremental model-step decoding whose callback
101
+ learns each beam's parent slot, length, finished flag and token prefix (so a
102
+ model can reorder per-beam state), with optional constraints. The original
103
+ `dbs_decode_model_steps` also runs incrementally now (`T` callbacks instead
104
+ of re-decoding every prefix).
105
+ - `dbs_decode_batch_into` / `dbs_backward_batch_into`: batch decoding and the
106
+ final-score backward on caller-owned arrays, with per-example steps and
107
+ constraints, used by the PyTorch CPU operators and by JAX.
108
+ - `DBS_OK` / `DBS_ERROR_*` status constants.
109
+ - `BeamOptions.banned_tokens`, `no_repeat_ngram_size`, `repetition_penalty`;
110
+ `steps=` and `vmap` in `beamgrad.jax.final_scores`.
111
+ - An import-time check that beamgrad was compiled against the installed
112
+ PyTorch, with the command that fixes a mismatch.
113
+ - `beamgrad.BeamOptions`, `final_scores`, `decode`, `backtrack`,
114
+ `BeamSearchOutput`, `cuda_available`, `CUDA_MAX_BEAM`;
115
+ `beamgrad.jax.final_scores`.
116
+ - The wheel bundles libdbs as `beamgrad._libdbs` for ctypes and JAX use.
117
+ - CMake package `find_package(beamgrad)` with targets `beamgrad::dbs` and
118
+ `beamgrad::dbs_cuda`, a `DBS_WARNINGS_AS_ERRORS` option, and ctest targets
119
+ for the ABI symbol check, a pure-C header test and the C example.
120
+ - CI across Linux (GCC, Clang, static), macOS and Windows; sanitizers,
121
+ fuzzing, an nvcc build of the CUDA backend and Python CUDA operators; an
122
+ opt-in self-hosted GPU workflow; a release workflow with provenance
123
+ attestation.
124
+ - Documentation in `docs/`: algorithm, Python API, C API, CUDA engine,
125
+ development guide.
126
+
127
+ ### Changed
128
+
129
+ - The Python extensions are built against CPython's limited API (abi3) and
130
+ no longer use pybind11.
131
+ - The CPU core is split into modules (decoder, kernels, dispatch, C ABI)
132
+ instead of one 4,300-line file. `src/c_api.cpp` includes `dbs.h` rather
133
+ than re-declaring it.
134
+ - `dbs_create_ex` rejects negative or non-finite options instead of silently
135
+ replacing them with defaults. Zero-initialised fields still select
136
+ defaults.
137
+ - The GNMT length penalty is evaluated in double precision from basic IEEE
138
+ operations (no `pow`) and rounded once, in a header the CPU and CUDA code
139
+ share, so the two agree bit for bit. Scores with `length_penalty_alpha != 0`
140
+ can differ from 1.x in the last bit.
141
+ - The softmax, dot product and sigmoid of the C-level surrogates are scalar on
142
+ every kernel path (the AVX-512 path used a different `exp`), and the core is
143
+ compiled without floating-point contraction, so results do not depend on
144
+ the SIMD path. The row scan keeps its SIMD paths, now for banned tokens and
145
+ EOS masking too, and a NEON path.
146
+ - Input validation (`validate_inputs`) checks every element of every row the
147
+ search reads, during the scan, in C, PyTorch (CPU and CUDA) and JAX.
148
+ Previously the C library sampled 1000 entries, JAX did not check at all, and
149
+ PyTorch made three extra passes over the tensor.
150
+ - The relaxed top-k pool is opt-in (`relaxed_pool_multiplier` defaults to 0):
151
+ keeping `8 * K` candidates per step made every decode pay for it
152
+ (K=64: 3.4 ms to 0.9 ms; K=256: 24 ms to 4 ms). `vocab_block` is ignored.
153
+ - Invalid arguments and inputs return `-1` as the header documents (they
154
+ returned `-2`), and every failing call records its own error message.
155
+ - CUDA: no kernel sorts a whole tile of candidates any more. Beams up to 16
156
+ use a register top-k scan, sized so that a single example still fills the
157
+ GPU; every scan, reduction and selection finds a block's best `K` keys with
158
+ a radix select and only the step's `K` winners are sorted. On an RTX 4080
159
+ SUPER a decode of B=8, T=16, V=32k takes 4.3 ms instead of 28.7 ms at K=64
160
+ (0.26 ms instead of 0.59 ms for B=1, K=4); results are unchanged, bit for
161
+ bit. The backward processes the beams of a step in parallel
162
+ (deterministically) instead of one thread per example.
163
+ - `dbs_decode_batch*` run on the calling thread as well and do not start
164
+ threads for a single example; variable batches read smaller beams in place
165
+ instead of copying them.
166
+ - PyTorch 2.4 or newer is required (for `torch.library.register_fake` and
167
+ `register_autograd`).
168
+ - SIMD scans pass candidates tied with the pool threshold to the exact
169
+ comparator, so every ISA path matches the scalar reference in all tie cases.
170
+ - `dbs_last_error` returns a thread-local copy, so the pointer stays valid if
171
+ another thread records an error on the same decoder.
172
+ - The CUDA API is reduced to `dbs_cuda_decode` / `dbs_cuda_backward` and is
173
+ asynchronous by default; its header carries export macros.
174
+ - Python 3.10 or newer is required.
175
+ - The C ABI's relaxed pool, `vocab_block` and status-code changes are listed
176
+ above; code that sets `relaxed_pool_multiplier` explicitly, or only checks
177
+ for a non-zero status, is unaffected.
178
+
179
+ ### Fixed
180
+
181
+ - `beam_search(..., device="cuda")` rejected rows on `cuda:0`, because
182
+ `torch.device("cuda")` does not compare equal to `torch.device("cuda:0")`.
183
+ - Integers beyond 32 bits were truncated instead of rejected: `steps=[4,
184
+ 2**32 + 1]` decoded one step for the second example (PyTorch on CPU and
185
+ CUDA, and JAX with 64-bit arrays), and through JAX's ctypes bindings
186
+ `min_length=2**32 + 1` became 1 and `no_repeat_ngram_size=2**32 + 1` became
187
+ 1. Step counts are now range-checked before they are narrowed, non-integer
188
+ step counts are rejected, and `BeamOptions` rejects integer options outside
189
+ the 32-bit range.
190
+ - `torch.func.grad`, `vjp` and `jacrev` (and `vmap` of them) failed on
191
+ `final_scores`: the autograd formula registered with `torch.library` is an
192
+ `autograd.Function` without a separate `setup_context`, which `torch.func`
193
+ requires.
194
+ - The length penalty converted `length_penalty_alpha` to `int` before checking
195
+ its range, which is undefined behaviour for exponents beyond `INT_MAX`.
196
+ - `banned_tokens` cost a `[V]` Python list and its conversion to a tensor on
197
+ every PyTorch call (4 ms at V=128k); the mask is now scattered on the
198
+ target device.
199
+ - Backward rejected results whose beam size differed from the decoder's, so
200
+ examples of `dbs_decode_batch_variable` with their own beam sizes could not
201
+ be differentiated.
202
+ - `dbs_result_validate_deterministic_order` skipped the raw-score tie-break
203
+ and reported the decoder's own output as out of order (with a length
204
+ penalty and EOS).
205
+ - `dbs_allocator_counters_reset` zeroed the live byte count, which then went
206
+ negative as allocations were freed; it now resets only the call count.
207
+ - Early failures (null handle or output pointer) returned without recording
208
+ an error, so `dbs_last_global_error()` showed the previous call's message.
209
+ - `dbs_set_deterministic_seed` wrote the seed without synchronization.
210
+ - The CPU-only `libdbs_cuda` stub exported no symbols (hidden visibility and
211
+ no export macros) and lacked five declared functions, so linking against it
212
+ failed.
213
+ - The CUDA sparse backward attributed each final beam's gradient to the same
214
+ slot index at every step instead of following the beam's path, and used a
215
+ different estimator from the CPU. It is replaced by the exact path gradient.
216
+ - Typed and variable-batch decoding use overflow-checked size arithmetic.
217
+ - Batch decoding records errors in stats and reports real elapsed time.
218
+ - The JAX custom VJP no longer calls itself from its forward rule.
219
+
220
+ ### Removed
221
+
222
+ - `dbs_validate_production_gate_manifest`, a stub that always failed.
223
+ - The test-only SIMD parity hooks, which were compiled into every build of the
224
+ library; the parity tests now live in `tests/internal_tests.cpp`.
225
+ - The `torch_dbs_extension`, `torch_dbs` and `jax_dbs` modules (use
226
+ `beamgrad`, `beamgrad._ctypes` and `beamgrad.jax`).
227
+ - `dbs_cuda_decode_forward*`, `dbs_cuda_decode_forward_variable`,
228
+ `dbs_cuda_backward_build_sparse` and `dbs_cuda_sparse_backward_scatter`
229
+ (use `dbs_cuda_decode` / `dbs_cuda_backward`); the
230
+ `DBS_ENABLE_SCORE_ONLY_FAST_PATH` switch and the `DBS_CUDA_USE_FAST_MATH`
231
+ option.
232
+ - Placeholder release material: SBOM/provenance templates, fixture manifests
233
+ and platform locks with `TBD` values, and the scripts built around them.
234
+
235
+ ### Migrating from 1.x
236
+
237
+ | 1.x | 2.0 |
238
+ |---|---|
239
+ | `pip install dbs-torch` | `pip install --no-build-isolation beamgrad` |
240
+ | `from torch_dbs_extension import DBSOptions, final_scores` | `from beamgrad import BeamOptions, final_scores` |
241
+ | `DBSOptions(beam_size=K, selected_temperature=..., ...)` | `BeamOptions(beam_size=K, eos_token=..., min_length=..., length_penalty_alpha=...)`; the other fields never affected `final_scores` |
242
+ | `torch_dbs_extension.decode(x, opts)` (CUDA only) | `beamgrad.decode(x, opts)` on CPU or CUDA |
243
+ | `DBS_BUILD_TORCH_CUDA=1` | automatic; force with `BEAMGRAD_CUDA=1` |
244
+ | `find_package(dbs)`, `dbs::dbs` | `find_package(beamgrad)`, `beamgrad::dbs` |
245
+
246
+ ## 1.0.0
247
+
248
+ First stable release, as `dbs-torch` / `differentiable-beam-search-cuda`.
249
+
250
+ - C ABI version 10: hard beam search with deterministic ordering, GNMT length
251
+ penalty, EOS handling and minimum length; sparse (default) and capped dense
252
+ surrogate backward over final scores, selected-beam weights and a relaxed
253
+ top-k pool; batch and variable-length batch decoding; banned/forced tokens,
254
+ repetition penalty, n-gram blocking and token-filter callbacks; fp16/bf16
255
+ input; model-callback decoding with reusable workspaces; statistics and
256
+ JSON summaries.
257
+ - Runtime-dispatched AVX-512, AVX2, SSE4.2 and NEON kernels.
258
+ - PyTorch extension with CPU autograd and a CUDA forward kernel for beams up
259
+ to 32 (other cases ran on the CPU); ctypes and JAX wrappers.
260
+
261
+ ## 0.x
262
+
263
+ Development releases leading to 1.0: the C ABI, sparse-by-default backward,
264
+ batching, constraints, SIMD kernels, and the first CUDA kernels.
@@ -0,0 +1,259 @@
1
+ cmake_minimum_required(VERSION 3.20)
2
+
3
+ project(beamgrad
4
+ VERSION 2.0.0
5
+ DESCRIPTION "Differentiable beam search: C ABI, SIMD CPU kernels, and native CUDA"
6
+ HOMEPAGE_URL "https://github.com/maged15/beamgrad"
7
+ LANGUAGES C CXX)
8
+
9
+ string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" DBS_TOP_LEVEL)
10
+
11
+ option(DBS_BUILD_SHARED "Build shared libraries (static when OFF)" ON)
12
+ option(DBS_BUILD_TESTS "Build the test suite" ${DBS_TOP_LEVEL})
13
+ option(DBS_BUILD_BENCHMARKS "Build the C++ benchmark" ${DBS_TOP_LEVEL})
14
+ option(DBS_BUILD_FUZZER "Build the libFuzzer harness (Clang only)" OFF)
15
+ option(DBS_ENABLE_CUDA "Build the native CUDA backend (otherwise a stub is built)" OFF)
16
+ option(DBS_ENABLE_SANITIZERS "Build with AddressSanitizer and UndefinedBehaviorSanitizer" OFF)
17
+ option(DBS_ENABLE_TSAN "Build with ThreadSanitizer" OFF)
18
+ option(DBS_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF)
19
+
20
+ # The C ABI version is the shared-library SOVERSION; it changes only on
21
+ # binary-incompatible changes (see docs/c-api.md).
22
+ set(DBS_ABI_VERSION 10)
23
+
24
+ set(CMAKE_CXX_STANDARD 17)
25
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
26
+ set(CMAKE_CXX_EXTENSIONS OFF)
27
+ set(CMAKE_CXX_VISIBILITY_PRESET hidden)
28
+ set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
29
+ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
30
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
31
+ endif()
32
+
33
+ include(GNUInstallDirs)
34
+
35
+ if(DBS_ENABLE_SANITIZERS AND NOT MSVC)
36
+ add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=undefined)
37
+ add_link_options(-fsanitize=address,undefined)
38
+ endif()
39
+ if(DBS_ENABLE_TSAN AND NOT MSVC)
40
+ add_compile_options(-fsanitize=thread -fno-omit-frame-pointer)
41
+ add_link_options(-fsanitize=thread)
42
+ endif()
43
+
44
+ # Floating-point contraction (fused multiply-add) would let compilers round
45
+ # differently on different targets; results must not depend on the target.
46
+ function(dbs_set_fp_model target)
47
+ if(NOT MSVC)
48
+ target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-ffp-contract=off>)
49
+ endif()
50
+ endfunction()
51
+
52
+ function(dbs_set_warnings target)
53
+ if(MSVC)
54
+ target_compile_options(${target} PRIVATE /W4 /permissive-)
55
+ if(DBS_WARNINGS_AS_ERRORS)
56
+ target_compile_options(${target} PRIVATE /WX)
57
+ endif()
58
+ else()
59
+ target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wall -Wextra -Wpedantic>)
60
+ if(DBS_WARNINGS_AS_ERRORS)
61
+ target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Werror>)
62
+ endif()
63
+ endif()
64
+ endfunction()
65
+
66
+ if(DBS_BUILD_SHARED)
67
+ set(DBS_LIBRARY_TYPE SHARED)
68
+ else()
69
+ set(DBS_LIBRARY_TYPE STATIC)
70
+ endif()
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # libdbs: CPU decoder and C ABI
74
+ # ---------------------------------------------------------------------------
75
+
76
+ set(DBS_CORE_SOURCES
77
+ src/c_api.cpp
78
+ src/cpu_features.cpp
79
+ src/decoder.cpp
80
+ src/kernels_scalar.cpp
81
+ src/kernels_x86.cpp)
82
+
83
+ # Object library so the internal tests can link the implementation directly.
84
+ add_library(dbs_core_objects OBJECT ${DBS_CORE_SOURCES})
85
+ set_target_properties(dbs_core_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
86
+ target_include_directories(dbs_core_objects PRIVATE include src)
87
+ if(DBS_BUILD_SHARED)
88
+ target_compile_definitions(dbs_core_objects PRIVATE DBS_BUILD_SHARED DBS_COMPILING_LIBRARY)
89
+ else()
90
+ target_compile_definitions(dbs_core_objects PRIVATE DBS_STATIC)
91
+ endif()
92
+ dbs_set_warnings(dbs_core_objects)
93
+ dbs_set_fp_model(dbs_core_objects)
94
+
95
+ add_library(dbs ${DBS_LIBRARY_TYPE} $<TARGET_OBJECTS:dbs_core_objects>)
96
+ add_library(beamgrad::dbs ALIAS dbs)
97
+ target_include_directories(dbs PUBLIC
98
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
99
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
100
+ find_package(Threads REQUIRED)
101
+ target_link_libraries(dbs PRIVATE Threads::Threads)
102
+ if(DBS_BUILD_SHARED)
103
+ target_compile_definitions(dbs INTERFACE DBS_BUILD_SHARED)
104
+ set_target_properties(dbs PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${DBS_ABI_VERSION})
105
+ if(UNIX AND NOT APPLE)
106
+ target_link_options(dbs PRIVATE "-Wl,--version-script=${PROJECT_SOURCE_DIR}/cmake/dbs.map")
107
+ endif()
108
+ else()
109
+ target_compile_definitions(dbs INTERFACE DBS_STATIC)
110
+ endif()
111
+
112
+ # ---------------------------------------------------------------------------
113
+ # libdbs_cuda: native CUDA backend, or a stub that reports "unavailable"
114
+ # ---------------------------------------------------------------------------
115
+
116
+ if(DBS_ENABLE_CUDA)
117
+ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
118
+ set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90)
119
+ endif()
120
+ enable_language(CUDA)
121
+ add_library(dbs_cuda ${DBS_LIBRARY_TYPE} cuda/dbs_cuda.cu)
122
+ set_target_properties(dbs_cuda PROPERTIES
123
+ CUDA_STANDARD 17
124
+ CUDA_STANDARD_REQUIRED ON
125
+ CUDA_VISIBILITY_PRESET hidden
126
+ POSITION_INDEPENDENT_CODE ON)
127
+ else()
128
+ add_library(dbs_cuda ${DBS_LIBRARY_TYPE} cuda/dbs_cuda_stub.cpp)
129
+ dbs_set_warnings(dbs_cuda)
130
+ endif()
131
+ add_library(beamgrad::dbs_cuda ALIAS dbs_cuda)
132
+ target_include_directories(dbs_cuda
133
+ PUBLIC
134
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
135
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
136
+ PRIVATE src)
137
+ if(DBS_BUILD_SHARED)
138
+ target_compile_definitions(dbs_cuda PRIVATE DBS_BUILD_SHARED DBS_COMPILING_LIBRARY INTERFACE DBS_BUILD_SHARED)
139
+ set_target_properties(dbs_cuda PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${DBS_ABI_VERSION})
140
+ else()
141
+ target_compile_definitions(dbs_cuda PUBLIC DBS_STATIC)
142
+ endif()
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # Tests, benchmark, fuzzer
146
+ # ---------------------------------------------------------------------------
147
+
148
+ if(DBS_BUILD_TESTS)
149
+ enable_testing()
150
+
151
+ add_executable(dbs_tests tests/dbs_tests.cpp)
152
+ target_link_libraries(dbs_tests PRIVATE dbs)
153
+ dbs_set_warnings(dbs_tests)
154
+ add_test(NAME dbs_tests COMMAND dbs_tests)
155
+
156
+ add_executable(dbs_internal_tests tests/internal_tests.cpp $<TARGET_OBJECTS:dbs_core_objects>)
157
+ target_include_directories(dbs_internal_tests PRIVATE include src tests)
158
+ target_compile_definitions(dbs_internal_tests PRIVATE DBS_STATIC)
159
+ target_link_libraries(dbs_internal_tests PRIVATE Threads::Threads)
160
+ dbs_set_warnings(dbs_internal_tests)
161
+ dbs_set_fp_model(dbs_internal_tests)
162
+ add_test(NAME dbs_internal_tests COMMAND dbs_internal_tests)
163
+
164
+ # Both public headers must be valid C, and both libraries must export them.
165
+ add_executable(dbs_c_api_test tests/c_api_test.c)
166
+ target_link_libraries(dbs_c_api_test PRIVATE dbs dbs_cuda)
167
+ dbs_set_warnings(dbs_c_api_test)
168
+ add_test(NAME dbs_c_api_test COMMAND dbs_c_api_test)
169
+
170
+ # The documented C example must keep compiling and running.
171
+ add_executable(dbs_example_c_api examples/c_api.c)
172
+ target_link_libraries(dbs_example_c_api PRIVATE dbs)
173
+ dbs_set_warnings(dbs_example_c_api)
174
+ add_test(NAME dbs_example_c_api COMMAND dbs_example_c_api)
175
+
176
+ if(DBS_ENABLE_SANITIZERS)
177
+ # A UBSan-instrumented libdbs needs the sanitizer's C++ runtime, which only
178
+ # the C++ driver links (Clang); plain C consumers are covered by normal builds.
179
+ set_target_properties(dbs_c_api_test dbs_example_c_api PROPERTIES LINKER_LANGUAGE CXX)
180
+ endif()
181
+
182
+ # The CUDA backend source, executed on the CPU and checked against libdbs.
183
+ # Needs POSIX ucontext; Linux is enough to verify the kernel logic.
184
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
185
+ add_executable(dbs_cuda_emulation_tests tests/cuda_emulation_tests.cpp)
186
+ target_include_directories(dbs_cuda_emulation_tests PRIVATE include src tests)
187
+ target_link_libraries(dbs_cuda_emulation_tests PRIVATE dbs)
188
+ dbs_set_fp_model(dbs_cuda_emulation_tests)
189
+ add_test(NAME dbs_cuda_emulation_tests COMMAND dbs_cuda_emulation_tests)
190
+ if(DBS_ENABLE_SANITIZERS)
191
+ # ASan cannot follow ucontext stack switches.
192
+ set_tests_properties(dbs_cuda_emulation_tests PROPERTIES
193
+ ENVIRONMENT "ASAN_OPTIONS=detect_stack_use_after_return=0:detect_leaks=1")
194
+ endif()
195
+ endif()
196
+
197
+ # The native CUDA backend on a real GPU against libdbs, bit for bit. Skipped
198
+ # (exit code 77) when no device is present.
199
+ if(DBS_ENABLE_CUDA)
200
+ find_package(CUDAToolkit REQUIRED)
201
+ add_executable(dbs_cuda_device_tests tests/cuda_device_tests.cpp)
202
+ target_include_directories(dbs_cuda_device_tests PRIVATE tests)
203
+ target_link_libraries(dbs_cuda_device_tests PRIVATE dbs dbs_cuda CUDA::cudart)
204
+ dbs_set_warnings(dbs_cuda_device_tests)
205
+ add_test(NAME dbs_cuda_device_tests COMMAND dbs_cuda_device_tests)
206
+ set_tests_properties(dbs_cuda_device_tests PROPERTIES SKIP_RETURN_CODE 77)
207
+ endif()
208
+
209
+ if(UNIX AND NOT APPLE AND DBS_BUILD_SHARED)
210
+ add_test(NAME dbs_abi_symbols
211
+ COMMAND bash ${PROJECT_SOURCE_DIR}/scripts/check_abi.sh $<TARGET_FILE:dbs>)
212
+ endif()
213
+ endif()
214
+
215
+ if(DBS_BUILD_BENCHMARKS)
216
+ add_executable(dbs_bench benchmarks/dbs_bench.cpp)
217
+ target_link_libraries(dbs_bench PRIVATE dbs)
218
+ endif()
219
+
220
+ if(DBS_BUILD_FUZZER)
221
+ if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
222
+ message(FATAL_ERROR "DBS_BUILD_FUZZER requires Clang (libFuzzer)")
223
+ endif()
224
+ add_executable(dbs_fuzz tests/fuzz_dbs.cpp)
225
+ target_link_libraries(dbs_fuzz PRIVATE dbs)
226
+ target_compile_options(dbs_fuzz PRIVATE -fsanitize=fuzzer)
227
+ target_link_options(dbs_fuzz PRIVATE -fsanitize=fuzzer)
228
+ endif()
229
+
230
+ # ---------------------------------------------------------------------------
231
+ # Install: headers, libraries, CMake package (find_package(beamgrad)), pkg-config
232
+ # ---------------------------------------------------------------------------
233
+
234
+ install(TARGETS dbs dbs_cuda EXPORT beamgradTargets
235
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
236
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
237
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
238
+ install(FILES include/dbs.h include/dbs_cuda.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
239
+ install(EXPORT beamgradTargets
240
+ FILE beamgradTargets.cmake
241
+ NAMESPACE beamgrad::
242
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beamgrad)
243
+
244
+ include(CMakePackageConfigHelpers)
245
+ write_basic_package_version_file(
246
+ "${PROJECT_BINARY_DIR}/beamgradConfigVersion.cmake"
247
+ VERSION ${PROJECT_VERSION}
248
+ COMPATIBILITY SameMajorVersion)
249
+ configure_package_config_file(
250
+ "${PROJECT_SOURCE_DIR}/cmake/beamgradConfig.cmake.in"
251
+ "${PROJECT_BINARY_DIR}/beamgradConfig.cmake"
252
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beamgrad)
253
+ install(FILES
254
+ "${PROJECT_BINARY_DIR}/beamgradConfig.cmake"
255
+ "${PROJECT_BINARY_DIR}/beamgradConfigVersion.cmake"
256
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beamgrad)
257
+
258
+ configure_file(pkgconfig/dbs.pc.in dbs.pc @ONLY)
259
+ install(FILES "${PROJECT_BINARY_DIR}/dbs.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
beamgrad-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maged Amr
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,8 @@
1
+ include VERSION LICENSE README.md CHANGELOG.md CMakeLists.txt
2
+ recursive-include include *.h
3
+ recursive-include src *.cpp *.hpp
4
+ recursive-include cuda *.cu *.cpp *.hpp
5
+ recursive-include python/csrc *.cpp
6
+ recursive-include cmake *.in *.map
7
+ recursive-include pkgconfig *.in
8
+ recursive-include abi *.symbols