bioimage-cpp 0.1.1__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 (194) hide show
  1. bioimage_cpp-0.1.1/.github/workflows/docs.yml +58 -0
  2. bioimage_cpp-0.1.1/.github/workflows/tests.yml +25 -0
  3. bioimage_cpp-0.1.1/.github/workflows/wheels.yml +119 -0
  4. bioimage_cpp-0.1.1/.gitignore +33 -0
  5. bioimage_cpp-0.1.1/AGENTS.md +212 -0
  6. bioimage_cpp-0.1.1/CMakeLists.txt +40 -0
  7. bioimage_cpp-0.1.1/LICENSE +21 -0
  8. bioimage_cpp-0.1.1/MIGRATION_GUIDE.md +1572 -0
  9. bioimage_cpp-0.1.1/PKG-INFO +36 -0
  10. bioimage_cpp-0.1.1/README.md +5 -0
  11. bioimage_cpp-0.1.1/development/affinities/check_compute_affinities.py +133 -0
  12. bioimage_cpp-0.1.1/development/filters/PERFORMANCE_NOTES.md +512 -0
  13. bioimage_cpp-0.1.1/development/filters/_bench_utils.py +562 -0
  14. bioimage_cpp-0.1.1/development/filters/benchmark.py +165 -0
  15. bioimage_cpp-0.1.1/development/filters/check_parity.py +134 -0
  16. bioimage_cpp-0.1.1/development/graph/_grid_affinity_compatibility.py +267 -0
  17. bioimage_cpp-0.1.1/development/graph/_rag_compatibility.py +331 -0
  18. bioimage_cpp-0.1.1/development/graph/check_grid_affinity_edges.py +154 -0
  19. bioimage_cpp-0.1.1/development/graph/check_grid_affinity_lifted_edges.py +144 -0
  20. bioimage_cpp-0.1.1/development/graph/check_rag_2d.py +31 -0
  21. bioimage_cpp-0.1.1/development/graph/check_rag_3d.py +30 -0
  22. bioimage_cpp-0.1.1/development/graph/lifted_multicut/PERFORMANCE_NOTES.md +390 -0
  23. bioimage_cpp-0.1.1/development/graph/lifted_multicut/_compatibility.py +162 -0
  24. bioimage_cpp-0.1.1/development/graph/lifted_multicut/check_fusion_move.py +64 -0
  25. bioimage_cpp-0.1.1/development/graph/lifted_multicut/check_greedy_additive.py +21 -0
  26. bioimage_cpp-0.1.1/development/graph/lifted_multicut/check_kernighan_lin.py +33 -0
  27. bioimage_cpp-0.1.1/development/graph/lifted_multicut/evaluate_solvers.py +251 -0
  28. bioimage_cpp-0.1.1/development/graph/multicut/PERFORMANCE_NOTES.md +92 -0
  29. bioimage_cpp-0.1.1/development/graph/multicut/_compatibility.py +134 -0
  30. bioimage_cpp-0.1.1/development/graph/multicut/check_chained.py +29 -0
  31. bioimage_cpp-0.1.1/development/graph/multicut/check_decomposer.py +23 -0
  32. bioimage_cpp-0.1.1/development/graph/multicut/check_fusion_move.py +43 -0
  33. bioimage_cpp-0.1.1/development/graph/multicut/check_greedy_additive.py +19 -0
  34. bioimage_cpp-0.1.1/development/graph/multicut/check_greedy_fixation.py +19 -0
  35. bioimage_cpp-0.1.1/development/graph/multicut/check_kernighan_lin.py +22 -0
  36. bioimage_cpp-0.1.1/development/graph/multicut/evaluate_solvers.py +305 -0
  37. bioimage_cpp-0.1.1/development/graph/mutex_watershed/check_mutex_clustering.py +341 -0
  38. bioimage_cpp-0.1.1/development/graph/mutex_watershed/check_semantic_mutex_clustering.py +420 -0
  39. bioimage_cpp-0.1.1/development/segmentation/PERFORMANCE_NOTES.md +184 -0
  40. bioimage_cpp-0.1.1/development/segmentation/_mutex_watershed_equivalence.py +238 -0
  41. bioimage_cpp-0.1.1/development/segmentation/_semantic_mws_equivalence.py +403 -0
  42. bioimage_cpp-0.1.1/development/segmentation/_watershed_equivalence.py +288 -0
  43. bioimage_cpp-0.1.1/development/segmentation/_watershed_from_affinities_equivalence.py +225 -0
  44. bioimage_cpp-0.1.1/development/segmentation/check_mutex_watershed_2d.py +39 -0
  45. bioimage_cpp-0.1.1/development/segmentation/check_mutex_watershed_3d.py +33 -0
  46. bioimage_cpp-0.1.1/development/segmentation/check_semantic_mutex_watershed_2d.py +40 -0
  47. bioimage_cpp-0.1.1/development/segmentation/check_semantic_mutex_watershed_3d.py +41 -0
  48. bioimage_cpp-0.1.1/development/segmentation/check_watershed_2d.py +40 -0
  49. bioimage_cpp-0.1.1/development/segmentation/check_watershed_3d.py +34 -0
  50. bioimage_cpp-0.1.1/development/segmentation/check_watershed_from_affinities_2d.py +34 -0
  51. bioimage_cpp-0.1.1/development/segmentation/check_watershed_from_affinities_3d.py +30 -0
  52. bioimage_cpp-0.1.1/development/transformation/PERFORMANCE_NOTES.md +247 -0
  53. bioimage_cpp-0.1.1/development/transformation/check_affine.py +499 -0
  54. bioimage_cpp-0.1.1/examples/segmentation/_lifted_problem.py +178 -0
  55. bioimage_cpp-0.1.1/examples/segmentation/lifted_multicut_from_affinities.py +98 -0
  56. bioimage_cpp-0.1.1/examples/segmentation/multicut_from_affinities.py +153 -0
  57. bioimage_cpp-0.1.1/examples/segmentation/mutex_watershed.py +45 -0
  58. bioimage_cpp-0.1.1/examples/segmentation/serialize_grid_lifted_problem.py +175 -0
  59. bioimage_cpp-0.1.1/examples/segmentation/serialize_lifted_problem.py +97 -0
  60. bioimage_cpp-0.1.1/examples/segmentation/watershed.py +104 -0
  61. bioimage_cpp-0.1.1/include/bioimage_cpp/affinities/compute_affinities.hxx +191 -0
  62. bioimage_cpp-0.1.1/include/bioimage_cpp/array_view.hxx +30 -0
  63. bioimage_cpp-0.1.1/include/bioimage_cpp/blocking.hxx +487 -0
  64. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/edge_hash.hxx +27 -0
  65. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/grid.hxx +59 -0
  66. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/indexed_heap.hxx +300 -0
  67. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/mutex_storage.hxx +54 -0
  68. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/profile.hxx +101 -0
  69. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/relabel.hxx +25 -0
  70. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/semantic_labels.hxx +57 -0
  71. bioimage_cpp-0.1.1/include/bioimage_cpp/detail/threading.hxx +60 -0
  72. bioimage_cpp-0.1.1/include/bioimage_cpp/filters/convolve.hxx +451 -0
  73. bioimage_cpp-0.1.1/include/bioimage_cpp/filters/eigenvalues.hxx +134 -0
  74. bioimage_cpp-0.1.1/include/bioimage_cpp/filters/gaussian.hxx +494 -0
  75. bioimage_cpp-0.1.1/include/bioimage_cpp/filters/kernel.hxx +137 -0
  76. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/breadth_first_search.hxx +118 -0
  77. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/connected_components.hxx +45 -0
  78. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/detail/fusion_contract.hxx +171 -0
  79. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/edge_weighted_watershed.hxx +159 -0
  80. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/feature_accumulation.hxx +624 -0
  81. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/grid_features.hxx +396 -0
  82. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/grid_graph.hxx +352 -0
  83. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_from_affinities.hxx +436 -0
  84. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut/detail.hxx +276 -0
  85. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut/fusion_move.hxx +438 -0
  86. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut/greedy_additive.hxx +146 -0
  87. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut/kernighan_lin.hxx +624 -0
  88. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut/objective.hxx +264 -0
  89. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/lifted_multicut.hxx +6 -0
  90. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/detail.hxx +289 -0
  91. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/fusion_move.hxx +352 -0
  92. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/greedy_additive.hxx +113 -0
  93. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/greedy_fixation.hxx +66 -0
  94. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/kernighan_lin.hxx +474 -0
  95. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut/objective.hxx +114 -0
  96. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/multicut.hxx +6 -0
  97. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/mutex_watershed/clustering.hxx +144 -0
  98. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/mutex_watershed/semantic.hxx +212 -0
  99. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/mutex_watershed.hxx +4 -0
  100. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/node_label_projection.hxx +86 -0
  101. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/proposal_generator.hxx +35 -0
  102. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/proposal_generators/greedy_additive_multicut.hxx +77 -0
  103. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/proposal_generators/watershed.hxx +128 -0
  104. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/region_adjacency_graph.hxx +223 -0
  105. bioimage_cpp-0.1.1/include/bioimage_cpp/graph/undirected_graph.hxx +431 -0
  106. bioimage_cpp-0.1.1/include/bioimage_cpp/overlap.hxx +262 -0
  107. bioimage_cpp-0.1.1/include/bioimage_cpp/segmentation/mutex_watershed.hxx +145 -0
  108. bioimage_cpp-0.1.1/include/bioimage_cpp/segmentation/semantic_mutex_watershed.hxx +198 -0
  109. bioimage_cpp-0.1.1/include/bioimage_cpp/segmentation/watershed.hxx +980 -0
  110. bioimage_cpp-0.1.1/include/bioimage_cpp/take_dict.hxx +41 -0
  111. bioimage_cpp-0.1.1/include/bioimage_cpp/transformation/affine.hxx +700 -0
  112. bioimage_cpp-0.1.1/include/bioimage_cpp/util/union_find.hxx +88 -0
  113. bioimage_cpp-0.1.1/pyproject.toml +60 -0
  114. bioimage_cpp-0.1.1/src/bindings/affinities.cxx +232 -0
  115. bioimage_cpp-0.1.1/src/bindings/affinities.hxx +9 -0
  116. bioimage_cpp-0.1.1/src/bindings/blocking.cxx +175 -0
  117. bioimage_cpp-0.1.1/src/bindings/blocking.hxx +9 -0
  118. bioimage_cpp-0.1.1/src/bindings/filters.cxx +565 -0
  119. bioimage_cpp-0.1.1/src/bindings/filters.hxx +9 -0
  120. bioimage_cpp-0.1.1/src/bindings/graph.cxx +1894 -0
  121. bioimage_cpp-0.1.1/src/bindings/graph.hxx +9 -0
  122. bioimage_cpp-0.1.1/src/bindings/ground_truth.cxx +117 -0
  123. bioimage_cpp-0.1.1/src/bindings/ground_truth.hxx +9 -0
  124. bioimage_cpp-0.1.1/src/bindings/module.cxx +26 -0
  125. bioimage_cpp-0.1.1/src/bindings/segmentation.cxx +504 -0
  126. bioimage_cpp-0.1.1/src/bindings/segmentation.hxx +9 -0
  127. bioimage_cpp-0.1.1/src/bindings/transformation.cxx +151 -0
  128. bioimage_cpp-0.1.1/src/bindings/transformation.hxx +9 -0
  129. bioimage_cpp-0.1.1/src/bindings/util.cxx +146 -0
  130. bioimage_cpp-0.1.1/src/bindings/util.hxx +9 -0
  131. bioimage_cpp-0.1.1/src/bindings/utils.cxx +113 -0
  132. bioimage_cpp-0.1.1/src/bindings/utils.hxx +9 -0
  133. bioimage_cpp-0.1.1/src/bioimage_cpp/__init__.py +78 -0
  134. bioimage_cpp-0.1.1/src/bioimage_cpp/_data.py +318 -0
  135. bioimage_cpp-0.1.1/src/bioimage_cpp/_version.py +1 -0
  136. bioimage_cpp-0.1.1/src/bioimage_cpp/affinities/__init__.py +5 -0
  137. bioimage_cpp-0.1.1/src/bioimage_cpp/affinities/compute_affinities.py +127 -0
  138. bioimage_cpp-0.1.1/src/bioimage_cpp/filters/__init__.py +20 -0
  139. bioimage_cpp-0.1.1/src/bioimage_cpp/filters/_filters.py +236 -0
  140. bioimage_cpp-0.1.1/src/bioimage_cpp/graph/__init__.py +2115 -0
  141. bioimage_cpp-0.1.1/src/bioimage_cpp/graph/_external.py +234 -0
  142. bioimage_cpp-0.1.1/src/bioimage_cpp/segmentation/__init__.py +11 -0
  143. bioimage_cpp-0.1.1/src/bioimage_cpp/segmentation/mutex_watershed.py +394 -0
  144. bioimage_cpp-0.1.1/src/bioimage_cpp/segmentation/watershed.py +261 -0
  145. bioimage_cpp-0.1.1/src/bioimage_cpp/transformation/__init__.py +13 -0
  146. bioimage_cpp-0.1.1/src/bioimage_cpp/transformation/_transformation.py +342 -0
  147. bioimage_cpp-0.1.1/src/bioimage_cpp/utils.py +368 -0
  148. bioimage_cpp-0.1.1/src/cpp/segmentation/mutex_watershed.cxx +23 -0
  149. bioimage_cpp-0.1.1/src/cpp/segmentation/semantic_mutex_watershed.cxx +27 -0
  150. bioimage_cpp-0.1.1/src/cpp/take_dict.cxx +32 -0
  151. bioimage_cpp-0.1.1/tests/affinities/test_compute_affinities.py +154 -0
  152. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/__init__.py +0 -0
  153. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/_helpers.py +11 -0
  154. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/conftest.py +52 -0
  155. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/test_external_problem.py +51 -0
  156. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/test_fusion_move.py +311 -0
  157. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/test_greedy_additive.py +88 -0
  158. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/test_kernighan_lin.py +99 -0
  159. bioimage_cpp-0.1.1/tests/graph/lifted_multicut/test_objective.py +157 -0
  160. bioimage_cpp-0.1.1/tests/graph/multicut/__init__.py +1 -0
  161. bioimage_cpp-0.1.1/tests/graph/multicut/_helpers.py +16 -0
  162. bioimage_cpp-0.1.1/tests/graph/multicut/conftest.py +55 -0
  163. bioimage_cpp-0.1.1/tests/graph/multicut/test_chain_decomposer.py +83 -0
  164. bioimage_cpp-0.1.1/tests/graph/multicut/test_external_problem.py +29 -0
  165. bioimage_cpp-0.1.1/tests/graph/multicut/test_fusion_move.py +267 -0
  166. bioimage_cpp-0.1.1/tests/graph/multicut/test_greedy_additive.py +44 -0
  167. bioimage_cpp-0.1.1/tests/graph/multicut/test_greedy_fixation.py +38 -0
  168. bioimage_cpp-0.1.1/tests/graph/multicut/test_kernighan_lin.py +54 -0
  169. bioimage_cpp-0.1.1/tests/graph/multicut/test_objective.py +40 -0
  170. bioimage_cpp-0.1.1/tests/graph/multicut/test_proposal_generators.py +67 -0
  171. bioimage_cpp-0.1.1/tests/graph/test_breadth_first_search.py +71 -0
  172. bioimage_cpp-0.1.1/tests/graph/test_connected_components.py +54 -0
  173. bioimage_cpp-0.1.1/tests/graph/test_edge_weighted_watershed.py +294 -0
  174. bioimage_cpp-0.1.1/tests/graph/test_grid_affinity_multicut_integration.py +89 -0
  175. bioimage_cpp-0.1.1/tests/graph/test_grid_features.py +203 -0
  176. bioimage_cpp-0.1.1/tests/graph/test_grid_graph.py +189 -0
  177. bioimage_cpp-0.1.1/tests/graph/test_mutex_watershed_graph.py +265 -0
  178. bioimage_cpp-0.1.1/tests/graph/test_node_label_projection.py +47 -0
  179. bioimage_cpp-0.1.1/tests/graph/test_rag_features.py +204 -0
  180. bioimage_cpp-0.1.1/tests/graph/test_rag_lifted_features.py +307 -0
  181. bioimage_cpp-0.1.1/tests/graph/test_rag_multicut_integration.py +64 -0
  182. bioimage_cpp-0.1.1/tests/graph/test_region_adjacency_graph.py +99 -0
  183. bioimage_cpp-0.1.1/tests/graph/test_semantic_mutex_watershed_graph.py +276 -0
  184. bioimage_cpp-0.1.1/tests/graph/test_undirected_graph.py +157 -0
  185. bioimage_cpp-0.1.1/tests/segmentation/test_mutex_watershed.py +179 -0
  186. bioimage_cpp-0.1.1/tests/segmentation/test_semantic_mutex_watershed.py +185 -0
  187. bioimage_cpp-0.1.1/tests/segmentation/test_watershed.py +157 -0
  188. bioimage_cpp-0.1.1/tests/segmentation/test_watershed_from_affinities.py +299 -0
  189. bioimage_cpp-0.1.1/tests/test_blocking.py +144 -0
  190. bioimage_cpp-0.1.1/tests/test_filters.py +271 -0
  191. bioimage_cpp-0.1.1/tests/test_ground_truth_overlap.py +146 -0
  192. bioimage_cpp-0.1.1/tests/test_transformation.py +410 -0
  193. bioimage_cpp-0.1.1/tests/test_util_union_find.py +143 -0
  194. bioimage_cpp-0.1.1/tests/test_utils_take_dict.py +75 -0
@@ -0,0 +1,58 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.11"
25
+ - uses: actions/configure-pages@v5
26
+ - name: Install package and docs tooling
27
+ run: python -m pip install -v ".[test]" pdoc
28
+ - name: Prepare source tree for pdoc
29
+ run: |
30
+ python - <<'PY'
31
+ import importlib.util
32
+ import shutil
33
+ from pathlib import Path
34
+
35
+ spec = importlib.util.find_spec("bioimage_cpp._core")
36
+ if spec is None or spec.origin is None:
37
+ raise RuntimeError("Could not find installed bioimage_cpp._core")
38
+
39
+ source_package = Path("src/bioimage_cpp")
40
+ target = source_package / Path(spec.origin).name
41
+ shutil.copy2(spec.origin, target)
42
+ print(f"Copied {spec.origin} to {target}")
43
+ PY
44
+ - name: Build docs
45
+ run: PYTHONPATH=src pdoc bioimage_cpp -o docs
46
+ - uses: actions/upload-pages-artifact@v3
47
+ with:
48
+ path: docs
49
+
50
+ deploy:
51
+ needs: build
52
+ runs-on: ubuntu-latest
53
+ environment:
54
+ name: github-pages
55
+ url: ${{ steps.deployment.outputs.page_url }}
56
+ steps:
57
+ - id: deployment
58
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,25 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ name: ${{ matrix.os }}
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest, windows-latest]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.11"
20
+ - name: Install package
21
+ run: python -m pip install -v ".[test]"
22
+ - name: Test import
23
+ run: python -c "import bioimage_cpp"
24
+ - name: Run tests
25
+ run: pytest -q
@@ -0,0 +1,119 @@
1
+ name: wheels
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build_wheels:
13
+ name: wheels-${{ matrix.os }}
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, macos-latest, windows-latest]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Build wheels
24
+ uses: pypa/cibuildwheel@v3.4.1
25
+ env:
26
+ CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*"
27
+ CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux_*"
28
+ CIBW_ARCHS_MACOS: "x86_64 arm64"
29
+ CIBW_ENVIRONMENT_MACOS: "MACOSX_DEPLOYMENT_TARGET=10.13"
30
+ CIBW_TEST_REQUIRES: "pytest pooch scipy"
31
+ CIBW_TEST_COMMAND: "python -c \"import bioimage_cpp; print(bioimage_cpp.__file__)\" && pytest -q {project}/tests"
32
+
33
+ - name: Upload wheels
34
+ uses: actions/upload-artifact@v4
35
+ with:
36
+ name: cibw-wheels-${{ matrix.os }}
37
+ path: wheelhouse/*.whl
38
+
39
+ build_sdist:
40
+ name: sdist
41
+ runs-on: ubuntu-latest
42
+
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: "3.11"
48
+
49
+ - name: Install build tooling
50
+ run: python -m pip install build twine
51
+
52
+ - name: Build sdist
53
+ run: python -m build --sdist
54
+
55
+ - name: Check sdist metadata
56
+ run: python -m twine check dist/*
57
+
58
+ - name: Upload sdist
59
+ uses: actions/upload-artifact@v4
60
+ with:
61
+ name: cibw-sdist
62
+ path: dist/*.tar.gz
63
+
64
+ publish-testpypi:
65
+ name: publish-to-testpypi
66
+ needs: [build_wheels, build_sdist]
67
+ runs-on: ubuntu-latest
68
+ if: github.event_name == 'workflow_dispatch'
69
+
70
+ environment:
71
+ name: testpypi
72
+ url: https://test.pypi.org/p/bioimage-cpp
73
+
74
+ permissions:
75
+ id-token: write
76
+
77
+ steps:
78
+ - name: Download distributions
79
+ uses: actions/download-artifact@v4
80
+ with:
81
+ pattern: cibw-*
82
+ path: dist
83
+ merge-multiple: true
84
+
85
+ - name: List distributions
86
+ run: ls -lh dist
87
+
88
+ - name: Publish to TestPyPI
89
+ uses: pypa/gh-action-pypi-publish@release/v1
90
+ with:
91
+ repository-url: https://test.pypi.org/legacy/
92
+ attestations: false
93
+
94
+ publish-pypi:
95
+ name: publish-to-pypi
96
+ needs: [build_wheels, build_sdist]
97
+ runs-on: ubuntu-latest
98
+ if: github.event_name == 'release' && github.event.action == 'published'
99
+
100
+ environment:
101
+ name: pypi
102
+ url: https://pypi.org/p/bioimage-cpp
103
+
104
+ permissions:
105
+ id-token: write
106
+
107
+ steps:
108
+ - name: Download distributions
109
+ uses: actions/download-artifact@v4
110
+ with:
111
+ pattern: cibw-*
112
+ path: dist
113
+ merge-multiple: true
114
+
115
+ - name: List distributions
116
+ run: ls -lh dist
117
+
118
+ - name: Publish to PyPI
119
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,33 @@
1
+ # Python caches
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Python packaging/build outputs
7
+ *.egg-info/
8
+ build/
9
+ dist/
10
+ wheelhouse/
11
+
12
+ # scikit-build-core / CMake outputs
13
+ _skbuild/
14
+ CMakeFiles/
15
+ CMakeCache.txt
16
+ cmake_install.cmake
17
+ compile_commands.json
18
+
19
+ # Test and coverage artifacts
20
+ .pytest_cache/
21
+ .coverage
22
+ htmlcov/
23
+
24
+ # Local virtual environments
25
+ .venv/
26
+ venv/
27
+
28
+ # Data
29
+ *.h5
30
+ *.npz
31
+
32
+ CLAUDE.md
33
+ pypi-release.txt
@@ -0,0 +1,212 @@
1
+ # AGENTS.md — bioimage-cpp
2
+
3
+ A small C++/Python package for bioimage-analysis algorithms that are otherwise hard to install. Goal: reliable PyPI wheels with a minimal dependency footprint. Not a compatibility layer for `nifty`/`vigra`/`affogato`, and not a full reimplementation — a focused implementation of selected functionality.
4
+
5
+ ## Core principles
6
+
7
+ - Easy to build, easy to ship on PyPI.
8
+ - C++20 standard library only. Avoid template-heavy libraries and external binary dependencies.
9
+ - NumPy at the Python boundary; lightweight C++ array views internally.
10
+ - Keep I/O outside the C++ core (TIFF/HDF5/zarr/N5/OME-NGFF belong in Python).
11
+ - Keep the C++ algorithmic core independent of Python, NumPy, and nanobind — nanobind only in the binding layer.
12
+ - Explicit, narrow APIs. No compatibility namespaces for older libraries.
13
+
14
+ ## Build & test
15
+
16
+ ```bash
17
+ pip install -e . --no-build-isolation # editable build (rebuilds C++)
18
+ python -m pytest tests/ -q # full Python test suite
19
+ ```
20
+
21
+ Required in the environment: `scikit-build-core`, `cmake>=3.21`, `ninja`, `nanobind`, `numpy`, `pytest`. The build produces one extension module: `bioimage_cpp._core`. Development scripts under `development/` compare against external references (nifty, affogato); they are not part of the test suite and must not be required by `pytest`.
22
+
23
+ ## Reuse existing helpers — do not duplicate
24
+
25
+ Before introducing union-finds, priority queues, edge hashing, stride math, threading helpers, or label relabeling, check `include/bioimage_cpp/detail/`:
26
+
27
+ - `detail/union_find.hxx` — `UnionFind` (path compression + union by rank). `find`, `merge`, `merge_to`, `unite_roots`.
28
+ - `detail/indexed_heap.hxx` — addressable max-heap with mutable priorities. `DenseIndexedHeap` (vector-backed locator, integer keys in `[0, N)`) and `SparseIndexedHeap` (hashmap-backed, arbitrary keys).
29
+ - `detail/edge_hash.hxx` — `Edge`, `edge_key`, `EdgeHash` for hashing unordered node pairs.
30
+ - `detail/grid.hxx` — `c_order_strides`, `valid_offset_target`, `is_valid_grid_edge` for row-major grid offsets.
31
+ - `detail/relabel.hxx` — `dense_relabel` to map arbitrary labels onto `[0, k)` preserving first-occurrence order.
32
+ - `detail/threading.hxx` — `normalize_thread_count`, `parallel_for_chunks(n_threads, n_items, chunk)`.
33
+
34
+ If a needed helper does not exist but is generally useful, add it to `detail/` as a header-only utility with a focused API rather than inlining it into one algorithm. Keep the contract small and well-documented; over time `detail/` is what lets multiple modules stay small and consistent.
35
+
36
+ ## Reusable algorithmic infrastructure
37
+
38
+ Some larger pieces of infrastructure sit above `detail/` but are still
39
+ intended to be reused across objective types. Check these before starting a
40
+ new fusion-move / proposal-based / contraction-based solver:
41
+
42
+ - `include/bioimage_cpp/graph/detail/fusion_contract.hxx` — objective-agnostic
43
+ agreement-projection primitive. `contract_by_agreement(graph, proposals,
44
+ n_proposals, ...)` returns `{contracted_graph, contracted_edge_of_original,
45
+ root_of_node}`. Already supports N ≥ 1 proposals; reused by both pairwise
46
+ and joint multi-proposal fuses.
47
+ - `include/bioimage_cpp/graph/proposal_generator.hxx` — `ProposalGeneratorBase`
48
+ abstract class. Concrete generators (Watershed, GreedyAdditiveMulticut) live
49
+ in `proposal_generators/` and depend only on `(graph, edge_costs)` plus an
50
+ RNG seed. They emit `std::vector<std::uint64_t>` node labelings and are
51
+ therefore reusable across multicut, lifted multicut, mincut, etc.
52
+ - `include/bioimage_cpp/graph/multicut/greedy_additive.hxx` — exposes
53
+ `GreedyAdditiveWorkspace` so multiple invocations on different graphs
54
+ share scratch buffers. Use this pattern (workspace + `reset(graph)`) when
55
+ a fusion-move driver calls a sub-solver inside its iteration loop.
56
+ - `UndirectedGraph::from_sorted_unique_edges(N, edges, populate_lookup=false)`
57
+ — bulk graph construction without the per-edge hash insertion in
58
+ `insert_edge`. Pair with `populate_lookup=false` when the consumer only
59
+ walks edges / adjacency (the multicut sub-solvers do).
60
+ - `detail/threading.hxx::parallel_for_chunks` — the only threading primitive
61
+ we use. New parallel solvers should not introduce alternatives.
62
+
63
+ When porting fusion moves to a new objective (e.g. lifted multicut):
64
+
65
+ 1. The driver loop in `multicut/fusion_move.hxx::FusionMoveSolver::optimize`
66
+ is short and dense. Duplicate it for the new objective rather than
67
+ abstracting it via a template/CRTP base — the moving parts (cost
68
+ aggregation, energy evaluator, sub-solver type) are objective-specific
69
+ and template gymnastics buy little.
70
+ 2. Reuse `contract_by_agreement` unchanged; it operates on the *base* graph
71
+ only.
72
+ 3. Write a new `fuse_multi(...)` that aggregates *both* base and lifted (or
73
+ other auxiliary) weights through `contraction.contracted_edge_of_original`
74
+ and `contraction.root_of_node`, calls the new objective's sub-solver, and
75
+ lifts labels back via `root_of_node`.
76
+ 4. Reuse the existing `WatershedProposalGenerator` and
77
+ `GreedyAdditiveMulticutProposalGenerator` verbatim; they only depend on
78
+ the base graph + base costs and emit node labelings. Add objective-specific
79
+ generators (e.g. `GreedyAdditiveLiftedMulticutProposalGenerator`) only if a
80
+ meaningful new proposal strategy emerges.
81
+ 5. Reuse the per-thread parallel pattern from `optimize`: stage-1 parallel
82
+ proposal generation + parallel pairwise fuse, stage-2 sequential joint
83
+ multi-fuse on leftover candidates. Per-thread `GreedyAdditiveWorkspace`
84
+ becomes per-thread `<NewObjective>Workspace` if the new sub-solver follows
85
+ the same pattern.
86
+
87
+ ## Dependencies
88
+
89
+ **Allowed**: C++20 stdlib, `nanobind`, `numpy`, `scikit-build-core`, `cmake`, `pytest`, `cibuildwheel` (CI only).
90
+
91
+ **Avoid in the core package** (require strong justification + wheel impact analysis): `xtensor`, `Boost.Python`, `pybind11`, `vigra`, `nifty`, HDF5, z5/N5, libtiff/libpng/libjpeg, OpenEXR, FFTW, heavy solver libraries, conda-only packages, and unguarded OpenMP. Isolate optional heavy features behind separate packages.
92
+
93
+ ## Repository layout
94
+
95
+ ```
96
+ include/bioimage_cpp/ public/semi-public C++ headers (header-only algorithms)
97
+ include/bioimage_cpp/detail/ shared header-only utilities (see above)
98
+ src/cpp/ non-templated C++ implementation files
99
+ src/bindings/ nanobind binding code only (module.cxx + per-module .cxx)
100
+ src/bioimage_cpp/ Python package
101
+ tests/ pytest suite, runs against the installed package
102
+ development/ reference comparisons — not required by tests
103
+ ```
104
+
105
+ Build system is `scikit-build-core` + CMake. Build one extension module (`bioimage_cpp._core`). Do not use `setup.py`-style builds. Do not enable nanobind `STABLE_ABI` while Python <3.12 is supported.
106
+
107
+ ## CMake guidelines
108
+
109
+ - C++20 throughout (`cxx_std_20`).
110
+ - Do not assume conda or system HDF5/TIFF/Boost.
111
+ - Do not enable `-march=native` in wheel builds.
112
+ - Use hidden symbol visibility where appropriate.
113
+ - Avoid platform-specific flags unless carefully guarded.
114
+
115
+ ## Wheel building
116
+
117
+ `cibuildwheel` in GitHub Actions. Targets: Linux x86_64 (manylinux), macOS x86_64 / arm64, Windows x86_64. Linux aarch64 once core wheels are stable.
118
+
119
+ - No conda dependency. No compiler required at install time.
120
+ - No external shared libraries unless bundled correctly and legally.
121
+ - Test the installed wheel — importability and core functions on small arrays.
122
+ - No `-march=native`, no unguarded OpenMP, no platform-specific assumptions.
123
+
124
+ ## Python API
125
+
126
+ Prefer functions: `bic.some_function(input_array, labels, ...)`. Avoid exposing complex C++ classes unless genuinely needed; if exposed, lifetime semantics must be obvious. No `vigra`/`nifty` compatibility namespace.
127
+
128
+ ## Array handling
129
+
130
+ - NumPy at the Python boundary, `ArrayView<T>` / `ConstArrayView<T>` internally. The view carries `data`, `shape`, `strides`, `ndim()` only.
131
+ - Algorithm code must not depend on Python, NumPy, or nanobind.
132
+ - C-contiguous in C++ kernels; Python wrappers convert with `np.ascontiguousarray` when copying is acceptable. Support for arbitrary strides, if any, must be intentional and tested.
133
+ - NumPy axis order throughout. For shape `(z, y, x)`, coordinates are reported as `(z, y, x)` unless explicitly documented otherwise.
134
+ - Define supported dtypes explicitly per function. Typical: label arrays `uint32/uint64/int32/int64`; image arrays `uint8/uint16/uint32/float32/float64`; stats outputs `float64`; index outputs `int64/uint64`. Use explicit dtype dispatch in the binding layer; avoid large template instantiation matrices.
135
+
136
+ ### Memory ownership
137
+
138
+ - Do not store raw pointers to array data past the call. Do not return views into temporaries.
139
+ - Prefer returning newly allocated arrays. For in-place outputs, require writable arrays and document mutation.
140
+ - If nanobind wraps memory owned by C++, attach an explicit capsule/owner so lifetimes are correct.
141
+
142
+ ### GIL
143
+
144
+ Release the GIL only after all Python-object validation and metadata extraction:
145
+
146
+ ```cpp
147
+ { nb::gil_scoped_release release; run_algorithm(...); }
148
+ ```
149
+
150
+ Do not touch Python objects while the GIL is released.
151
+
152
+ ### Error handling
153
+
154
+ Throw `std::invalid_argument` / `std::runtime_error` from C++; nanobind translates them to Python exceptions. Messages must name the argument and report expected vs. actual shape/dtype. Example: `labels must have ndim >= 2, got ndim=1`.
155
+
156
+ ## Binding layer
157
+
158
+ The binding layer (and only the binding layer) validates `nanobind::ndarray` inputs — dimensionality, dtype (or convert), writability for outputs, shape compatibility, C-contiguity when required — converts metadata into `ArrayView`, allocates outputs, dispatches to the right template instantiation, and releases the GIL. Do not pass `nanobind::ndarray` or other nanobind types into algorithm code. Use `namespace nb = nanobind;` at the top of binding files. Prefer readable, explicit binding code over overly generic templates.
159
+
160
+ ## Testing
161
+
162
+ Tests run against the installed Python package. For each public function, cover: small 2D / small 3D arrays, nontrivial labels, background-label handling, dtype variants, non-contiguous inputs (if accepted), invalid shapes, invalid dtypes, empty/degenerate inputs, and deterministic behavior. Reference comparisons against `nifty`/`affogato` are useful during development but must not be required by the default test suite, wheel tests, or source builds.
163
+
164
+ ## Coding style
165
+
166
+ **C++**: clear, boring C++20. Small functions over template-heavy abstractions. `std::vector`/`std::array`/`std::span` where appropriate. Explicit integer types when overflow matters; careful with signed/unsigned conversions for shapes, strides, labels. Avoid clever metaprogramming.
167
+
168
+ **Python**: thin wrappers. Validate user-facing arguments in Python when this improves error messages. Use NumPy for lightweight preprocessing only. Avoid dependencies for small conveniences.
169
+
170
+ ## Performance
171
+
172
+ Correct first, fast second. Benchmark before adding complexity. Prefer algorithmic improvements over build-level tweaks. Release the GIL for expensive kernels. Add threading only after the single-threaded implementation is stable; it must be portable and user-controllable.
173
+
174
+ ### Profiling
175
+
176
+ Measure before optimizing. The codebase carries a lightweight per-phase profiling utility for exactly this:
177
+
178
+ - Header: `include/bioimage_cpp/detail/profile.hxx`. Macros: `BIOIMAGE_PROFILE_INIT(name)`, `BIOIMAGE_PROFILE_SCOPE(name, "label")`, `BIOIMAGE_PROFILE_REPORT(name)`.
179
+ - Gated behind the `BIOIMAGE_PROFILE` compile-time flag. Outside of profile builds the macros expand to no-ops and a `NullProfiler` stub so the same code compiles unchanged.
180
+ - Enable via CMake option: `pip install -e . --no-build-isolation -C cmake.define.BIOIMAGE_PROFILE=ON`. Rebuild without the flag for production work.
181
+ - Reports per-phase wall-clock totals to stderr at the end of the instrumented scope (e.g., at the end of `optimize`). Same labels accumulate across multiple invocations of the scope (e.g., per-iteration phases).
182
+
183
+ Workflow when adding or chasing a performance issue:
184
+
185
+ 1. **Compare standalone primitives first** (`development/.../check_*.py` scripts vs. nifty). If a primitive is already fast, the gap is elsewhere — don't optimize it speculatively.
186
+ 2. **Instrument the suspect function** by wrapping each logical phase in a `BIOIMAGE_PROFILE_SCOPE`. Pick labels that map to one operation each ("agreement_contract", "sub_solve", "energy_eval", ...), not full call paths.
187
+ 3. **Build with `BIOIMAGE_PROFILE=ON` and run a realistic problem** — typically the external multicut instance loaded by the comparison scripts. Run with `--repeats 1` so the report isn't drowned out.
188
+ 4. **Optimize the largest phase** (50% phase beats two 10% phases combined). Re-measure after each change; verify no other phase regressed.
189
+ 5. **Strip the instrumentation when done** only if it adds clutter; otherwise leave it in place — it's free when the flag is off.
190
+
191
+ Don't add `std::chrono` snippets ad hoc; use the existing macros so future profiling sessions land in a consistent format.
192
+
193
+ ## Documentation
194
+
195
+ Update `MIGRATION_GUIDE.md` whenever public functionality changes, so users migrating from `nifty`/`affogato` see the corresponding `bioimage-cpp` API, behavioral differences, and intentional improvements.
196
+
197
+ The documentation is build via pdoc, see `.github/workflow/docs.yaml`.
198
+
199
+ ## Checklist when modifying code
200
+
201
+ 1. Reuse existing `detail/` helpers; add new shared ones rather than duplicating.
202
+ 2. Keep the build dependency-light. No external C++ dependencies without strong justification.
203
+ 3. Algorithm code stays separate from binding code. nanobind only in the binding layer.
204
+ 4. Validate arrays at the binding boundary.
205
+ 5. Use internal array views — not external multidim-array libraries.
206
+ 6. Tests for new behavior; tests run against the installed package.
207
+ 7. Preserve PyPI wheel portability — no conda, no system libraries, no compiler at install time.
208
+ 8. Clear error messages over permissive behavior.
209
+ 9. No I/O format support in the C++ core.
210
+ 10. No compatibility namespaces for older libraries.
211
+
212
+ When in doubt, choose the simpler design that is easier to build, test, and ship as wheels.
@@ -0,0 +1,40 @@
1
+ cmake_minimum_required(VERSION 3.21)
2
+ project(bioimage_cpp LANGUAGES CXX)
3
+
4
+ set(CMAKE_CXX_STANDARD 20)
5
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
+ set(CMAKE_CXX_EXTENSIONS OFF)
7
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
8
+
9
+ find_package(Python 3.10 COMPONENTS Interpreter Development.Module REQUIRED)
10
+ find_package(nanobind CONFIG REQUIRED)
11
+
12
+ nanobind_add_module(_core
13
+ NB_STATIC
14
+ src/bindings/affinities.cxx
15
+ src/bindings/blocking.cxx
16
+ src/bindings/module.cxx
17
+ src/bindings/filters.cxx
18
+ src/bindings/graph.cxx
19
+ src/bindings/ground_truth.cxx
20
+ src/bindings/segmentation.cxx
21
+ src/bindings/transformation.cxx
22
+ src/bindings/util.cxx
23
+ src/bindings/utils.cxx
24
+ src/cpp/segmentation/mutex_watershed.cxx
25
+ src/cpp/segmentation/semantic_mutex_watershed.cxx
26
+ src/cpp/take_dict.cxx
27
+ )
28
+
29
+ target_include_directories(_core PRIVATE include)
30
+ target_compile_features(_core PRIVATE cxx_std_20)
31
+ target_compile_options(_core PRIVATE
32
+ $<$<NOT:$<CONFIG:Debug>>:-O3>
33
+ )
34
+
35
+ option(BIOIMAGE_PROFILE "Enable per-phase profiling instrumentation (development only)" OFF)
36
+ if(BIOIMAGE_PROFILE)
37
+ target_compile_definitions(_core PRIVATE BIOIMAGE_PROFILE)
38
+ endif()
39
+
40
+ install(TARGETS _core LIBRARY DESTINATION bioimage_cpp)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bioimage-cpp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.