interpn 0.8.2__tar.gz → 0.9.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 (132) hide show
  1. {interpn-0.8.2 → interpn-0.9.0}/.readthedocs.yml +1 -0
  2. {interpn-0.8.2 → interpn-0.9.0}/CHANGELOG.md +15 -0
  3. {interpn-0.8.2 → interpn-0.9.0}/Cargo.lock +15 -30
  4. {interpn-0.8.2 → interpn-0.9.0}/Cargo.toml +6 -5
  5. {interpn-0.8.2 → interpn-0.9.0}/PKG-INFO +7 -10
  6. {interpn-0.8.2 → interpn-0.9.0}/README.md +6 -9
  7. {interpn-0.8.2 → interpn-0.9.0}/benches/bench_cpu.py +64 -88
  8. {interpn-0.8.2 → interpn-0.9.0}/docs/1d_quality_of_fit_Rectilinear.html +1 -1
  9. {interpn-0.8.2 → interpn-0.9.0}/docs/1d_quality_of_fit_Rectilinear.svg +1 -1
  10. {interpn-0.8.2 → interpn-0.9.0}/docs/1d_quality_of_fit_Regular.html +1 -1
  11. {interpn-0.8.2 → interpn-0.9.0}/docs/1d_quality_of_fit_Regular.svg +1 -1
  12. {interpn-0.8.2 → interpn-0.9.0}/docs/2d_quality_of_fit_Rectilinear.html +1 -1
  13. {interpn-0.8.2 → interpn-0.9.0}/docs/2d_quality_of_fit_Rectilinear.svg +1 -1
  14. {interpn-0.8.2 → interpn-0.9.0}/docs/2d_quality_of_fit_Regular.html +1 -1
  15. {interpn-0.8.2 → interpn-0.9.0}/docs/2d_quality_of_fit_Regular.svg +1 -1
  16. interpn-0.9.0/docs/3d_throughput_vs_nobs_cubic.html +2 -0
  17. interpn-0.9.0/docs/3d_throughput_vs_nobs_cubic.svg +1 -0
  18. interpn-0.9.0/docs/3d_throughput_vs_nobs_linear.html +2 -0
  19. interpn-0.9.0/docs/3d_throughput_vs_nobs_linear.svg +1 -0
  20. interpn-0.9.0/docs/3d_throughput_vs_nobs_prealloc_cubic.html +2 -0
  21. interpn-0.9.0/docs/3d_throughput_vs_nobs_prealloc_cubic.svg +1 -0
  22. interpn-0.8.2/docs/speedup_vs_dims_1_obs_cubic.html → interpn-0.9.0/docs/3d_throughput_vs_nobs_prealloc_linear.html +1 -1
  23. interpn-0.9.0/docs/3d_throughput_vs_nobs_prealloc_linear.svg +1 -0
  24. interpn-0.8.2/docs/throughput_vs_dims_1_obs.html → interpn-0.9.0/docs/4d_throughput_vs_nobs_cubic.html +1 -1
  25. interpn-0.9.0/docs/4d_throughput_vs_nobs_cubic.svg +1 -0
  26. interpn-0.9.0/docs/4d_throughput_vs_nobs_linear.html +2 -0
  27. interpn-0.9.0/docs/4d_throughput_vs_nobs_linear.svg +1 -0
  28. interpn-0.8.2/docs/speedup_vs_dims_1_obs_linear.html → interpn-0.9.0/docs/4d_throughput_vs_nobs_prealloc_cubic.html +1 -1
  29. interpn-0.9.0/docs/4d_throughput_vs_nobs_prealloc_cubic.svg +1 -0
  30. interpn-0.9.0/docs/4d_throughput_vs_nobs_prealloc_linear.html +2 -0
  31. interpn-0.9.0/docs/4d_throughput_vs_nobs_prealloc_linear.svg +1 -0
  32. {interpn-0.8.2 → interpn-0.9.0}/docs/index.md +7 -1
  33. {interpn-0.8.2 → interpn-0.9.0}/docs/nearest_quality_of_fit.html +1 -1
  34. {interpn-0.8.2 → interpn-0.9.0}/docs/nearest_quality_of_fit.svg +1 -1
  35. {interpn-0.8.2 → interpn-0.9.0}/docs/perf.md +42 -20
  36. interpn-0.9.0/docs/speedup_vs_dims_1000_obs_cubic.html +2 -0
  37. interpn-0.9.0/docs/speedup_vs_dims_1000_obs_cubic.svg +1 -0
  38. {interpn-0.8.2 → interpn-0.9.0}/docs/speedup_vs_dims_1000_obs_linear.html +1 -1
  39. interpn-0.9.0/docs/speedup_vs_dims_1000_obs_linear.svg +1 -0
  40. interpn-0.9.0/docs/speedup_vs_dims_1_obs_cubic.html +2 -0
  41. interpn-0.9.0/docs/speedup_vs_dims_1_obs_cubic.svg +1 -0
  42. interpn-0.9.0/docs/speedup_vs_dims_1_obs_linear.html +2 -0
  43. interpn-0.9.0/docs/speedup_vs_dims_1_obs_linear.svg +1 -0
  44. interpn-0.9.0/docs/speedup_vs_dims_1_obs_linear_inverted.svg +6 -0
  45. interpn-0.9.0/docs/stylesheets/extra.css +7 -0
  46. interpn-0.8.2/docs/speedup_vs_dims_1000_obs_cubic.html → interpn-0.9.0/docs/throughput_vs_dims_1000_obs.html +1 -1
  47. interpn-0.9.0/docs/throughput_vs_dims_1000_obs.svg +1 -0
  48. interpn-0.9.0/docs/throughput_vs_dims_1_obs.html +2 -0
  49. interpn-0.9.0/docs/throughput_vs_dims_1_obs.svg +1 -0
  50. {interpn-0.8.2 → interpn-0.9.0}/examples/cubic_comparison.py +10 -10
  51. {interpn-0.8.2 → interpn-0.9.0}/examples/nearest_comparison.py +5 -5
  52. interpn-0.9.0/mkdocs.yml +45 -0
  53. {interpn-0.8.2 → interpn-0.9.0}/pyproject.toml +2 -2
  54. interpn-0.9.0/src/interpn/py.typed +0 -0
  55. {interpn-0.8.2 → interpn-0.9.0}/src/multicubic/rectilinear.rs +52 -20
  56. {interpn-0.8.2 → interpn-0.9.0}/src/multicubic/regular.rs +57 -22
  57. {interpn-0.8.2 → interpn-0.9.0}/uv.lock +1 -1
  58. interpn-0.8.2/docs/3d_throughput_vs_nobs.html +0 -2
  59. interpn-0.8.2/docs/3d_throughput_vs_nobs.svg +0 -1
  60. interpn-0.8.2/docs/3d_throughput_vs_nobs_prealloc.html +0 -2
  61. interpn-0.8.2/docs/3d_throughput_vs_nobs_prealloc.svg +0 -1
  62. interpn-0.8.2/docs/4d_throughput_vs_nobs.html +0 -2
  63. interpn-0.8.2/docs/4d_throughput_vs_nobs.svg +0 -1
  64. interpn-0.8.2/docs/4d_throughput_vs_nobs_prealloc.html +0 -2
  65. interpn-0.8.2/docs/4d_throughput_vs_nobs_prealloc.svg +0 -1
  66. interpn-0.8.2/docs/requirements.txt +0 -1
  67. interpn-0.8.2/docs/speedup_vs_dims_1000_obs_cubic.svg +0 -1
  68. interpn-0.8.2/docs/speedup_vs_dims_1000_obs_linear.svg +0 -1
  69. interpn-0.8.2/docs/speedup_vs_dims_1_obs_cubic.svg +0 -1
  70. interpn-0.8.2/docs/speedup_vs_dims_1_obs_linear.svg +0 -1
  71. interpn-0.8.2/docs/throughput_vs_dims_1000_obs.html +0 -2
  72. interpn-0.8.2/docs/throughput_vs_dims_1000_obs.svg +0 -1
  73. interpn-0.8.2/docs/throughput_vs_dims_1_obs.svg +0 -1
  74. interpn-0.8.2/mkdocs.yml +0 -38
  75. {interpn-0.8.2 → interpn-0.9.0}/.cargo/config.toml +0 -0
  76. {interpn-0.8.2 → interpn-0.9.0}/.github/workflows/release-python.yml +0 -0
  77. {interpn-0.8.2 → interpn-0.9.0}/.github/workflows/release-rust.yml +0 -0
  78. {interpn-0.8.2 → interpn-0.9.0}/.github/workflows/test-python.yml +0 -0
  79. {interpn-0.8.2 → interpn-0.9.0}/.github/workflows/test-rust.yml +0 -0
  80. {interpn-0.8.2 → interpn-0.9.0}/.gitignore +0 -0
  81. {interpn-0.8.2 → interpn-0.9.0}/LICENSE-APACHE +0 -0
  82. {interpn-0.8.2 → interpn-0.9.0}/LICENSE-MIT +0 -0
  83. {interpn-0.8.2 → interpn-0.9.0}/benches/bench.rs +0 -0
  84. {interpn-0.8.2 → interpn-0.9.0}/benches/bench_mem.py +0 -0
  85. {interpn-0.8.2 → interpn-0.9.0}/docs/API_Docs.md +0 -0
  86. {interpn-0.8.2 → interpn-0.9.0}/docs/ram_vs_dims.svg +0 -0
  87. /interpn-0.8.2/src/interpn/py.typed → /interpn-0.9.0/docs/requirements.txt +0 -0
  88. {interpn-0.8.2 → interpn-0.9.0}/scripts/distr_pgo.sh +0 -0
  89. {interpn-0.8.2 → interpn-0.9.0}/scripts/distr_pgo_install.sh +0 -0
  90. {interpn-0.8.2 → interpn-0.9.0}/scripts/distr_pgo_profile.sh +0 -0
  91. {interpn-0.8.2 → interpn-0.9.0}/scripts/install_llvm.sh +0 -0
  92. {interpn-0.8.2 → interpn-0.9.0}/scripts/native_pgo.sh +0 -0
  93. {interpn-0.8.2 → interpn-0.9.0}/scripts/native_pgo_install.sh +0 -0
  94. {interpn-0.8.2 → interpn-0.9.0}/scripts/native_pgo_profile.sh +0 -0
  95. {interpn-0.8.2 → interpn-0.9.0}/scripts/profile_workload.py +0 -0
  96. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/__init__.py +0 -0
  97. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/multicubic_rectilinear.py +0 -0
  98. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/multicubic_regular.py +0 -0
  99. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/multilinear_rectilinear.py +0 -0
  100. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/multilinear_regular.py +0 -0
  101. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/nearest_rectilinear.py +0 -0
  102. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/nearest_regular.py +0 -0
  103. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/raw.py +0 -0
  104. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/raw.pyi +0 -0
  105. {interpn-0.8.2 → interpn-0.9.0}/src/interpn/serialization.py +0 -0
  106. {interpn-0.8.2 → interpn-0.9.0}/src/lib.rs +0 -0
  107. {interpn-0.8.2 → interpn-0.9.0}/src/multicubic/mod.rs +0 -0
  108. {interpn-0.8.2 → interpn-0.9.0}/src/multicubic/rectilinear_recursive.rs +0 -0
  109. {interpn-0.8.2 → interpn-0.9.0}/src/multicubic/regular_recursive.rs +0 -0
  110. {interpn-0.8.2 → interpn-0.9.0}/src/multilinear/mod.rs +0 -0
  111. {interpn-0.8.2 → interpn-0.9.0}/src/multilinear/rectilinear.rs +0 -0
  112. {interpn-0.8.2 → interpn-0.9.0}/src/multilinear/rectilinear_recursive.rs +0 -0
  113. {interpn-0.8.2 → interpn-0.9.0}/src/multilinear/regular.rs +0 -0
  114. {interpn-0.8.2 → interpn-0.9.0}/src/multilinear/regular_recursive.rs +0 -0
  115. {interpn-0.8.2 → interpn-0.9.0}/src/nearest/mod.rs +0 -0
  116. {interpn-0.8.2 → interpn-0.9.0}/src/nearest/rectilinear.rs +0 -0
  117. {interpn-0.8.2 → interpn-0.9.0}/src/nearest/regular.rs +0 -0
  118. {interpn-0.8.2 → interpn-0.9.0}/src/one_dim/hold.rs +0 -0
  119. {interpn-0.8.2 → interpn-0.9.0}/src/one_dim/linear.rs +0 -0
  120. {interpn-0.8.2 → interpn-0.9.0}/src/one_dim/mod.rs +0 -0
  121. {interpn-0.8.2 → interpn-0.9.0}/src/python.rs +0 -0
  122. {interpn-0.8.2 → interpn-0.9.0}/src/testing.rs +0 -0
  123. {interpn-0.8.2 → interpn-0.9.0}/src/utils.rs +0 -0
  124. {interpn-0.8.2 → interpn-0.9.0}/test/test_docs.py +0 -0
  125. {interpn-0.8.2 → interpn-0.9.0}/test/test_examples.py +0 -0
  126. {interpn-0.8.2 → interpn-0.9.0}/test/test_interpn.py +0 -0
  127. {interpn-0.8.2 → interpn-0.9.0}/test/test_multicubic_rectilinear.py +0 -0
  128. {interpn-0.8.2 → interpn-0.9.0}/test/test_multicubic_regular.py +0 -0
  129. {interpn-0.8.2 → interpn-0.9.0}/test/test_multilinear_rectilinear.py +0 -0
  130. {interpn-0.8.2 → interpn-0.9.0}/test/test_multilinear_regular.py +0 -0
  131. {interpn-0.8.2 → interpn-0.9.0}/test/test_nearest_rectilinear.py +0 -0
  132. {interpn-0.8.2 → interpn-0.9.0}/test/test_nearest_regular.py +0 -0
@@ -14,6 +14,7 @@ build:
14
14
  pre_build:
15
15
  # Rust 1.90 required but not available yet
16
16
  - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.90.0
17
+ - pip install -e .[pydantic] --group doc
17
18
 
18
19
  mkdocs:
19
20
  configuration: mkdocs.yml
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0 2025-12-27
4
+
5
+ ### Added
6
+
7
+ * Rust
8
+ * Add `deep-unroll` feature that sets crunchy unroll depth to 256 and enables 4D unrolled cubic interpolation
9
+ * This improves compile times in typical use-cases
10
+
11
+ ### Changed
12
+
13
+ * Rust
14
+ * Gate 4D unrolled cubic interpolation behind `deep-unroll` feature
15
+ * Enable `deep-unroll` feature for Python builds
16
+ * Update pyo3 deps
17
+
3
18
  ## 0.8.2 2025-11-12
4
19
 
5
20
  ### Changed
@@ -221,12 +221,12 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
221
221
 
222
222
  [[package]]
223
223
  name = "interpn"
224
- version = "0.8.2"
224
+ version = "0.9.0"
225
225
  dependencies = [
226
226
  "criterion",
227
227
  "crunchy",
228
228
  "itertools 0.14.0",
229
- "ndarray 0.17.1",
229
+ "ndarray",
230
230
  "num-traits",
231
231
  "numpy",
232
232
  "pyo3",
@@ -310,21 +310,6 @@ dependencies = [
310
310
  "autocfg",
311
311
  ]
312
312
 
313
- [[package]]
314
- name = "ndarray"
315
- version = "0.16.1"
316
- source = "registry+https://github.com/rust-lang/crates.io-index"
317
- checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
318
- dependencies = [
319
- "matrixmultiply",
320
- "num-complex",
321
- "num-integer",
322
- "num-traits",
323
- "portable-atomic",
324
- "portable-atomic-util",
325
- "rawpointer",
326
- ]
327
-
328
313
  [[package]]
329
314
  name = "ndarray"
330
315
  version = "0.17.1"
@@ -370,12 +355,12 @@ dependencies = [
370
355
 
371
356
  [[package]]
372
357
  name = "numpy"
373
- version = "0.27.0"
358
+ version = "0.27.1"
374
359
  source = "registry+https://github.com/rust-lang/crates.io-index"
375
- checksum = "0fa24ffc88cf9d43f7269d6b6a0d0a00010924a8cc90604a21ef9c433b66998d"
360
+ checksum = "7aac2e6a6e4468ffa092ad43c39b81c79196c2bb773b8db4085f695efe3bba17"
376
361
  dependencies = [
377
362
  "libc",
378
- "ndarray 0.16.1",
363
+ "ndarray",
379
364
  "num-complex",
380
365
  "num-integer",
381
366
  "num-traits",
@@ -459,9 +444,9 @@ dependencies = [
459
444
 
460
445
  [[package]]
461
446
  name = "pyo3"
462
- version = "0.27.1"
447
+ version = "0.27.2"
463
448
  source = "registry+https://github.com/rust-lang/crates.io-index"
464
- checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf"
449
+ checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
465
450
  dependencies = [
466
451
  "indoc",
467
452
  "libc",
@@ -476,9 +461,9 @@ dependencies = [
476
461
 
477
462
  [[package]]
478
463
  name = "pyo3-build-config"
479
- version = "0.27.1"
464
+ version = "0.27.2"
480
465
  source = "registry+https://github.com/rust-lang/crates.io-index"
481
- checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb"
466
+ checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
482
467
  dependencies = [
483
468
  "python3-dll-a",
484
469
  "target-lexicon",
@@ -486,9 +471,9 @@ dependencies = [
486
471
 
487
472
  [[package]]
488
473
  name = "pyo3-ffi"
489
- version = "0.27.1"
474
+ version = "0.27.2"
490
475
  source = "registry+https://github.com/rust-lang/crates.io-index"
491
- checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be"
476
+ checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
492
477
  dependencies = [
493
478
  "libc",
494
479
  "pyo3-build-config",
@@ -496,9 +481,9 @@ dependencies = [
496
481
 
497
482
  [[package]]
498
483
  name = "pyo3-macros"
499
- version = "0.27.1"
484
+ version = "0.27.2"
500
485
  source = "registry+https://github.com/rust-lang/crates.io-index"
501
- checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71"
486
+ checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
502
487
  dependencies = [
503
488
  "proc-macro2",
504
489
  "pyo3-macros-backend",
@@ -508,9 +493,9 @@ dependencies = [
508
493
 
509
494
  [[package]]
510
495
  name = "pyo3-macros-backend"
511
- version = "0.27.1"
496
+ version = "0.27.2"
512
497
  source = "registry+https://github.com/rust-lang/crates.io-index"
513
- checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b"
498
+ checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
514
499
  dependencies = [
515
500
  "heck",
516
501
  "proc-macro2",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "interpn"
3
- version = "0.8.2"
3
+ version = "0.9.0"
4
4
  edition = "2024"
5
5
  authors = ["James Logan <jlogan03@gmail.com>"]
6
6
  license = "MIT OR Apache-2.0"
@@ -17,11 +17,11 @@ crate-type = ["cdylib", "rlib"]
17
17
  [dependencies]
18
18
  # Rust lib deps
19
19
  num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
20
- crunchy = { version = "0.2.4", default-features = false, features = ["limit_256"] }
20
+ crunchy = { version = "0.2.4", default-features = false }
21
21
 
22
22
  # Python bindings
23
- pyo3 = { version = "0.27.1", features = ["extension-module", "abi3-py310", "generate-import-lib"], optional = true }
24
- numpy = { version = "0.27.0", optional = true }
23
+ pyo3 = { version = "0.27.2", features = ["extension-module", "abi3-py310", "generate-import-lib"], optional = true }
24
+ numpy = { version = "0.27.1", optional = true }
25
25
 
26
26
  # Test-only utils
27
27
  itertools = { version = "0.14.0", optional = true }
@@ -32,9 +32,10 @@ criterion = "0.7.0"
32
32
  ndarray = "0.17.1"
33
33
 
34
34
  [features]
35
- default = ["std"]
35
+ default = ["std", "crunchy/limit_64"]
36
36
  python = ["numpy", "pyo3", "std"]
37
37
  std = ["itertools"]
38
+ deep-unroll = ["crunchy/limit_256"]
38
39
  fma = []
39
40
 
40
41
  [profile.release]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: interpn
3
- Version: 0.8.2
3
+ Version: 0.9.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -21,6 +21,7 @@ Project-URL: changelog, https://github.com/jlogan03/interpn/blob/main/CHANGELOG.
21
21
 
22
22
  # InterpN
23
23
 
24
+ [Writeup](https://jlogan.dev/blog/#2025-11-10-interpn-fast-interpolation) |
24
25
  [Repo](https://github.com/jlogan03/interpn) |
25
26
  [Python Docs](https://interpnpy.readthedocs.io/en/latest/) |
26
27
  [Rust Docs](https://docs.rs/interpn/latest/interpn/)
@@ -30,11 +31,6 @@ prioritizing correctness, performance, and compatiblity with memory-constrained
30
31
 
31
32
  Available as a rust crate and python library.
32
33
 
33
- These methods perform zero allocation when evaluated (except, optionally, for the output).
34
- Because of this, they have minimal per-call overhead, and are particularly
35
- effective when examining small numbers of observation points. See the
36
- [performance](https://interpnpy.readthedocs.io/en/latest/perf/) page for detailed benchmarks.
37
-
38
34
  ## Features
39
35
 
40
36
  | Feature →<br>↓ Interpolant Method | Regular<br>Grid | Rectilinear<br>Grid | Json<br>Serialization |
@@ -49,10 +45,12 @@ The methods provided here, while more limited in scope than scipy's,
49
45
  * use almost no RAM (and perform no heap allocations at all)
50
46
  * produce significantly improved floating-point error (by several orders of magnitude)
51
47
  * are json-serializable using Pydantic
52
- * can also be used easily in web and embedded applications via the Rust library
48
+ * can also be used easily in web, embedded and gpu applications via the Rust library
53
49
  * are permissively licensed
54
50
 
55
- ![ND throughput 1000 obs](./docs/throughput_vs_dims_1000_obs.svg)
51
+ <br>
52
+
53
+ <img src="./docs/speedup_vs_dims_1_obs_linear_inverted.svg" alt="">
56
54
 
57
55
  See [here](https://interpnpy.readthedocs.io/en/latest/perf/) for more info about quality-of-fit, throughput, and memory usage.
58
56
 
@@ -64,8 +62,7 @@ pip install interpn
64
62
 
65
63
  ## Profile-Guided Optimization
66
64
 
67
- To build the extension with profile-guided optimization using pre-built profiles, do `sh ./scripts/distr_pgo_install.sh`.
68
- You can also generate your own PGO profiles like `sh ./scripts/distr_pgo_profile.sh`.
65
+ To build the extension with profile-guided optimization, do `sh ./scripts/distr_pgo.sh`
69
66
  after installing this extra compiler dependency:
70
67
 
71
68
  ```bash
@@ -1,5 +1,6 @@
1
1
  # InterpN
2
2
 
3
+ [Writeup](https://jlogan.dev/blog/#2025-11-10-interpn-fast-interpolation) |
3
4
  [Repo](https://github.com/jlogan03/interpn) |
4
5
  [Python Docs](https://interpnpy.readthedocs.io/en/latest/) |
5
6
  [Rust Docs](https://docs.rs/interpn/latest/interpn/)
@@ -9,11 +10,6 @@ prioritizing correctness, performance, and compatiblity with memory-constrained
9
10
 
10
11
  Available as a rust crate and python library.
11
12
 
12
- These methods perform zero allocation when evaluated (except, optionally, for the output).
13
- Because of this, they have minimal per-call overhead, and are particularly
14
- effective when examining small numbers of observation points. See the
15
- [performance](https://interpnpy.readthedocs.io/en/latest/perf/) page for detailed benchmarks.
16
-
17
13
  ## Features
18
14
 
19
15
  | Feature →<br>↓ Interpolant Method | Regular<br>Grid | Rectilinear<br>Grid | Json<br>Serialization |
@@ -28,10 +24,12 @@ The methods provided here, while more limited in scope than scipy's,
28
24
  * use almost no RAM (and perform no heap allocations at all)
29
25
  * produce significantly improved floating-point error (by several orders of magnitude)
30
26
  * are json-serializable using Pydantic
31
- * can also be used easily in web and embedded applications via the Rust library
27
+ * can also be used easily in web, embedded and gpu applications via the Rust library
32
28
  * are permissively licensed
33
29
 
34
- ![ND throughput 1000 obs](./docs/throughput_vs_dims_1000_obs.svg)
30
+ <br>
31
+
32
+ <img src="./docs/speedup_vs_dims_1_obs_linear_inverted.svg" alt="">
35
33
 
36
34
  See [here](https://interpnpy.readthedocs.io/en/latest/perf/) for more info about quality-of-fit, throughput, and memory usage.
37
35
 
@@ -43,8 +41,7 @@ pip install interpn
43
41
 
44
42
  ## Profile-Guided Optimization
45
43
 
46
- To build the extension with profile-guided optimization using pre-built profiles, do `sh ./scripts/distr_pgo_install.sh`.
47
- You can also generate your own PGO profiles like `sh ./scripts/distr_pgo_profile.sh`.
44
+ To build the extension with profile-guided optimization, do `sh ./scripts/distr_pgo.sh`
48
45
  after installing this extra compiler dependency:
49
46
 
50
47
  ```bash
@@ -92,13 +92,7 @@ def _plot_normalized_vs_nobs(
92
92
  title: str,
93
93
  output_path: Path,
94
94
  ) -> None:
95
- fig = make_subplots(
96
- rows=2,
97
- cols=1,
98
- subplot_titles=["Linear", "Cubic"],
99
- horizontal_spacing=0.08,
100
- )
101
- for row, kind in enumerate(["Linear", "Cubic"], start=1):
95
+ for kind in ["Linear", "Cubic"]:
102
96
  baseline_vals = throughputs.get(f"Scipy RegularGridInterpolator {kind}")
103
97
  if not baseline_vals:
104
98
  continue
@@ -108,7 +102,7 @@ def _plot_normalized_vs_nobs(
108
102
  for name, values in throughputs.items()
109
103
  if kinds.get(name) == kind and values
110
104
  ]
111
-
105
+ fig = make_subplots(rows=1, cols=1)
112
106
  for idx, (label, values) in enumerate(series):
113
107
  min_len = min(len(values), len(baseline_arr))
114
108
  if min_len == 0:
@@ -116,6 +110,12 @@ def _plot_normalized_vs_nobs(
116
110
  x_vals = np.array(ns[:min_len])
117
111
  ratios = values[:min_len] / baseline_arr[:min_len]
118
112
  is_baseline = label.startswith("Scipy RegularGridInterpolator")
113
+ legend_name = "Scipy" if is_baseline else "InterpN"
114
+ showlegend = True
115
+ for trace in fig.data:
116
+ if trace.name == legend_name:
117
+ showlegend = False
118
+ break
119
119
  fig.add_trace(
120
120
  go.Scatter(
121
121
  x=x_vals,
@@ -129,13 +129,9 @@ def _plot_normalized_vs_nobs(
129
129
  size=8,
130
130
  ),
131
131
  opacity=1.0,
132
- name=label if not is_baseline else f"{label}<br>(baseline)",
133
- showlegend=True,
134
- legendgroup=kind,
135
- legendgrouptitle_text=kind,
136
- ),
137
- row=row,
138
- col=1,
132
+ name=legend_name,
133
+ showlegend=showlegend,
134
+ )
139
135
  )
140
136
  if not is_baseline and label.startswith("InterpN"):
141
137
  ones = np.ones_like(ratios)
@@ -146,81 +142,59 @@ def _plot_normalized_vs_nobs(
146
142
  x=x_vals,
147
143
  upper=upper,
148
144
  lower=lower,
149
- row=row,
145
+ row=1,
150
146
  col=1,
151
147
  )
152
-
153
- fig.update_xaxes(
154
- type="log",
155
- row=1,
156
- col=1,
157
- showline=True,
158
- linecolor="black",
159
- linewidth=1,
160
- mirror=True,
161
- ticks="outside",
162
- tickcolor="black",
163
- showgrid=False,
164
- zeroline=False,
165
- )
166
- fig.update_xaxes(
167
- type="log",
168
- title_text="Number of Observation Points",
169
- row=2,
170
- col=1,
171
- showline=True,
172
- linecolor="black",
173
- linewidth=1,
174
- mirror=True,
175
- ticks="outside",
176
- tickcolor="black",
177
- showgrid=False,
178
- zeroline=False,
179
- )
180
- fig.update_yaxes(
181
- title_text="Speedup vs. Scipy",
182
- row=1,
183
- col=1,
184
- showline=True,
185
- linecolor="black",
186
- linewidth=1,
187
- mirror=True,
188
- ticks="outside",
189
- tickcolor="black",
190
- showgrid=False,
191
- zeroline=False,
192
- )
193
- fig.update_yaxes(
194
- row=2,
195
- col=1,
196
- showline=True,
197
- linecolor="black",
198
- linewidth=1,
199
- mirror=True,
200
- ticks="outside",
201
- tickcolor="black",
202
- showgrid=False,
203
- zeroline=False,
204
- )
205
- fig.update_layout(
206
- title=dict(text=title, y=0.97, yanchor="top"),
207
- height=450,
208
- margin=dict(t=80, l=60, r=200, b=90),
209
- legend=dict(
210
- orientation="v",
211
- yanchor="top",
212
- y=1.0,
213
- x=1.02,
214
- xanchor="left",
215
- ),
216
- plot_bgcolor="rgba(0,0,0,0)",
217
- paper_bgcolor="rgba(0,0,0,0)",
218
- )
219
- fig.write_image(str(output_path))
220
- fig.write_html(
221
- str(output_path.with_suffix(".html")), include_plotlyjs="cdn", full_html=False
222
- )
223
- fig.show()
148
+ fig.update_xaxes(
149
+ type="log",
150
+ title_text="Number of Observation Points",
151
+ row=1,
152
+ col=1,
153
+ showline=True,
154
+ linecolor="black",
155
+ linewidth=1,
156
+ mirror=True,
157
+ ticks="outside",
158
+ tickcolor="black",
159
+ showgrid=False,
160
+ zeroline=False,
161
+ )
162
+ fig.update_yaxes(
163
+ title_text="Normalized Throughput",
164
+ row=1,
165
+ col=1,
166
+ showline=True,
167
+ linecolor="black",
168
+ linewidth=1,
169
+ mirror=True,
170
+ ticks="outside",
171
+ tickcolor="black",
172
+ showgrid=False,
173
+ zeroline=False,
174
+ )
175
+ fig.update_layout(
176
+ title=dict(text=f"{title}, {kind}", y=0.97, yanchor="top"),
177
+ height=400,
178
+ margin=dict(t=60, l=60, r=60, b=110),
179
+ legend=dict(
180
+ orientation="h",
181
+ yanchor="top",
182
+ y=1.0,
183
+ x=1.0,
184
+ xanchor="right",
185
+ ),
186
+ plot_bgcolor="rgba(0,0,0,0)",
187
+ paper_bgcolor="rgba(0,0,0,0)",
188
+ font=dict(color="black"),
189
+ )
190
+ per_kind_output = output_path.with_stem(output_path.stem + f"_{kind.lower()}")
191
+ fig.write_image(str(per_kind_output))
192
+ fig.write_html(
193
+ str(per_kind_output.with_suffix(".html")),
194
+ include_plotlyjs="cdn",
195
+ full_html=False,
196
+ )
197
+ fig.show()
224
198
 
225
199
 
226
200
  def _plot_throughput_vs_dims(
@@ -368,6 +342,7 @@ def _plot_throughput_vs_dims(
368
342
  ),
369
343
  plot_bgcolor="rgba(0,0,0,0)",
370
344
  paper_bgcolor="rgba(0,0,0,0)",
345
+ font=dict(color="black"),
371
346
  )
372
347
  fig.write_image(str(output_path))
373
348
  fig.write_html(
@@ -479,6 +454,7 @@ def _plot_speedup_vs_dims(
479
454
  # ),
480
455
  plot_bgcolor="rgba(0,0,0,0)",
481
456
  paper_bgcolor="rgba(0,0,0,0)",
457
+ font=dict(color="black"),
482
458
  )
483
459
  output_path = output_dir / f"speedup_vs_dims_{nobs}_obs_{kind.lower()}.svg"
484
460
  fig.write_image(str(output_path))