IsoSpecPy 2.3.4__tar.gz → 2.4.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 (64) hide show
  1. isospecpy-2.4.0/PKG-INFO +159 -0
  2. isospecpy-2.4.0/README.md +137 -0
  3. isospecpy-2.4.0/VERSION +1 -0
  4. {isospecpy-2.3.4 → isospecpy-2.4.0}/pyproject.toml +22 -3
  5. isospecpy-2.4.0/skbuild/CMakeLists.txt +71 -0
  6. isospecpy-2.4.0/src/IsoSpec++/IsaDispatch.cmake +78 -0
  7. isospecpy-2.4.0/src/IsoSpec++/aligned_ptr.h +622 -0
  8. isospecpy-2.4.0/src/IsoSpec++/cwrapper.cpp +582 -0
  9. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/cwrapper.h +37 -0
  10. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/fasta.h +4 -1
  11. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/fixedEnvelopes.cpp +474 -362
  12. isospecpy-2.4.0/src/IsoSpec++/fixedEnvelopes.h +418 -0
  13. isospecpy-2.4.0/src/IsoSpec++/isa_dispatch.cpp +294 -0
  14. isospecpy-2.4.0/src/IsoSpec++/isa_kernel_impl.h +192 -0
  15. isospecpy-2.4.0/src/IsoSpec++/isa_kernels.h +172 -0
  16. isospecpy-2.4.0/src/IsoSpec++/isa_kernels_avx.cpp +57 -0
  17. isospecpy-2.4.0/src/IsoSpec++/isa_kernels_baseline.cpp +27 -0
  18. isospecpy-2.4.0/src/IsoSpec++/isa_kernels_v3.cpp +45 -0
  19. isospecpy-2.4.0/src/IsoSpec++/isa_kernels_v4.cpp +46 -0
  20. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/isoMath.cpp +20 -0
  21. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/isoMath.h +23 -3
  22. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/isoSpec++.cpp +21 -7
  23. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/isoSpec++.h +50 -2
  24. isospecpy-2.4.0/src/IsoSpec++/iso_simd.h +48 -0
  25. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/marginalTrek++.cpp +43 -24
  26. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/marginalTrek++.h +20 -4
  27. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/misc.cpp +1 -1
  28. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/misc.h +6 -2
  29. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/platform.h +69 -0
  30. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/pod_vector.h +5 -3
  31. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/unity-build.cpp +7 -0
  32. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/Distributions.py +0 -1
  33. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/IsoSpecPy.py +101 -42
  34. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/PeriodicTbl.py +1 -1
  35. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/approximations.py +0 -9
  36. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/isoFFI.py +11 -2
  37. isospecpy-2.3.4/PKG-INFO +0 -43
  38. isospecpy-2.3.4/README.md +0 -21
  39. isospecpy-2.3.4/skbuild/CMakeLists.txt +0 -18
  40. isospecpy-2.3.4/src/IsoSpec++/cwrapper.cpp +0 -495
  41. isospecpy-2.3.4/src/IsoSpec++/fixedEnvelopes.h +0 -245
  42. {isospecpy-2.3.4 → isospecpy-2.4.0}/LICENCE +0 -0
  43. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/allocator.cpp +0 -0
  44. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/allocator.h +0 -0
  45. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/btrd.h +0 -0
  46. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/conf.h +0 -0
  47. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/dirtyAllocator.cpp +0 -0
  48. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/dirtyAllocator.h +0 -0
  49. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/element_tables.cpp +0 -0
  50. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/element_tables.h +0 -0
  51. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/fasta.cpp +0 -0
  52. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/mman.cpp +0 -0
  53. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/mman.h +0 -0
  54. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/operators.cpp +0 -0
  55. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/operators.h +0 -0
  56. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/platform_incl.h +0 -0
  57. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/python-build.cpp +0 -0
  58. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpec++/summator.h +0 -0
  59. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/Advanced.py +0 -0
  60. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/Formulas.py +0 -0
  61. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/IsoSpecPyOld.py +0 -0
  62. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/__init__.py +0 -0
  63. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/__main__.py +0 -0
  64. {isospecpy-2.3.4 → isospecpy-2.4.0}/src/IsoSpecPy/confs_passthrough.py +0 -0
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: IsoSpecPy
3
+ Version: 2.4.0
4
+ Summary: IsoSpecPy is a Python library for computing isotopic distributions of molecules.
5
+ Keywords: isotopic distribution,mass spectrometry,chemistry,isotopic envelope,isotopologues
6
+ Author: Michał Startek, Mateusz Łącki
7
+ License-Expression: BSD-2-Clause
8
+ License-File: LICENCE
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.6
11
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Operating System :: OS Independent
14
+ Project-URL: Homepage, https://github.com/MatteoLacki/IsoSpec
15
+ Project-URL: Repository, https://github.com/MatteoLacki/IsoSpec
16
+ Requires-Python: >=3.6
17
+ Requires-Dist: cffi
18
+ Provides-Extra: testing
19
+ Requires-Dist: pytest; extra == "testing"
20
+ Requires-Dist: OldIsoSpecPy; extra == "testing"
21
+ Description-Content-Type: text/markdown
22
+
23
+ # IsoSpec
24
+
25
+ IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
26
+
27
+ IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI) and R (`IsoSpecR`, on CRAN).
28
+
29
+ ## Installation
30
+
31
+ ### Python
32
+
33
+ ```bash
34
+ pip install IsoSpecPy
35
+ ```
36
+
37
+ The wheel bundles the C++ library — no separate native install required. Compatible with CPython and PyPy on Linux, macOS, Windows, and Cygwin/MinGW. Python ≥ 3.6.
38
+
39
+ To build from source: `pip install .` from a checkout. A C++20 compiler is required.
40
+
41
+ ### R
42
+
43
+ ```r
44
+ install.packages("IsoSpecR")
45
+ ```
46
+
47
+ From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
48
+
49
+ ### C++ library
50
+
51
+ ```bash
52
+ cd src/IsoSpec++
53
+ make # produces libIsoSpec++.so
54
+ ```
55
+
56
+ Or via CMake from the repo root:
57
+
58
+ ```bash
59
+ cmake -B build -DCMAKE_BUILD_TYPE=Release
60
+ cmake --build build
61
+ sudo cmake --install build
62
+ ```
63
+
64
+ Requires a C++20 compiler. CMake produces both shared and static libraries and installs headers under `${CMAKE_INSTALL_INCLUDEDIR}/IsoSpec++`.
65
+
66
+ ## Quick start
67
+
68
+ The most common usage is `IsoTotalProb`: ask for the smallest set of isotopologues whose summed probability covers a chosen fraction of the spectrum (typically 0.99–0.9999). The result is a materialized envelope — arrays of masses and probabilities you can read directly.
69
+
70
+ ### Python
71
+
72
+ ```python
73
+ import IsoSpecPy
74
+
75
+ # Isotopologues covering at least 99.9% of the probability mass of water.
76
+ iso = IsoSpecPy.IsoTotalProb(formula="H2O1", prob_to_cover=0.999)
77
+
78
+ for mass, prob in zip(iso.masses, iso.probs):
79
+ print(mass, prob)
80
+
81
+ # From an amino-acid FASTA sequence:
82
+ iso = IsoSpecPy.IsoTotalProb(fasta="AAAPPGQAAC", prob_to_cover=0.999)
83
+ print(list(zip(iso.masses, iso.probs)))
84
+ ```
85
+
86
+ See `Examples/Python/` for radiolabelling, custom elements, binned spectra, and FASTA modifications.
87
+
88
+ ### C++
89
+
90
+ ```cpp
91
+ #include "IsoSpec++/isoSpec++.h"
92
+ #include "IsoSpec++/fixedEnvelopes.h"
93
+
94
+ using namespace IsoSpec;
95
+
96
+ int main() {
97
+ FixedEnvelope iso = FixedEnvelope::FromTotalProb("H2O1", 0.999, true, true);
98
+
99
+ for (size_t i = 0; i < iso.confs_no(); ++i) {
100
+ std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
101
+ }
102
+ }
103
+ ```
104
+
105
+ Quickest way to build:
106
+
107
+ ```bash
108
+ clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
109
+ ```
110
+
111
+ (`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
112
+
113
+ ### R
114
+
115
+ ```r
116
+ library(IsoSpecR)
117
+ water <- c(H = 2, O = 1)
118
+ IsoSpecify(molecule = water, stopCondition = 0.999)
119
+ ```
120
+
121
+ See `Examples/R/` for radiolabelling and full-spectrum extraction.
122
+
123
+ ## Advanced features
124
+
125
+ - **Alternative algorithms** — for cases where `IsoTotalProb` isn't the right shape:
126
+ - `IsoThreshold` — all isotopologues with probability above a fixed threshold.
127
+ - `IsoStochastic` — simulate a measured spectrum by sampling integer ion counts.
128
+ - `IsoBinned` — histogram-style envelope at a chosen bin width.
129
+ - **FASTA support** — build an `Iso` directly from an amino-acid sequence; optionally include the N/C-terminal water.
130
+ - **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
131
+ - **Fixed-envelope arithmetic** — addition, normalization, convolution, Wasserstein distance.
132
+ - **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
133
+ - **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability.
134
+
135
+ Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
136
+
137
+ ## Repository layout
138
+
139
+ ```
140
+ src/IsoSpec++/ C++ core library (the algorithms live here)
141
+ src/IsoSpecPy/ Python binding, loaded via cffi
142
+ src/IsoSpecR/ R binding, via Rcpp
143
+ Examples/ Working examples in each language
144
+ tests/ C, C++, and Python test suites
145
+ skbuild/ scikit-build-core entry point used when installing the Python wheel
146
+ ```
147
+
148
+ ## Citation
149
+
150
+ If IsoSpec is useful in your research, please cite:
151
+
152
+ - Łącki, M. K.; Valkenborg, D.; Startek, M. P. *IsoSpec2: Ultrafast Fine Structure Calculator.* Analytical Chemistry **2020**, *92* (14), 9472–9475. <https://doi.org/10.1021/acs.analchem.0c00959>
153
+ - Łącki, M. K.; Startek, M.; Valkenborg, D.; Gambin, A. *IsoSpec: Hyperfast Fine Structure Calculator.* Analytical Chemistry **2017**, *89* (6), 3272–3277. <https://doi.org/10.1021/acs.analchem.6b01459>
154
+
155
+ The Supporting Information of each paper has the algorithmic detail.
156
+
157
+ ## License
158
+
159
+ 2-clause BSD (see `LICENCE`). If you need different licensing terms, contact the authors. The authors appreciate (but do not require) being told when IsoSpec is used in other software.
@@ -0,0 +1,137 @@
1
+ # IsoSpec
2
+
3
+ IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
4
+
5
+ IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI) and R (`IsoSpecR`, on CRAN).
6
+
7
+ ## Installation
8
+
9
+ ### Python
10
+
11
+ ```bash
12
+ pip install IsoSpecPy
13
+ ```
14
+
15
+ The wheel bundles the C++ library — no separate native install required. Compatible with CPython and PyPy on Linux, macOS, Windows, and Cygwin/MinGW. Python ≥ 3.6.
16
+
17
+ To build from source: `pip install .` from a checkout. A C++20 compiler is required.
18
+
19
+ ### R
20
+
21
+ ```r
22
+ install.packages("IsoSpecR")
23
+ ```
24
+
25
+ From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
26
+
27
+ ### C++ library
28
+
29
+ ```bash
30
+ cd src/IsoSpec++
31
+ make # produces libIsoSpec++.so
32
+ ```
33
+
34
+ Or via CMake from the repo root:
35
+
36
+ ```bash
37
+ cmake -B build -DCMAKE_BUILD_TYPE=Release
38
+ cmake --build build
39
+ sudo cmake --install build
40
+ ```
41
+
42
+ Requires a C++20 compiler. CMake produces both shared and static libraries and installs headers under `${CMAKE_INSTALL_INCLUDEDIR}/IsoSpec++`.
43
+
44
+ ## Quick start
45
+
46
+ The most common usage is `IsoTotalProb`: ask for the smallest set of isotopologues whose summed probability covers a chosen fraction of the spectrum (typically 0.99–0.9999). The result is a materialized envelope — arrays of masses and probabilities you can read directly.
47
+
48
+ ### Python
49
+
50
+ ```python
51
+ import IsoSpecPy
52
+
53
+ # Isotopologues covering at least 99.9% of the probability mass of water.
54
+ iso = IsoSpecPy.IsoTotalProb(formula="H2O1", prob_to_cover=0.999)
55
+
56
+ for mass, prob in zip(iso.masses, iso.probs):
57
+ print(mass, prob)
58
+
59
+ # From an amino-acid FASTA sequence:
60
+ iso = IsoSpecPy.IsoTotalProb(fasta="AAAPPGQAAC", prob_to_cover=0.999)
61
+ print(list(zip(iso.masses, iso.probs)))
62
+ ```
63
+
64
+ See `Examples/Python/` for radiolabelling, custom elements, binned spectra, and FASTA modifications.
65
+
66
+ ### C++
67
+
68
+ ```cpp
69
+ #include "IsoSpec++/isoSpec++.h"
70
+ #include "IsoSpec++/fixedEnvelopes.h"
71
+
72
+ using namespace IsoSpec;
73
+
74
+ int main() {
75
+ FixedEnvelope iso = FixedEnvelope::FromTotalProb("H2O1", 0.999, true, true);
76
+
77
+ for (size_t i = 0; i < iso.confs_no(); ++i) {
78
+ std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
79
+ }
80
+ }
81
+ ```
82
+
83
+ Quickest way to build:
84
+
85
+ ```bash
86
+ clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
87
+ ```
88
+
89
+ (`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
90
+
91
+ ### R
92
+
93
+ ```r
94
+ library(IsoSpecR)
95
+ water <- c(H = 2, O = 1)
96
+ IsoSpecify(molecule = water, stopCondition = 0.999)
97
+ ```
98
+
99
+ See `Examples/R/` for radiolabelling and full-spectrum extraction.
100
+
101
+ ## Advanced features
102
+
103
+ - **Alternative algorithms** — for cases where `IsoTotalProb` isn't the right shape:
104
+ - `IsoThreshold` — all isotopologues with probability above a fixed threshold.
105
+ - `IsoStochastic` — simulate a measured spectrum by sampling integer ion counts.
106
+ - `IsoBinned` — histogram-style envelope at a chosen bin width.
107
+ - **FASTA support** — build an `Iso` directly from an amino-acid sequence; optionally include the N/C-terminal water.
108
+ - **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
109
+ - **Fixed-envelope arithmetic** — addition, normalization, convolution, Wasserstein distance.
110
+ - **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
111
+ - **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability.
112
+
113
+ Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
114
+
115
+ ## Repository layout
116
+
117
+ ```
118
+ src/IsoSpec++/ C++ core library (the algorithms live here)
119
+ src/IsoSpecPy/ Python binding, loaded via cffi
120
+ src/IsoSpecR/ R binding, via Rcpp
121
+ Examples/ Working examples in each language
122
+ tests/ C, C++, and Python test suites
123
+ skbuild/ scikit-build-core entry point used when installing the Python wheel
124
+ ```
125
+
126
+ ## Citation
127
+
128
+ If IsoSpec is useful in your research, please cite:
129
+
130
+ - Łącki, M. K.; Valkenborg, D.; Startek, M. P. *IsoSpec2: Ultrafast Fine Structure Calculator.* Analytical Chemistry **2020**, *92* (14), 9472–9475. <https://doi.org/10.1021/acs.analchem.0c00959>
131
+ - Łącki, M. K.; Startek, M.; Valkenborg, D.; Gambin, A. *IsoSpec: Hyperfast Fine Structure Calculator.* Analytical Chemistry **2017**, *89* (6), 3272–3277. <https://doi.org/10.1021/acs.analchem.6b01459>
132
+
133
+ The Supporting Information of each paper has the algorithmic detail.
134
+
135
+ ## License
136
+
137
+ 2-clause BSD (see `LICENCE`). If you need different licensing terms, contact the authors. The authors appreciate (but do not require) being told when IsoSpec is used in other software.
@@ -0,0 +1 @@
1
+ 2.4.0
@@ -2,6 +2,15 @@
2
2
  requires = ["setuptools", "scikit-build-core"]
3
3
  build-backend = "scikit_build_core.build"
4
4
 
5
+ # Single source of truth for the version: the VERSION file at the top of the
6
+ # tree, which CMakeLists.txt reads too (see the note there). Keep that file to
7
+ # one bare version number on one line.
8
+ [[tool.dynamic-metadata]]
9
+ field = "version"
10
+ provider = "scikit_build_core.metadata.regex"
11
+ input = "VERSION"
12
+ regex = "^\\s*(?P<value>[0-9]+(?:\\.[0-9]+)*)"
13
+
5
14
  [tool.scikit-build]
6
15
  cmake.source-dir = "skbuild"
7
16
 
@@ -9,7 +18,7 @@ cmake.source-dir = "skbuild"
9
18
  name = "IsoSpecPy"
10
19
  dependencies = ["cffi"]
11
20
  description = "IsoSpecPy is a Python library for computing isotopic distributions of molecules."
12
- version = "2.3.4"
21
+ dynamic = ["version"]
13
22
  license = "BSD-2-Clause"
14
23
  license-files = ["LICENCE"]
15
24
  authors = [{name = "Michał Startek"}, {name = "Mateusz Łącki"}]
@@ -38,11 +47,17 @@ testpaths = ["tests/Python"]
38
47
 
39
48
  [tool.cibuildwheel]
40
49
  enable = ["pypy"]
41
- skip = ["cp36-*", "cp37-*", "pp37-*"]
42
- test-command = "python -m pytest {project}/tests/Python"
50
+ test-command = "python -m pytest -o faulthandler_timeout=600 {project}/tests/Python"
43
51
  #test-sources = ["tests/Python"]
44
52
  test-extras = ["testing"]
45
53
 
54
+ # Apple Clang's libc++ has no <experimental/simd>; build with Homebrew GCC instead.
55
+ [tool.cibuildwheel.macos]
56
+ before-all = "brew install gcc"
57
+ # NB: cibuildwheel evaluates these with bashlex, which supports command
58
+ # substitution but *not* pipelines - hence the `sh -c` wrapper.
59
+ environment = { CC = "$(sh -c 'ls $(brew --prefix gcc)/bin/gcc-* | sort -V | tail -1')", CXX = "$(sh -c 'ls $(brew --prefix gcc)/bin/g++-* | sort -V | tail -1')" }
60
+
46
61
  [tool.scikit-build.sdist]
47
62
  exclude = ["**/*"]
48
63
  include = [
@@ -51,6 +66,10 @@ include = [
51
66
  "/src/IsoSpec++/*.h",
52
67
  "/src/IsoSpec++/*.hpp",
53
68
  "/src/IsoSpec++/*.cpp",
69
+ # skbuild/CMakeLists.txt include()s IsaDispatch.cmake; without this the
70
+ # sdist configures no further than that line.
71
+ "/src/IsoSpec++/*.cmake",
72
+ "/VERSION",
54
73
  "/LICENCE",
55
74
  "/README.md",
56
75
  "/pyproject.toml",
@@ -0,0 +1,71 @@
1
+ cmake_minimum_required(VERSION 3.15)
2
+
3
+ project(IsoSpecPy CXX)
4
+
5
+ set(CMAKE_CXX_STANDARD 20)
6
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
7
+ set(CMAKE_CXX_EXTENSIONS OFF)
8
+
9
+ #find_package(PythonExtensions REQUIRED)
10
+ #find_package(Python COMPONENTS Interpreter Development REQUIRED)
11
+
12
+ # Runtime ISA dispatch. This matters most here: the wheel is built with no
13
+ # -march at all, so without it every user gets the x86-64 baseline -- 2-double
14
+ # vectors -- no matter what their CPU can do.
15
+ include(${CMAKE_CURRENT_LIST_DIR}/../src/IsoSpec++/IsaDispatch.cmake)
16
+
17
+ add_library(IsoSpecCppPy SHARED ../src/IsoSpec++/unity-build.cpp ${isospec_ISA_SRCS})
18
+ target_compile_features(IsoSpecCppPy PRIVATE cxx_std_20)
19
+
20
+ # macOS wheels are built with Homebrew GCC (Apple's libc++ has no
21
+ # <experimental/simd>), and Homebrew bottles its libstdc++.6.dylib for the
22
+ # *current* macOS -- minos 26.0 today. delocate refuses to bundle a dylib whose
23
+ # minimum target is newer than the wheel's (11.0 on arm64), and hard-fails the
24
+ # build. Linking the C++ runtime statically leaves libSystem as the only
25
+ # dependency, so there is nothing for delocate to reject. The
26
+ # "built for newer macOS version" warnings this draws from ld are the archive
27
+ # members' own load commands and are harmless.
28
+ #
29
+ # Plain -static-libstdc++ is not enough, though: the archive members keep
30
+ # default visibility, so the dylib would re-export ~2000 libstdc++ symbols.
31
+ # Mach-O coalesces weak definitions (templates, inline functions, vtables)
32
+ # across *all* loaded images regardless of two-level namespace, so a process
33
+ # that also loads anything built against Homebrew's libstdc++.6.dylib ends up
34
+ # with two copies of that runtime spliced together and aborts inside dlopen --
35
+ # silently, with no dyld message and nothing Python can catch. A seven-line
36
+ # extension whose static initialiser touches std::locale is enough to trigger
37
+ # it; OldIsoSpecPy, which the wheel test suite installs, is one such consumer.
38
+ # -load_hidden links the archive with all of its symbols hidden, so our private
39
+ # copy of the runtime stays private. It replaces -static-libstdc++ (which would
40
+ # otherwise pull the same archive in again, visibly).
41
+ if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
42
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libstdc++.a
43
+ OUTPUT_VARIABLE ISOSPEC_LIBSTDCXX_A
44
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
45
+ if(NOT IS_ABSOLUTE "${ISOSPEC_LIBSTDCXX_A}" OR NOT EXISTS "${ISOSPEC_LIBSTDCXX_A}")
46
+ message(FATAL_ERROR
47
+ "${CMAKE_CXX_COMPILER} could not locate a static libstdc++.a "
48
+ "(-print-file-name returned '${ISOSPEC_LIBSTDCXX_A}'). The macOS wheel "
49
+ "needs one: linking libstdc++ dynamically makes delocate reject the "
50
+ "Homebrew bottle, and linking it visibly breaks other libstdc++ users "
51
+ "in the same process.")
52
+ endif()
53
+ # -load_hidden needs a reasonably modern ld64; an older one rejects the
54
+ # option outright, which is a loud failure rather than a silent regression.
55
+ #
56
+ # The archive is only half of it: our own translation units instantiate std::
57
+ # templates (std::to_string, sorts, the Mersenne twister), and those weak
58
+ # definitions coalesce across images just as readily. std:: is not part of
59
+ # this library's ABI -- callers reach it through cwrapper's extern "C"
60
+ # interface -- so none of it has any business being exported.
61
+ # tests/Python/test_cxx_runtime.py fails if any of this comes undone.
62
+ target_link_options(IsoSpecCppPy PRIVATE
63
+ -static-libgcc "-Wl,-load_hidden,${ISOSPEC_LIBSTDCXX_A}"
64
+ "-Wl,-unexported_symbol,__ZNSt*" "-Wl,-unexported_symbol,__ZNKSt*"
65
+ "-Wl,-unexported_symbol,__ZSt*")
66
+ endif()
67
+ #python_extension_module(IsoSpecCppPy)
68
+ install(TARGETS IsoSpecCppPy LIBRARY DESTINATION IsoSpecPy)
69
+ install(DIRECTORY ../src/IsoSpec++/ DESTINATION IsoSpecPy/IsoSpec++
70
+ FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.hxx"
71
+ )
@@ -0,0 +1,78 @@
1
+ # Runtime ISA dispatch, for the CMake builds.
2
+ #
3
+ # The two batched fill kernels are compiled once per instruction-set level, each
4
+ # into its own translation unit with its own -march, and the one to run is chosen
5
+ # from the CPU at startup. They must never share a compilation with the rest of
6
+ # the library: a raised -march would otherwise reach every inline function in the
7
+ # headers, and the linker could then pick an AVX-512 copy of one for a code path
8
+ # reached on a CPU without it. See isa_kernels.h for the full reasoning.
9
+ #
10
+ # Include this, then add ${isospec_ISA_SRCS} to your target's sources. It sets
11
+ # the per-source flags and defines ISOSPEC_ISA_DISPATCH=1 for the directory.
12
+ #
13
+ # The kernel sources deliberately get no -march of their own beyond the level
14
+ # they implement: the baseline level has to stay runnable on any CPU of the
15
+ # target architecture, since it is what dispatch falls back to.
16
+
17
+ include(CheckCXXCompilerFlag)
18
+ include(CheckCXXSourceCompiles)
19
+
20
+ set(_isa_dir ${CMAKE_CURRENT_LIST_DIR})
21
+
22
+ # Worth turning off when building exclusively for the machine that will run the
23
+ # result (-march=native, say): dispatching costs an indirect call per marginal-0
24
+ # run -- measured at 0.5-3% on the binned fill and 2-7% on the threshold fill --
25
+ # which a single-level build compiled for the actual CPU does not pay.
26
+ option(ISOSPEC_ISA_DISPATCH "Build several instruction-set levels and select at run time" ON)
27
+
28
+ if(NOT ISOSPEC_ISA_DISPATCH)
29
+ set(isospec_ISA_SRCS "")
30
+ message(STATUS "IsoSpec: runtime ISA dispatch disabled; single-level build")
31
+ return()
32
+ endif()
33
+
34
+ set(isospec_ISA_SRCS
35
+ ${_isa_dir}/isa_kernels_baseline.cpp
36
+ ${_isa_dir}/isa_kernels_avx.cpp
37
+ ${_isa_dir}/isa_kernels_v3.cpp
38
+ ${_isa_dir}/isa_kernels_v4.cpp
39
+ )
40
+
41
+ set(_isa_avx_flags -mavx)
42
+ set(_isa_v3_flags -mavx2 -mfma)
43
+ set(_isa_v4_flags -mavx512f -mavx512bw -mavx512dq -mavx512vl)
44
+
45
+ # Only offer a level its flags where the compiler will take them; they are
46
+ # meaningless off x86, and older toolchains may not know the AVX-512 ones. The
47
+ # .cpp files then self-check the predefined macros those flags produce, so a
48
+ # level whose flags did not arrive publishes an empty table and dispatch simply
49
+ # never selects it -- rather than it being quietly built at the wrong width.
50
+ check_cxx_compiler_flag("-mavx" ISOSPEC_CXX_ACCEPTS_AVX)
51
+ check_cxx_compiler_flag("-mavx2 -mfma" ISOSPEC_CXX_ACCEPTS_V3)
52
+ check_cxx_compiler_flag("-mavx512f -mavx512bw -mavx512dq -mavx512vl" ISOSPEC_CXX_ACCEPTS_V4)
53
+
54
+ if(ISOSPEC_CXX_ACCEPTS_AVX)
55
+ set_source_files_properties(${_isa_dir}/isa_kernels_avx.cpp
56
+ PROPERTIES COMPILE_OPTIONS "${_isa_avx_flags}")
57
+ message(STATUS "IsoSpec: building ISA level avx (AVX, no FMA)")
58
+ else()
59
+ message(STATUS "IsoSpec: ISA level avx not available with this compiler/target")
60
+ endif()
61
+
62
+ if(ISOSPEC_CXX_ACCEPTS_V3)
63
+ set_source_files_properties(${_isa_dir}/isa_kernels_v3.cpp
64
+ PROPERTIES COMPILE_OPTIONS "${_isa_v3_flags}")
65
+ message(STATUS "IsoSpec: building ISA level v3 (AVX2+FMA)")
66
+ else()
67
+ message(STATUS "IsoSpec: ISA level v3 not available with this compiler/target")
68
+ endif()
69
+
70
+ if(ISOSPEC_CXX_ACCEPTS_V4)
71
+ set_source_files_properties(${_isa_dir}/isa_kernels_v4.cpp
72
+ PROPERTIES COMPILE_OPTIONS "${_isa_v4_flags}")
73
+ message(STATUS "IsoSpec: building ISA level v4 (AVX-512)")
74
+ else()
75
+ message(STATUS "IsoSpec: ISA level v4 not available with this compiler/target")
76
+ endif()
77
+
78
+ add_definitions(-DISOSPEC_ISA_DISPATCH=1)