interpn 0.6.2__tar.gz → 0.6.4__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 (86) hide show
  1. {interpn-0.6.2 → interpn-0.6.4}/.github/workflows/release-python.yml +4 -8
  2. {interpn-0.6.2 → interpn-0.6.4}/.github/workflows/release-rust.yml +0 -1
  3. {interpn-0.6.2 → interpn-0.6.4}/.github/workflows/test-python.yml +8 -2
  4. {interpn-0.6.2 → interpn-0.6.4}/CHANGELOG.md +34 -0
  5. {interpn-0.6.2 → interpn-0.6.4}/Cargo.lock +13 -13
  6. {interpn-0.6.2 → interpn-0.6.4}/Cargo.toml +3 -3
  7. interpn-0.6.4/PKG-INFO +227 -0
  8. {interpn-0.6.2 → interpn-0.6.4}/benches/bench.rs +67 -36
  9. {interpn-0.6.2 → interpn-0.6.4}/benches/bench_cpu.py +56 -2
  10. {interpn-0.6.2 → interpn-0.6.4}/benches/bench_mem.py +12 -8
  11. {interpn-0.6.2 → interpn-0.6.4}/docs/1d_quality_of_fit_Rectilinear.svg +147 -147
  12. {interpn-0.6.2 → interpn-0.6.4}/docs/1d_quality_of_fit_Regular.svg +144 -144
  13. {interpn-0.6.2 → interpn-0.6.4}/docs/2d_quality_of_fit_Rectilinear.svg +247 -247
  14. {interpn-0.6.2 → interpn-0.6.4}/docs/2d_quality_of_fit_Regular.svg +244 -244
  15. {interpn-0.6.2 → interpn-0.6.4}/docs/3d_throughput_vs_nobs.svg +507 -401
  16. {interpn-0.6.2 → interpn-0.6.4}/docs/3d_throughput_vs_nobs_prealloc.svg +509 -403
  17. {interpn-0.6.2 → interpn-0.6.4}/docs/4d_throughput_vs_nobs.svg +513 -400
  18. {interpn-0.6.2 → interpn-0.6.4}/docs/4d_throughput_vs_nobs_prealloc.svg +522 -402
  19. interpn-0.6.4/docs/nearest_quality_of_fit.svg +6053 -0
  20. {interpn-0.6.2 → interpn-0.6.4}/docs/perf.md +5 -0
  21. {interpn-0.6.2 → interpn-0.6.4}/docs/throughput_vs_dims_1000_obs.svg +332 -230
  22. {interpn-0.6.2 → interpn-0.6.4}/docs/throughput_vs_dims_1_obs.svg +298 -210
  23. interpn-0.6.4/examples/nearest_comparison.py +120 -0
  24. {interpn-0.6.2 → interpn-0.6.4}/pyproject.toml +10 -8
  25. interpn-0.6.4/scripts/pgo-profiles/pgo.profdata +0 -0
  26. {interpn-0.6.2 → interpn-0.6.4}/scripts/profile_workload.py +6 -0
  27. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/__init__.py +4 -0
  28. interpn-0.6.4/src/interpn/nearest_rectilinear.py +198 -0
  29. interpn-0.6.4/src/interpn/nearest_regular.py +213 -0
  30. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/raw.py +8 -0
  31. {interpn-0.6.2 → interpn-0.6.4}/src/lib.rs +23 -0
  32. {interpn-0.6.2 → interpn-0.6.4}/src/multicubic/rectilinear.rs +2 -15
  33. {interpn-0.6.2 → interpn-0.6.4}/src/multicubic/regular.rs +2 -15
  34. {interpn-0.6.2 → interpn-0.6.4}/src/multilinear/rectilinear.rs +3 -16
  35. {interpn-0.6.2 → interpn-0.6.4}/src/multilinear/rectilinear_recursive.rs +1 -1
  36. {interpn-0.6.2 → interpn-0.6.4}/src/multilinear/regular.rs +3 -20
  37. {interpn-0.6.2 → interpn-0.6.4}/src/multilinear/regular_recursive.rs +1 -1
  38. interpn-0.6.4/src/nearest/mod.rs +8 -0
  39. interpn-0.6.4/src/nearest/rectilinear.rs +392 -0
  40. interpn-0.6.4/src/nearest/regular.rs +418 -0
  41. {interpn-0.6.2 → interpn-0.6.4}/src/python.rs +67 -1
  42. interpn-0.6.4/test/test_nearest_rectilinear.py +71 -0
  43. interpn-0.6.4/test/test_nearest_regular.py +81 -0
  44. {interpn-0.6.2 → interpn-0.6.4}/uv.lock +308 -110
  45. interpn-0.6.2/PKG-INFO +0 -30
  46. interpn-0.6.2/scripts/pgo-profiles/pgo.profdata +0 -0
  47. {interpn-0.6.2 → interpn-0.6.4}/.cargo/config.toml +0 -0
  48. {interpn-0.6.2 → interpn-0.6.4}/.github/workflows/test-rust.yml +0 -0
  49. {interpn-0.6.2 → interpn-0.6.4}/.gitignore +0 -0
  50. {interpn-0.6.2 → interpn-0.6.4}/.readthedocs.yml +0 -0
  51. {interpn-0.6.2 → interpn-0.6.4}/LICENSE-APACHE +0 -0
  52. {interpn-0.6.2 → interpn-0.6.4}/LICENSE-MIT +0 -0
  53. {interpn-0.6.2 → interpn-0.6.4}/README.md +0 -0
  54. {interpn-0.6.2 → interpn-0.6.4}/docs/API_Docs.md +0 -0
  55. {interpn-0.6.2 → interpn-0.6.4}/docs/index.md +0 -0
  56. {interpn-0.6.2 → interpn-0.6.4}/docs/ram_vs_dims.svg +0 -0
  57. {interpn-0.6.2 → interpn-0.6.4}/docs/requirements.txt +0 -0
  58. {interpn-0.6.2 → interpn-0.6.4}/examples/cubic_comparison.py +0 -0
  59. {interpn-0.6.2 → interpn-0.6.4}/mkdocs.yml +0 -0
  60. {interpn-0.6.2 → interpn-0.6.4}/scripts/distr_pgo.sh +0 -0
  61. {interpn-0.6.2 → interpn-0.6.4}/scripts/distr_pgo_install.sh +0 -0
  62. {interpn-0.6.2 → interpn-0.6.4}/scripts/distr_pgo_profile.sh +0 -0
  63. {interpn-0.6.2 → interpn-0.6.4}/scripts/native_pgo.sh +0 -0
  64. {interpn-0.6.2 → interpn-0.6.4}/scripts/native_pgo_install.sh +0 -0
  65. {interpn-0.6.2 → interpn-0.6.4}/scripts/native_pgo_profile.sh +0 -0
  66. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/multicubic_rectilinear.py +0 -0
  67. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/multicubic_regular.py +0 -0
  68. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/multilinear_rectilinear.py +0 -0
  69. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/multilinear_regular.py +0 -0
  70. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/py.typed +0 -0
  71. {interpn-0.6.2 → interpn-0.6.4}/src/interpn/serialization.py +0 -0
  72. {interpn-0.6.2 → interpn-0.6.4}/src/multicubic/mod.rs +0 -0
  73. {interpn-0.6.2 → interpn-0.6.4}/src/multicubic/rectilinear_recursive.rs +0 -0
  74. {interpn-0.6.2 → interpn-0.6.4}/src/multicubic/regular_recursive.rs +0 -0
  75. {interpn-0.6.2 → interpn-0.6.4}/src/multilinear/mod.rs +0 -0
  76. {interpn-0.6.2 → interpn-0.6.4}/src/one_dim/hold.rs +0 -0
  77. {interpn-0.6.2 → interpn-0.6.4}/src/one_dim/linear.rs +0 -0
  78. {interpn-0.6.2 → interpn-0.6.4}/src/one_dim/mod.rs +0 -0
  79. {interpn-0.6.2 → interpn-0.6.4}/src/testing.rs +0 -0
  80. {interpn-0.6.2 → interpn-0.6.4}/src/utils.rs +0 -0
  81. {interpn-0.6.2 → interpn-0.6.4}/test/test_docs.py +0 -0
  82. {interpn-0.6.2 → interpn-0.6.4}/test/test_examples.py +0 -0
  83. {interpn-0.6.2 → interpn-0.6.4}/test/test_multicubic_rectilinear.py +0 -0
  84. {interpn-0.6.2 → interpn-0.6.4}/test/test_multicubic_regular.py +0 -0
  85. {interpn-0.6.2 → interpn-0.6.4}/test/test_multilinear_rectilinear.py +0 -0
  86. {interpn-0.6.2 → interpn-0.6.4}/test/test_multilinear_regular.py +0 -0
@@ -6,18 +6,14 @@
6
6
  name: release-python
7
7
 
8
8
  on:
9
- push:
10
- branches:
11
- - main
12
9
  workflow_dispatch:
13
10
 
14
11
  permissions:
15
12
  contents: read
16
13
 
17
14
  jobs:
18
- release_rust:
19
- uses: ./.github/workflows/release-rust.yml
20
- secrets: inherit
15
+ test_python:
16
+ uses: ./.github/workflows/test-python.yml
21
17
 
22
18
  linux:
23
19
  runs-on: ${{ matrix.platform.runner }}
@@ -124,7 +120,7 @@ jobs:
124
120
  strategy:
125
121
  matrix:
126
122
  platform:
127
- - runner: macos-13
123
+ - runner: macos-15-intel
128
124
  target: x86_64
129
125
  - runner: macos-14
130
126
  target: aarch64
@@ -163,7 +159,7 @@ jobs:
163
159
  name: Release
164
160
  runs-on: ubuntu-latest
165
161
  # if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
166
- needs: [release_rust, linux, musllinux, windows, macos, sdist]
162
+ needs: [test_python, linux, musllinux, windows, macos, sdist]
167
163
  permissions:
168
164
  # Use to sign the release artifacts
169
165
  id-token: write
@@ -4,7 +4,6 @@ permissions:
4
4
  contents: read
5
5
 
6
6
  on:
7
- workflow_call:
8
7
  workflow_dispatch:
9
8
 
10
9
  jobs:
@@ -11,7 +11,13 @@ jobs:
11
11
  strategy:
12
12
  matrix:
13
13
  target: [x86_64]
14
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14
+ python-version:
15
+ - "3.9"
16
+ - "3.10"
17
+ - "3.11"
18
+ - "3.12"
19
+ - "3.13"
20
+ - "3.14"
15
21
  steps:
16
22
  - uses: actions/checkout@v3
17
23
  - name: Install uv
@@ -42,7 +48,7 @@ jobs:
42
48
  - runner: windows-latest
43
49
  - runner: ubuntu-latest
44
50
  - runner: ubuntu-24.04-arm # aarch64
45
- - runner: macos-13 # x86_64
51
+ - runner: macos-15-intel # x86_64
46
52
  - runner: macos-14 # aarch64
47
53
  python-version: ["3.9"]
48
54
  steps:
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.4 2025-10-24
4
+
5
+ Implement N-dimensional nearest-neighbor interpolation on regular and rectilinear grids.
6
+
7
+ ### Added
8
+
9
+ * Rust
10
+ * Add `nearest` module with regular- and rectilinear- grid methods in up to 6 dimensions
11
+ * Reduce code duplication for fixed-dim array indexing
12
+ * Update pyo3 and numpy rust deps
13
+ * Python
14
+ * Add bindings, tests, benchmarks, and quality-of-fit plots for `NearestRegular` and `NearestRectilinear`
15
+ * Update PGO profile data to include new functions
16
+
17
+ ## 0.6.3 2025-10-22
18
+
19
+ Unpin max supported python version due to use of stable ABI3,
20
+ along with a host of other improvements to packaging and actions workflows.
21
+
22
+ ### New Contributors
23
+
24
+ * [Clément Robert](https://github.com/neutrinoceros) contributed PRs 30,32,33,36 making up all the substantial changes in this release. Thanks, Clément!
25
+
26
+ ### Changed
27
+
28
+ * Python
29
+ * Unpin max python version
30
+ * Roll forward pydantic version for python 3.14 compatibility
31
+ * Update package metadata
32
+ * Add python 3.14 to test matrix
33
+ * Workflows
34
+ * Reconfigure from single-contributor to commons-project by segmenting release workflows to be dispatched manually only
35
+ * Update python release workflow to depend on test-python instead of release-rust to support separate releases
36
+
3
37
  ## 0.6.2 2025-10-20
4
38
 
5
39
  Add optional use of fused multiply-add, enabled for python distributions.
@@ -221,7 +221,7 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
221
221
 
222
222
  [[package]]
223
223
  name = "interpn"
224
- version = "0.6.2"
224
+ version = "0.6.4"
225
225
  dependencies = [
226
226
  "criterion",
227
227
  "crunchy",
@@ -355,9 +355,9 @@ dependencies = [
355
355
 
356
356
  [[package]]
357
357
  name = "numpy"
358
- version = "0.26.0"
358
+ version = "0.27.0"
359
359
  source = "registry+https://github.com/rust-lang/crates.io-index"
360
- checksum = "9b2dba356160b54f5371b550575b78130a54718b4c6e46b3f33a6da74a27e78b"
360
+ checksum = "0fa24ffc88cf9d43f7269d6b6a0d0a00010924a8cc90604a21ef9c433b66998d"
361
361
  dependencies = [
362
362
  "libc",
363
363
  "ndarray",
@@ -444,9 +444,9 @@ dependencies = [
444
444
 
445
445
  [[package]]
446
446
  name = "pyo3"
447
- version = "0.26.0"
447
+ version = "0.27.1"
448
448
  source = "registry+https://github.com/rust-lang/crates.io-index"
449
- checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383"
449
+ checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf"
450
450
  dependencies = [
451
451
  "indoc",
452
452
  "libc",
@@ -461,9 +461,9 @@ dependencies = [
461
461
 
462
462
  [[package]]
463
463
  name = "pyo3-build-config"
464
- version = "0.26.0"
464
+ version = "0.27.1"
465
465
  source = "registry+https://github.com/rust-lang/crates.io-index"
466
- checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f"
466
+ checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb"
467
467
  dependencies = [
468
468
  "python3-dll-a",
469
469
  "target-lexicon",
@@ -471,9 +471,9 @@ dependencies = [
471
471
 
472
472
  [[package]]
473
473
  name = "pyo3-ffi"
474
- version = "0.26.0"
474
+ version = "0.27.1"
475
475
  source = "registry+https://github.com/rust-lang/crates.io-index"
476
- checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105"
476
+ checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be"
477
477
  dependencies = [
478
478
  "libc",
479
479
  "pyo3-build-config",
@@ -481,9 +481,9 @@ dependencies = [
481
481
 
482
482
  [[package]]
483
483
  name = "pyo3-macros"
484
- version = "0.26.0"
484
+ version = "0.27.1"
485
485
  source = "registry+https://github.com/rust-lang/crates.io-index"
486
- checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded"
486
+ checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71"
487
487
  dependencies = [
488
488
  "proc-macro2",
489
489
  "pyo3-macros-backend",
@@ -493,9 +493,9 @@ dependencies = [
493
493
 
494
494
  [[package]]
495
495
  name = "pyo3-macros-backend"
496
- version = "0.26.0"
496
+ version = "0.27.1"
497
497
  source = "registry+https://github.com/rust-lang/crates.io-index"
498
- checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf"
498
+ checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b"
499
499
  dependencies = [
500
500
  "heck",
501
501
  "proc-macro2",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "interpn"
3
- version = "0.6.2"
3
+ version = "0.6.4"
4
4
  edition = "2024"
5
5
  authors = ["James Logan <jlogan03@gmail.com>"]
6
6
  license = "MIT OR Apache-2.0"
@@ -20,8 +20,8 @@ num-traits = { version = "0.2.19", default-features = false, features = ["libm"]
20
20
  crunchy = { version = "0.2.4", default-features = false, features = ["limit_256"] }
21
21
 
22
22
  # Python bindings
23
- pyo3 = { version = "0.26.0", features = ["extension-module", "abi3-py39", "generate-import-lib"], optional = true }
24
- numpy = { version = "0.26.0", optional = true }
23
+ pyo3 = { version = "0.27.1", features = ["extension-module", "abi3-py39", "generate-import-lib"], optional = true }
24
+ numpy = { version = "0.27.0", optional = true }
25
25
 
26
26
  # Test-only utils
27
27
  itertools = { version = "0.14.0", optional = true }
interpn-0.6.4/PKG-INFO ADDED
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.4
2
+ Name: interpn
3
+ Version: 0.6.4
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Requires-Dist: numpy>=2
8
+ Requires-Dist: pydantic>=2.12
9
+ Requires-Dist: pytest>=8.4.2 ; extra == 'test'
10
+ Requires-Dist: pytest-cov>=7.0.0 ; extra == 'test'
11
+ Requires-Dist: ruff>=0.13.3 ; extra == 'test'
12
+ Requires-Dist: pyright==1.1.337 ; extra == 'test'
13
+ Requires-Dist: mktestdocs>=0.2.1 ; extra == 'test'
14
+ Requires-Dist: scipy>=1.11.4 ; extra == 'test'
15
+ Requires-Dist: matplotlib>=3.8 ; extra == 'test'
16
+ Requires-Dist: scipy>=1.11.4 ; extra == 'bench'
17
+ Requires-Dist: matplotlib>=3.8 ; extra == 'bench'
18
+ Requires-Dist: memory-profiler>=0.61.0 ; extra == 'bench'
19
+ Requires-Dist: mkdocs>=1.5.3 ; extra == 'doc'
20
+ Requires-Dist: mkdocstrings-python>=1.7.5 ; extra == 'doc'
21
+ Requires-Dist: mkdocs-material>=9.4.10 ; extra == 'doc'
22
+ Provides-Extra: test
23
+ Provides-Extra: bench
24
+ Provides-Extra: doc
25
+ License-File: LICENSE-MIT
26
+ License-File: LICENSE-APACHE
27
+ Summary: N-dimensional interpolation/extrapolation methods
28
+ Home-Page: https://github.com/jlogan03/interpn/
29
+ Author-email: James Logan <jlogan03@gmail.com>
30
+ License-Expression: MIT OR Apache-2.0
31
+ Requires-Python: >=3.9
32
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
33
+ Project-URL: repository, https://github.com/jlogan03/interpn
34
+ Project-URL: documentation, https://interpn.readthedocs.io/
35
+
36
+ # InterpN
37
+
38
+ [Repo](https://github.com/jlogan03/interpn) |
39
+ [Python Docs](https://interpnpy.readthedocs.io/en/latest/) |
40
+ [Rust Docs](https://docs.rs/interpn/latest/interpn/)
41
+
42
+ N-dimensional interpolation/extrapolation methods, no-std and no-alloc compatible,
43
+ prioritizing correctness, performance, and compatiblity with memory-constrained environments.
44
+
45
+ Available as a rust crate and python library.
46
+
47
+ These methods perform zero allocation when evaluated (except, optionally, for the output).
48
+ Because of this, they have minimal per-call overhead, and are particularly
49
+ effective when examining small numbers of observation points. See the
50
+ [performance](https://interpnpy.readthedocs.io/en/latest/perf/) page for detailed benchmarks.
51
+
52
+ ## Features
53
+
54
+ | Feature →<br>↓ Interpolant Method | Regular<br>Grid | Rectilinear<br>Grid | Json<br>Serialization |
55
+ |-----------------------------------|-----------------|---------------------|-----------------------|
56
+ | Linear | ✅ | ✅ | ✅ |
57
+ | Cubic | ✅ | ✅ | ✅ |
58
+
59
+ The methods provided here, while more limited in scope than scipy's,
60
+
61
+ * are significantly faster under most conditions
62
+ * use almost no RAM (and perform no heap allocations at all)
63
+ * produce significantly improved floating-point error (by several orders of magnitude)
64
+ * are json-serializable using Pydantic
65
+ * can also be used easily in web and embedded applications via the Rust library
66
+ * are permissively licensed
67
+
68
+ ![ND throughput 1000 obs](./docs/throughput_vs_dims_1000_obs.svg)
69
+
70
+ See [here](https://interpnpy.readthedocs.io/en/latest/perf/) for more info about quality-of-fit, throughput, and memory usage.
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ pip install interpn
76
+ ```
77
+
78
+ ## Profile-Guided Optimization
79
+
80
+ To build the extension with profile-guided optimization using pre-built profiles, do `sh ./scripts/pgo_install.sh`.
81
+ You can also generate your own PGO profiles like `sh ./scripts/pgo_profile.sh`.
82
+ after installing these extra compiler dependencies:
83
+
84
+ ```bash
85
+ rustup component add llvm-tools-preview
86
+ ```
87
+
88
+ ## Rust Examples
89
+
90
+ ### Regular Grid
91
+ ```rust
92
+ use interpn::{multilinear, multicubic};
93
+
94
+ // Define a grid
95
+ let x = [1.0_f64, 2.0, 3.0, 4.0];
96
+ let y = [0.0_f64, 1.0, 2.0, 3.0];
97
+
98
+ // Grid input for rectilinear method
99
+ let grids = &[&x[..], &y[..]];
100
+
101
+ // Grid input for regular grid method
102
+ let dims = [x.len(), y.len()];
103
+ let starts = [x[0], y[0]];
104
+ let steps = [x[1] - x[0], y[1] - y[0]];
105
+
106
+ // Values at grid points
107
+ let z = [2.0; 16];
108
+
109
+ // Observation points to interpolate/extrapolate
110
+ let xobs = [0.0_f64, 5.0];
111
+ let yobs = [-1.0, 3.0];
112
+ let obs = [&xobs[..], &yobs[..]];
113
+
114
+ // Storage for output
115
+ let mut out = [0.0; 2];
116
+
117
+ // Do interpolation
118
+ multilinear::regular::interpn(&dims, &starts, &steps, &z, &obs, &mut out);
119
+ multicubic::regular::interpn(&dims, &starts, &steps, &z, false, &obs, &mut out);
120
+ ```
121
+
122
+ ### Rectilinear Grid
123
+ ```rust
124
+ use interpn::{multilinear, multicubic};
125
+
126
+ // Define a grid
127
+ let x = [1.0_f64, 2.0, 3.0, 4.0];
128
+ let y = [0.0_f64, 1.0, 2.0, 3.0];
129
+
130
+ // Grid input for rectilinear method
131
+ let grids = &[&x[..], &y[..]];
132
+
133
+ // Values at grid points
134
+ let z = [2.0; 16];
135
+
136
+ // Points to interpolate/extrapolate
137
+ let xobs = [0.0_f64, 5.0];
138
+ let yobs = [-1.0, 3.0];
139
+ let obs = [&xobs[..], &yobs[..]];
140
+
141
+ // Storage for output
142
+ let mut out = [0.0; 2];
143
+
144
+ // Do interpolation
145
+ multilinear::rectilinear::interpn(grids, &z, &obs, &mut out).unwrap();
146
+ multicubic::rectilinear::interpn(grids, &z, false, &obs, &mut out).unwrap();
147
+ ```
148
+
149
+ ## Python Examples
150
+
151
+ ### Available Methods
152
+
153
+ ```python
154
+ import interpn
155
+ import numpy as np
156
+
157
+ # Build grid
158
+ x = np.linspace(0.0, 10.0, 5)
159
+ y = np.linspace(20.0, 30.0, 4)
160
+ grids = [x, y]
161
+
162
+ xgrid, ygrid = np.meshgrid(x, y, indexing="ij")
163
+ zgrid = (xgrid + 2.0 * ygrid) # Values at grid points
164
+
165
+ # Grid inputs for true regular grid
166
+ dims = [x.size, y.size]
167
+ starts = np.array([x[0], y[0]])
168
+ steps = np.array([x[1] - x[0], y[1] - y[0]])
169
+
170
+ # Initialize different interpolators
171
+ # Call like `linear_regular.eval([xs, ys])`
172
+ linear_regular = interpn.MultilinearRegular.new(dims, starts, steps, zgrid)
173
+ cubic_regular = interpn.MulticubicRegular.new(dims, starts, steps, zgrid)
174
+ linear_rectilinear = interpn.MultilinearRectilinear.new(grids, zgrid)
175
+ cubic_rectilinear = interpn.MulticubicRectilinear.new(grids, zgrid)
176
+ ```
177
+
178
+ ### Multilinear Interpolation
179
+
180
+ ```python
181
+ import interpn
182
+ import numpy as np
183
+
184
+ # Build grid
185
+ x = np.linspace(0.0, 10.0, 5)
186
+ y = np.linspace(20.0, 30.0, 4)
187
+
188
+ xgrid, ygrid = np.meshgrid(x, y, indexing="ij")
189
+ zgrid = (xgrid + 2.0 * ygrid) # Values at grid points
190
+
191
+ # Grid inputs for true regular grid
192
+ dims = [x.size, y.size]
193
+ starts = np.array([x[0], y[0]])
194
+ steps = np.array([x[1] - x[0], y[1] - y[0]])
195
+
196
+ # Observation points pointed back at the grid
197
+ obs = [xgrid.flatten(), ygrid.flatten()]
198
+
199
+ # Initialize
200
+ interpolator = interpn.MultilinearRegular.new(dims, starts, steps, zgrid.flatten())
201
+
202
+ # Interpolate
203
+ out = interpolator.eval(obs)
204
+
205
+ # Check result
206
+ assert np.allclose(out, zgrid.flatten(), rtol=1e-13)
207
+
208
+ # Serialize and deserialize
209
+ roundtrip_interpolator = interpn.MultilinearRegular.model_validate_json(
210
+ interpolator.model_dump_json()
211
+ )
212
+ out2 = roundtrip_interpolator.eval(obs)
213
+
214
+ # Check result from roundtrip serialized/deserialized interpolator
215
+ assert np.all(out == out2)
216
+ ```
217
+
218
+
219
+ # License
220
+
221
+ Licensed under either of
222
+
223
+ - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
224
+ - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
225
+
226
+ at your option.
227
+
@@ -3,8 +3,8 @@
3
3
  use criterion::*;
4
4
  use gridgen::*;
5
5
  use interpn::{
6
- Linear1D, LinearHoldLast1D, MultilinearRegular, RectilinearGrid1D, RegularGrid1D, multicubic,
7
- multilinear,
6
+ Linear1D, LinearHoldLast1D, MultilinearRegular, NearestRectilinear, NearestRegular,
7
+ RectilinearGrid1D, RegularGrid1D, multicubic, multilinear, nearest,
8
8
  one_dim::{
9
9
  Interp1D,
10
10
  hold::{Left1D, Nearest1D},
@@ -135,6 +135,70 @@ macro_rules! bench_interp_specific {
135
135
  },
136
136
  );
137
137
 
138
+ $group.bench_with_input(
139
+ BenchmarkId::new(
140
+ format!(
141
+ "Nearest Regular {}x{}D, {}",
142
+ $gridsize, $ndims, scan_or_shuffle
143
+ ),
144
+ $size,
145
+ ),
146
+ $size,
147
+ |b, &size| {
148
+ let (grids, z) = gen_grid($ndims, $gridsize, 0.0);
149
+ let m: usize = ((size as f64).powf(1.0 / ($ndims as f64)) + 2.0) as usize;
150
+ let gridobs_t = match $kind {
151
+ Kind::Interp => gen_interp_obs_grid(&grids, m, true),
152
+ Kind::Extrap => gen_extrap_obs_grid(&grids, m, true),
153
+ };
154
+ let obs: Vec<&[f64]> = gridobs_t.iter().map(|x| &x[..size]).collect();
155
+ let mut out = vec![0.0; size];
156
+
157
+ let dims = [$gridsize; $ndims];
158
+ let mut starts = [0.0; $ndims];
159
+ let mut steps = [0.0; $ndims];
160
+ (0..$ndims).for_each(|i| starts[i] = grids[i][0]);
161
+ (0..$ndims).for_each(|i| steps[i] = grids[i][1] - grids[i][0]);
162
+
163
+ b.iter(|| {
164
+ black_box({
165
+ nearest::regular::interpn(&dims, &starts, &steps, &z, &obs[..], &mut out)
166
+ .unwrap()
167
+ })
168
+ });
169
+ },
170
+ );
171
+
172
+ $group.bench_with_input(
173
+ BenchmarkId::new(
174
+ format!(
175
+ "Nearest Rectilinear {}x{}D, {}",
176
+ $gridsize, $ndims, scan_or_shuffle
177
+ ),
178
+ $size,
179
+ ),
180
+ $size,
181
+ |b, &size| {
182
+ let (grids, z) = gen_grid($ndims, $gridsize, 1e-3);
183
+
184
+ let m: usize = ((size as f64).powf(1.0 / ($ndims as f64)) + 2.0) as usize;
185
+ let gridobs_t = match $kind {
186
+ Kind::Interp => gen_interp_obs_grid(&grids, m, true),
187
+ Kind::Extrap => gen_extrap_obs_grid(&grids, m, true),
188
+ };
189
+ let obs: Vec<&[f64]> = gridobs_t.iter().map(|x| &x[..size]).collect();
190
+ let mut out = vec![0.0; size];
191
+
192
+ let gridslice: Vec<&[f64]> = grids.iter().map(|x| &x[..]).collect();
193
+
194
+ b.iter(|| {
195
+ black_box(
196
+ nearest::rectilinear::interpn(&gridslice, &z, &obs, &mut out).unwrap(),
197
+ )
198
+ });
199
+ },
200
+ );
201
+
138
202
  $group.bench_with_input(
139
203
  BenchmarkId::new(
140
204
  format!(
@@ -426,41 +490,8 @@ fn bench_interp(c: &mut Criterion) {
426
490
  }
427
491
  }
428
492
 
429
- fn bench_extrap(c: &mut Criterion) {
430
- //
431
- // Shuffled (un-ordered observation points)
432
- //
433
- for gridsize in [10] {
434
- let mut group = c.benchmark_group(format!("Extrap_1D_Shuffled_{gridsize}-grid"));
435
- for size in [1, 100, 1_000_000].iter() {
436
- group.throughput(Throughput::Elements(*size as u64));
437
- bench_interp_specific!(group, 1, gridsize, size, Kind::Extrap);
438
- }
439
- group.finish();
440
- }
441
-
442
- for gridsize in [10] {
443
- let mut group = c.benchmark_group(format!("Extrap_2D_Shuffled_{gridsize}-grid"));
444
- for size in [1, 100, 1_000_000].iter() {
445
- group.throughput(Throughput::Elements(*size as u64));
446
- bench_interp_specific!(group, 2, gridsize, size, Kind::Extrap);
447
- }
448
- group.finish();
449
- }
450
-
451
- for gridsize in [10] {
452
- let mut group = c.benchmark_group(format!("Extrap_3D_Shuffled_{gridsize}-grid"));
453
- for size in [1, 100, 1_000_000].iter() {
454
- group.throughput(Throughput::Elements(*size as u64));
455
- bench_interp_specific!(group, 3, gridsize, size, Kind::Extrap);
456
- }
457
- group.finish();
458
- }
459
- }
460
-
461
493
  criterion_group!(benches_interp, bench_interp);
462
- criterion_group!(benches_extrap, bench_extrap);
463
- criterion_main!(benches_interp, benches_extrap,);
494
+ criterion_main!(benches_interp);
464
495
 
465
496
  mod randn {
466
497
  use rand::Rng;