treeweave 0.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.
- treeweave-0.0.0/CMakeLists.txt +62 -0
- treeweave-0.0.0/PKG-INFO +89 -0
- treeweave-0.0.0/README.md +78 -0
- treeweave-0.0.0/pyproject.toml +78 -0
- treeweave-0.0.0/src/_treeweave.cpp +583 -0
- treeweave-0.0.0/tests/conftest.py +2 -0
- treeweave-0.0.0/tests/test_treeweave.py +321 -0
- treeweave-0.0.0/treeweave/__init__.py +326 -0
- treeweave-0.0.0/treeweave_python.cmake +70 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# bindings/python — nanobind extension linking treeweave_c_static + a pytest
|
|
2
|
+
# CTest. Added by cmake/treeweave_bindings.cmake when TREEWEAVE_BUILD_PYTHON=ON.
|
|
3
|
+
# The pip/scikit-build wheel build reaches this same file: pyproject sets
|
|
4
|
+
# cmake.source-dir = "../../" and configures the root with TREEWEAVE_BUILD_PYTHON=ON.
|
|
5
|
+
|
|
6
|
+
# Development.SABIModule (optional) lets nanobind emit a CPython stable-ABI
|
|
7
|
+
# (abi3) extension on 3.12+, which is what the wheel build ships.
|
|
8
|
+
find_package(
|
|
9
|
+
Python
|
|
10
|
+
3.9
|
|
11
|
+
QUIET
|
|
12
|
+
COMPONENTS Interpreter Development.Module
|
|
13
|
+
OPTIONAL_COMPONENTS Development.SABIModule
|
|
14
|
+
)
|
|
15
|
+
if(NOT Python_FOUND)
|
|
16
|
+
message(
|
|
17
|
+
STATUS
|
|
18
|
+
"treeweave[python]: Python 3.9+ (Development.Module) not found — skipping."
|
|
19
|
+
)
|
|
20
|
+
return()
|
|
21
|
+
endif()
|
|
22
|
+
|
|
23
|
+
# Shared module definition (also used by the pip wheel build) — locates nanobind
|
|
24
|
+
# (interpreter or FetchContent) and defines the `_treeweave` target.
|
|
25
|
+
include("${CMAKE_CURRENT_SOURCE_DIR}/treeweave_python.cmake")
|
|
26
|
+
treeweave_add_python_module(treeweave::treeweave_c_static)
|
|
27
|
+
|
|
28
|
+
# Install the extension into the wheel's `treeweave/` package. Scoped to its own
|
|
29
|
+
# component so the scikit-build-core wheel build installs ONLY this
|
|
30
|
+
# (install.components = ["python_ext"] in pyproject.toml) and never drags in the
|
|
31
|
+
# C++ dev tree (headers / libtreeweave_c / CMake config).
|
|
32
|
+
install(TARGETS _treeweave LIBRARY DESTINATION treeweave COMPONENT python_ext)
|
|
33
|
+
|
|
34
|
+
# Assemble an importable package *in the build tree* — never write the .so (or
|
|
35
|
+
# copy .py) into the source tree. Layout: <build>/python-pkg/treeweave/.
|
|
36
|
+
set(_treeweave_pypkg "${CMAKE_BINARY_DIR}/python-pkg")
|
|
37
|
+
set_target_properties(
|
|
38
|
+
_treeweave
|
|
39
|
+
PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${_treeweave_pypkg}/treeweave"
|
|
40
|
+
)
|
|
41
|
+
# Stage the pure-Python sources next to the extension (re-copied on reconfigure
|
|
42
|
+
# if they change, via the configure_file input dependency).
|
|
43
|
+
file(GLOB _treeweave_py "${CMAKE_CURRENT_SOURCE_DIR}/treeweave/*.py")
|
|
44
|
+
foreach(_f IN LISTS _treeweave_py)
|
|
45
|
+
get_filename_component(_n "${_f}" NAME)
|
|
46
|
+
configure_file("${_f}" "${_treeweave_pypkg}/treeweave/${_n}" COPYONLY)
|
|
47
|
+
endforeach()
|
|
48
|
+
|
|
49
|
+
add_test(
|
|
50
|
+
NAME python_treeweave
|
|
51
|
+
COMMAND
|
|
52
|
+
"${Python_EXECUTABLE}" -m pytest -q "${CMAKE_CURRENT_SOURCE_DIR}/tests"
|
|
53
|
+
)
|
|
54
|
+
set_tests_properties(
|
|
55
|
+
python_treeweave
|
|
56
|
+
PROPERTIES ENVIRONMENT "PYTHONPATH=${_treeweave_pypkg}"
|
|
57
|
+
)
|
|
58
|
+
message(
|
|
59
|
+
STATUS
|
|
60
|
+
"treeweave[python]: extension + pytest 'python_treeweave' registered "
|
|
61
|
+
"(build-tree package at ${_treeweave_pypkg})."
|
|
62
|
+
)
|
treeweave-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: treeweave
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: Python bindings for the treeweave piecewise-polynomial approximator
|
|
5
|
+
License-Expression: BSD-3-Clause
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Provides-Extra: test
|
|
9
|
+
Requires-Dist: pytest; extra == "test"
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# treeweave Python bindings
|
|
13
|
+
|
|
14
|
+
Python (nanobind) wrapper for the [treeweave](../../README.md) piecewise-polynomial
|
|
15
|
+
function approximator.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install scikit-build-core nanobind numpy
|
|
21
|
+
pip install . # regular install
|
|
22
|
+
# or for development:
|
|
23
|
+
pip install -e . --no-build-isolation
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import math
|
|
30
|
+
import numpy as np
|
|
31
|
+
import treeweave
|
|
32
|
+
|
|
33
|
+
# Fit exp(x) on [0, 1] to 1e-10 relative tolerance.
|
|
34
|
+
def func(x):
|
|
35
|
+
return math.exp(x[0]) # x is a (dim,) ndarray
|
|
36
|
+
|
|
37
|
+
approx = treeweave.fit(func, 0.0, 1.0, tol=1e-10) # dim & out_dim inferred
|
|
38
|
+
|
|
39
|
+
# Scalar eval
|
|
40
|
+
print(approx(0.5)) # ≈ exp(0.5)
|
|
41
|
+
|
|
42
|
+
# Batch eval
|
|
43
|
+
xs = np.linspace(0, 1, 1000)
|
|
44
|
+
ys = approx(xs) # shape (1000,)
|
|
45
|
+
ys = approx(xs, sorted=True) # 1-D ascending fast path
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
### `treeweave.fit(f, a, b, tol, *, dim=None, out_dim=None, dtype="f64", ...)`
|
|
51
|
+
|
|
52
|
+
Fits callable `f` and returns a callable `TreeweaveFunction`.
|
|
53
|
+
|
|
54
|
+
- `a`, `b`: domain corners (scalars for 1D, length-`dim` lists otherwise).
|
|
55
|
+
- `tol`: approximation tolerance (drives adaptive tree refinement).
|
|
56
|
+
- `dim`: input dimension; inferred from `len(a)` (scalar corners ⇒ 1) when omitted.
|
|
57
|
+
- `out_dim`: number of output components; inferred by probing `f` once at the
|
|
58
|
+
box midpoint (`np.asarray(f(mid)).size`, scalar ⇒ 1) when omitted.
|
|
59
|
+
- `dtype`: `"f64"` (default) or `"f32"`.
|
|
60
|
+
|
|
61
|
+
The C ABI auto-selects a register-optimal leaf polynomial degree per detected CPU; accuracy is controlled entirely by `tol`.
|
|
62
|
+
|
|
63
|
+
### `TreeweaveFunction`
|
|
64
|
+
|
|
65
|
+
The fitted object is **called** — there are no named eval methods. A point
|
|
66
|
+
gives a point result; a batch gives a batch result; two optional keyword flags
|
|
67
|
+
select alternate batch modes.
|
|
68
|
+
|
|
69
|
+
| Call / property | Description |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `fn(x)` | Evaluate. Point: scalar (`dim==1`) or `(dim,)` → scalar / `(out_dim,)`. Batch: `(N,)` (`dim==1`) or `(N, dim)` → `(N,)` / `(N, out_dim)` |
|
|
72
|
+
| `fn(x, sorted=True)` | 1-D ascending-batch fast path (requires `dim == 1`) |
|
|
73
|
+
| `fn(x, transposed=True)` | Batch returning `(out_dim, N)` (requires `out_dim > 1`) |
|
|
74
|
+
| `.dim` | Input dimensionality |
|
|
75
|
+
| `.out_dim` | Output dimensionality |
|
|
76
|
+
| `.dtype` | `"f64"` or `"f32"` |
|
|
77
|
+
| `.memory_usage` | Bytes used by the approximation |
|
|
78
|
+
| `.print_stats()` | Print internal tree statistics |
|
|
79
|
+
|
|
80
|
+
A point whose length `!= dim`, a batch whose column count `!= dim`,
|
|
81
|
+
`sorted=True` with `dim != 1`, or `transposed=True` with `out_dim == 1` each
|
|
82
|
+
raise `ValueError` rather than silently mis-shaping the result.
|
|
83
|
+
|
|
84
|
+
## Running tests
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install pytest
|
|
88
|
+
pytest tests/ -q
|
|
89
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# treeweave Python bindings
|
|
2
|
+
|
|
3
|
+
Python (nanobind) wrapper for the [treeweave](../../README.md) piecewise-polynomial
|
|
4
|
+
function approximator.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install scikit-build-core nanobind numpy
|
|
10
|
+
pip install . # regular install
|
|
11
|
+
# or for development:
|
|
12
|
+
pip install -e . --no-build-isolation
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import math
|
|
19
|
+
import numpy as np
|
|
20
|
+
import treeweave
|
|
21
|
+
|
|
22
|
+
# Fit exp(x) on [0, 1] to 1e-10 relative tolerance.
|
|
23
|
+
def func(x):
|
|
24
|
+
return math.exp(x[0]) # x is a (dim,) ndarray
|
|
25
|
+
|
|
26
|
+
approx = treeweave.fit(func, 0.0, 1.0, tol=1e-10) # dim & out_dim inferred
|
|
27
|
+
|
|
28
|
+
# Scalar eval
|
|
29
|
+
print(approx(0.5)) # ≈ exp(0.5)
|
|
30
|
+
|
|
31
|
+
# Batch eval
|
|
32
|
+
xs = np.linspace(0, 1, 1000)
|
|
33
|
+
ys = approx(xs) # shape (1000,)
|
|
34
|
+
ys = approx(xs, sorted=True) # 1-D ascending fast path
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
### `treeweave.fit(f, a, b, tol, *, dim=None, out_dim=None, dtype="f64", ...)`
|
|
40
|
+
|
|
41
|
+
Fits callable `f` and returns a callable `TreeweaveFunction`.
|
|
42
|
+
|
|
43
|
+
- `a`, `b`: domain corners (scalars for 1D, length-`dim` lists otherwise).
|
|
44
|
+
- `tol`: approximation tolerance (drives adaptive tree refinement).
|
|
45
|
+
- `dim`: input dimension; inferred from `len(a)` (scalar corners ⇒ 1) when omitted.
|
|
46
|
+
- `out_dim`: number of output components; inferred by probing `f` once at the
|
|
47
|
+
box midpoint (`np.asarray(f(mid)).size`, scalar ⇒ 1) when omitted.
|
|
48
|
+
- `dtype`: `"f64"` (default) or `"f32"`.
|
|
49
|
+
|
|
50
|
+
The C ABI auto-selects a register-optimal leaf polynomial degree per detected CPU; accuracy is controlled entirely by `tol`.
|
|
51
|
+
|
|
52
|
+
### `TreeweaveFunction`
|
|
53
|
+
|
|
54
|
+
The fitted object is **called** — there are no named eval methods. A point
|
|
55
|
+
gives a point result; a batch gives a batch result; two optional keyword flags
|
|
56
|
+
select alternate batch modes.
|
|
57
|
+
|
|
58
|
+
| Call / property | Description |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `fn(x)` | Evaluate. Point: scalar (`dim==1`) or `(dim,)` → scalar / `(out_dim,)`. Batch: `(N,)` (`dim==1`) or `(N, dim)` → `(N,)` / `(N, out_dim)` |
|
|
61
|
+
| `fn(x, sorted=True)` | 1-D ascending-batch fast path (requires `dim == 1`) |
|
|
62
|
+
| `fn(x, transposed=True)` | Batch returning `(out_dim, N)` (requires `out_dim > 1`) |
|
|
63
|
+
| `.dim` | Input dimensionality |
|
|
64
|
+
| `.out_dim` | Output dimensionality |
|
|
65
|
+
| `.dtype` | `"f64"` or `"f32"` |
|
|
66
|
+
| `.memory_usage` | Bytes used by the approximation |
|
|
67
|
+
| `.print_stats()` | Print internal tree statistics |
|
|
68
|
+
|
|
69
|
+
A point whose length `!= dim`, a batch whose column count `!= dim`,
|
|
70
|
+
`sorted=True` with `dim != 1`, or `transposed=True` with `out_dim == 1` each
|
|
71
|
+
raise `ValueError` rather than silently mis-shaping the result.
|
|
72
|
+
|
|
73
|
+
## Running tests
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install pytest
|
|
77
|
+
pytest tests/ -q
|
|
78
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["scikit-build-core>=0.10", "nanobind>=2.0"]
|
|
3
|
+
build-backend = "scikit_build_core.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "treeweave"
|
|
7
|
+
description = "Python bindings for the treeweave piecewise-polynomial approximator"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "BSD-3-Clause"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
dependencies = ["numpy"]
|
|
12
|
+
# Single-sourced from the root VERSION file via the regex provider below (the
|
|
13
|
+
# same file the root CMakeLists project() reads), so the wheel metadata, the C++
|
|
14
|
+
# core, and any future bump never drift apart.
|
|
15
|
+
dynamic = ["version"]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
test = ["pytest"]
|
|
19
|
+
|
|
20
|
+
[tool.scikit-build]
|
|
21
|
+
minimum-version = "0.10"
|
|
22
|
+
cmake.build-type = "Release"
|
|
23
|
+
# The Python package lives here in bindings/python, but the C++ core it links
|
|
24
|
+
# is the whole repo. Point scikit-build-core at the root CMakeLists (built
|
|
25
|
+
# with TREEWEAVE_BUILD_PYTHON=ON) so the wheel is self-contained — the same trick
|
|
26
|
+
# finufft uses. cibuildwheel copies the repo root into the build container, so
|
|
27
|
+
# "../../" resolves there too.
|
|
28
|
+
cmake.source-dir = "../../"
|
|
29
|
+
build.targets = ["_treeweave"]
|
|
30
|
+
# Install ONLY the extension component into the wheel (the install() rule in
|
|
31
|
+
# cmake/treeweave_bindings.cmake tags _treeweave with COMPONENT python_ext); without
|
|
32
|
+
# this the root install would also stage the C++ headers / libtreeweave_c / CMake
|
|
33
|
+
# config into the wheel.
|
|
34
|
+
install.components = ["python_ext"]
|
|
35
|
+
# The pure-Python package (treeweave/*.py) sits next to this pyproject.
|
|
36
|
+
wheel.packages = ["treeweave"]
|
|
37
|
+
# One abi3 wheel (CPython stable ABI) serves 3.12+; the nanobind module is
|
|
38
|
+
# built STABLE_ABI (see treeweave_python.cmake). 3.9–3.11 get version-specific
|
|
39
|
+
# wheels from the per-version cibuildwheel runs.
|
|
40
|
+
wheel.py-api = "cp312"
|
|
41
|
+
|
|
42
|
+
[tool.scikit-build.cmake.define]
|
|
43
|
+
TREEWEAVE_BUILD_PYTHON = "ON"
|
|
44
|
+
TREEWEAVE_BUILD_TESTS = "OFF"
|
|
45
|
+
TREEWEAVE_BUILD_EXAMPLES = "OFF"
|
|
46
|
+
# A stray warning on the wheel builder's compiler must never break `pip install`.
|
|
47
|
+
TREEWEAVE_WARNINGS_AS_ERRORS = "OFF"
|
|
48
|
+
|
|
49
|
+
[tool.scikit-build.metadata.version]
|
|
50
|
+
provider = "scikit_build_core.metadata.regex"
|
|
51
|
+
input = "../../VERSION"
|
|
52
|
+
regex = '''(?P<value>[0-9]+\.[0-9]+\.[0-9]+)'''
|
|
53
|
+
|
|
54
|
+
# The sdist is rooted at the repo (cmake.source-dir); drop everything the wheel
|
|
55
|
+
# build doesn't need so it stays small and the build context is lean.
|
|
56
|
+
[tool.scikit-build.sdist]
|
|
57
|
+
exclude = [
|
|
58
|
+
".git*", ".github", "bench", "docs", "examples",
|
|
59
|
+
"bindings/julia", "bindings/matlab",
|
|
60
|
+
"build", "build*", "*.whl",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
[tool.cibuildwheel]
|
|
64
|
+
# abi3 wheel once (cp312, covers 3.12+) plus version-specific 3.9–3.11. PyPy
|
|
65
|
+
# and musllinux are out of scope for the C-ABI core.
|
|
66
|
+
build = "cp39-* cp310-* cp311-* cp312-*"
|
|
67
|
+
skip = "*-musllinux_* pp*"
|
|
68
|
+
build-frontend = "build"
|
|
69
|
+
# The C ABI is linked statically into _treeweave, so the only shared deps are the
|
|
70
|
+
# system C/C++ runtimes — nothing external to vendor. The repair step still
|
|
71
|
+
# runs (auditwheel/delocate) to stamp the platform tag. Per-arch baselines
|
|
72
|
+
# (TREEWEAVE_ARCH / TREEWEAVE_C_MULTIARCH) are injected by wheels.yml.
|
|
73
|
+
test-extras = ["test"]
|
|
74
|
+
test-command = "pytest {project}/bindings/python/tests"
|
|
75
|
+
|
|
76
|
+
[tool.cibuildwheel.linux]
|
|
77
|
+
manylinux-x86_64-image = "manylinux_2_28"
|
|
78
|
+
manylinux-aarch64-image = "manylinux_2_28"
|