tfidf-stability 0.2.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 (223) hide show
  1. tfidf_stability-0.2.0/.clang-format +38 -0
  2. tfidf_stability-0.2.0/.editorconfig +26 -0
  3. tfidf_stability-0.2.0/.gitattributes +22 -0
  4. tfidf_stability-0.2.0/.gitignore +107 -0
  5. tfidf_stability-0.2.0/.pre-commit-config.yaml +89 -0
  6. tfidf_stability-0.2.0/.zenodo.json +29 -0
  7. tfidf_stability-0.2.0/CHANGELOG.md +81 -0
  8. tfidf_stability-0.2.0/CITATION.cff +47 -0
  9. tfidf_stability-0.2.0/CMakeLists.txt +72 -0
  10. tfidf_stability-0.2.0/CMakePresets.json +136 -0
  11. tfidf_stability-0.2.0/CONTRIBUTING.md +58 -0
  12. tfidf_stability-0.2.0/LICENSE.md +63 -0
  13. tfidf_stability-0.2.0/LICENSES/Apache-2.0.txt +73 -0
  14. tfidf_stability-0.2.0/LICENSES/BSD-3-Clause.txt +11 -0
  15. tfidf_stability-0.2.0/LICENSES/CC-BY-4.0.txt +156 -0
  16. tfidf_stability-0.2.0/LICENSES/MIT.txt +18 -0
  17. tfidf_stability-0.2.0/PKG-INFO +903 -0
  18. tfidf_stability-0.2.0/README.md +853 -0
  19. tfidf_stability-0.2.0/REUSE.toml +129 -0
  20. tfidf_stability-0.2.0/SECURITY.md +71 -0
  21. tfidf_stability-0.2.0/THIRD_PARTY_NOTICES.md +106 -0
  22. tfidf_stability-0.2.0/configs/ablations.yaml +48 -0
  23. tfidf_stability-0.2.0/configs/datasets.yaml +79 -0
  24. tfidf_stability-0.2.0/configs/default.yaml +65 -0
  25. tfidf_stability-0.2.0/configs/equivalent_mutants.txt +217 -0
  26. tfidf_stability-0.2.0/configs/equivalent_mutants_cpp.txt +98 -0
  27. tfidf_stability-0.2.0/configs/pipeline_digest.txt +32 -0
  28. tfidf_stability-0.2.0/cpp/CMakeLists.txt +132 -0
  29. tfidf_stability-0.2.0/cpp/bench/CMakeLists.txt +18 -0
  30. tfidf_stability-0.2.0/cpp/bench/bench_main.cpp +206 -0
  31. tfidf_stability-0.2.0/cpp/bindings/module.cpp +650 -0
  32. tfidf_stability-0.2.0/cpp/cmake/NumericsFlags.cmake +118 -0
  33. tfidf_stability-0.2.0/cpp/cmake/Sanitizers.cmake +32 -0
  34. tfidf_stability-0.2.0/cpp/cmake/Warnings.cmake +48 -0
  35. tfidf_stability-0.2.0/cpp/include/tfidf/core/build_config.hpp.in +26 -0
  36. tfidf_stability-0.2.0/cpp/include/tfidf/core/fp_guard.hpp +220 -0
  37. tfidf_stability-0.2.0/cpp/include/tfidf/core/reduction.hpp +276 -0
  38. tfidf_stability-0.2.0/cpp/include/tfidf/core/types.hpp +62 -0
  39. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/attributes.hpp +92 -0
  40. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/distances.hpp +391 -0
  41. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/margins.hpp +104 -0
  42. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/ranker.hpp +159 -0
  43. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/sort_keys.hpp +122 -0
  44. tfidf_stability-0.2.0/cpp/include/tfidf/ranking/tie_groups.hpp +182 -0
  45. tfidf_stability-0.2.0/cpp/include/tfidf/similarity/scoring.hpp +208 -0
  46. tfidf_stability-0.2.0/cpp/include/tfidf/vectorisation/sparse.hpp +270 -0
  47. tfidf_stability-0.2.0/cpp/tests/CMakeLists.txt +34 -0
  48. tfidf_stability-0.2.0/cpp/tests/main.cpp +2 -0
  49. tfidf_stability-0.2.0/cpp/tests/test_distances.cpp +514 -0
  50. tfidf_stability-0.2.0/cpp/tests/test_fp_guard.cpp +242 -0
  51. tfidf_stability-0.2.0/cpp/tests/test_ranking.cpp +748 -0
  52. tfidf_stability-0.2.0/cpp/tests/test_reduction.cpp +424 -0
  53. tfidf_stability-0.2.0/cpp/tests/test_scoring.cpp +669 -0
  54. tfidf_stability-0.2.0/cpp/third_party/MANIFEST.sha256 +2 -0
  55. tfidf_stability-0.2.0/cpp/third_party/doctest/doctest.h +7106 -0
  56. tfidf_stability-0.2.0/cpp/third_party/nanobench/nanobench.h +3484 -0
  57. tfidf_stability-0.2.0/data/README.md +95 -0
  58. tfidf_stability-0.2.0/data/assets/MANIFEST.sha256 +12 -0
  59. tfidf_stability-0.2.0/data/assets/stopwords_en_v1.txt +160 -0
  60. tfidf_stability-0.2.0/docs/experiments.md +132 -0
  61. tfidf_stability-0.2.0/docs/index.md +140 -0
  62. tfidf_stability-0.2.0/docs/main.pdf +0 -0
  63. tfidf_stability-0.2.0/docs/mathematical_formulation.md +143 -0
  64. tfidf_stability-0.2.0/docs/perturbation_notes.md +100 -0
  65. tfidf_stability-0.2.0/docs/ranking_stability.md +108 -0
  66. tfidf_stability-0.2.0/docs/spec_addenda.md +1427 -0
  67. tfidf_stability-0.2.0/docs/tie_breaking_discontinuities.md +152 -0
  68. tfidf_stability-0.2.0/examples/inspect_intermediates.py +440 -0
  69. tfidf_stability-0.2.0/examples/minimal_corpus_demo.py +382 -0
  70. tfidf_stability-0.2.0/examples/stability_certificate_demo.py +336 -0
  71. tfidf_stability-0.2.0/examples/tie_break_discontinuity_demo.py +319 -0
  72. tfidf_stability-0.2.0/notebooks/cosine_stability.ipynb +123 -0
  73. tfidf_stability-0.2.0/notebooks/idf_sensitivity.ipynb +121 -0
  74. tfidf_stability-0.2.0/notebooks/margin_distributions.ipynb +137 -0
  75. tfidf_stability-0.2.0/notebooks/pipeline_walkthrough.ipynb +155 -0
  76. tfidf_stability-0.2.0/notebooks/sanity_check.ipynb +203 -0
  77. tfidf_stability-0.2.0/notebooks/tie_break_ablation.ipynb +139 -0
  78. tfidf_stability-0.2.0/notebooks/tie_group_case_study.ipynb +163 -0
  79. tfidf_stability-0.2.0/pyproject.toml +252 -0
  80. tfidf_stability-0.2.0/reports/intermediates_d000000.json +180 -0
  81. tfidf_stability-0.2.0/reports/similarity.json +1037 -0
  82. tfidf_stability-0.2.0/reports/stability_profile.json +1664 -0
  83. tfidf_stability-0.2.0/reports/summary.md +190 -0
  84. tfidf_stability-0.2.0/reports/text/bibliography.bib +256 -0
  85. tfidf_stability-0.2.0/reports/text/main.tex +459 -0
  86. tfidf_stability-0.2.0/reports/tie_break_ablations.json +2371 -0
  87. tfidf_stability-0.2.0/requirements-dev.txt +53 -0
  88. tfidf_stability-0.2.0/requirements.txt +15 -0
  89. tfidf_stability-0.2.0/scripts/benchmark.py +92 -0
  90. tfidf_stability-0.2.0/scripts/build_corpus.py +85 -0
  91. tfidf_stability-0.2.0/scripts/check_cpp_format.py +99 -0
  92. tfidf_stability-0.2.0/scripts/check_dependencies.py +158 -0
  93. tfidf_stability-0.2.0/scripts/check_docs.py +390 -0
  94. tfidf_stability-0.2.0/scripts/check_layout.py +56 -0
  95. tfidf_stability-0.2.0/scripts/check_python_floor.py +109 -0
  96. tfidf_stability-0.2.0/scripts/check_test_vacuity.py +345 -0
  97. tfidf_stability-0.2.0/scripts/check_vendored.py +110 -0
  98. tfidf_stability-0.2.0/scripts/check_versions.py +168 -0
  99. tfidf_stability-0.2.0/scripts/export_intermediates.py +140 -0
  100. tfidf_stability-0.2.0/scripts/fetch_data.py +180 -0
  101. tfidf_stability-0.2.0/scripts/make_figures.py +1086 -0
  102. tfidf_stability-0.2.0/scripts/render_summary.py +503 -0
  103. tfidf_stability-0.2.0/scripts/run_similarity.py +134 -0
  104. tfidf_stability-0.2.0/scripts/run_stability_profile.py +408 -0
  105. tfidf_stability-0.2.0/scripts/run_tie_break_ablations.py +521 -0
  106. tfidf_stability-0.2.0/scripts/snapshot.py +227 -0
  107. tfidf_stability-0.2.0/src/tfidf_stability/__init__.py +18 -0
  108. tfidf_stability-0.2.0/src/tfidf_stability/_native/__init__.py +166 -0
  109. tfidf_stability-0.2.0/src/tfidf_stability/analysis/__init__.py +29 -0
  110. tfidf_stability-0.2.0/src/tfidf_stability/analysis/noise_floor.py +374 -0
  111. tfidf_stability-0.2.0/src/tfidf_stability/analysis/query_grid.py +262 -0
  112. tfidf_stability-0.2.0/src/tfidf_stability/analysis/stability_profile.py +306 -0
  113. tfidf_stability-0.2.0/src/tfidf_stability/analysis/stratify.py +192 -0
  114. tfidf_stability-0.2.0/src/tfidf_stability/analysis/summarise.py +222 -0
  115. tfidf_stability-0.2.0/src/tfidf_stability/analysis/tie_break_ablations.py +201 -0
  116. tfidf_stability-0.2.0/src/tfidf_stability/benchmarks/__init__.py +1 -0
  117. tfidf_stability-0.2.0/src/tfidf_stability/benchmarks/tfidf_perf.py +838 -0
  118. tfidf_stability-0.2.0/src/tfidf_stability/cli/__init__.py +1 -0
  119. tfidf_stability-0.2.0/src/tfidf_stability/cli/commands.py +541 -0
  120. tfidf_stability-0.2.0/src/tfidf_stability/cli/main.py +144 -0
  121. tfidf_stability-0.2.0/src/tfidf_stability/datasets/__init__.py +1 -0
  122. tfidf_stability-0.2.0/src/tfidf_stability/datasets/loaders.py +193 -0
  123. tfidf_stability-0.2.0/src/tfidf_stability/datasets/movielens.py +313 -0
  124. tfidf_stability-0.2.0/src/tfidf_stability/datasets/synthetic.py +446 -0
  125. tfidf_stability-0.2.0/src/tfidf_stability/persistence/__init__.py +36 -0
  126. tfidf_stability-0.2.0/src/tfidf_stability/persistence/manifest.py +195 -0
  127. tfidf_stability-0.2.0/src/tfidf_stability/persistence/model.py +99 -0
  128. tfidf_stability-0.2.0/src/tfidf_stability/persistence/save_load.py +552 -0
  129. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/__init__.py +54 -0
  130. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/corpus_edits.py +166 -0
  131. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/experiments.py +165 -0
  132. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/idf_perturb.py +181 -0
  133. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/score_bounds.py +203 -0
  134. tfidf_stability-0.2.0/src/tfidf_stability/perturbation/vector_perturb.py +216 -0
  135. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/__init__.py +1 -0
  136. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/_snowball/MANIFEST.sha256 +6 -0
  137. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/_snowball/__init__.py +33 -0
  138. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/_snowball/among.py +12 -0
  139. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/_snowball/basestemmer.py +280 -0
  140. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/_snowball/english_stemmer.py +676 -0
  141. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/lemmatise.py +210 -0
  142. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/ngrams.py +118 -0
  143. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/normalise.py +108 -0
  144. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/pipeline.py +352 -0
  145. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/stopwords.py +211 -0
  146. tfidf_stability-0.2.0/src/tfidf_stability/preprocessing/tokenise.py +108 -0
  147. tfidf_stability-0.2.0/src/tfidf_stability/profiles/__init__.py +37 -0
  148. tfidf_stability-0.2.0/src/tfidf_stability/profiles/query_modes.py +339 -0
  149. tfidf_stability-0.2.0/src/tfidf_stability/profiles/user_profile.py +302 -0
  150. tfidf_stability-0.2.0/src/tfidf_stability/ranking/__init__.py +95 -0
  151. tfidf_stability-0.2.0/src/tfidf_stability/ranking/attributes.py +479 -0
  152. tfidf_stability-0.2.0/src/tfidf_stability/ranking/distances.py +355 -0
  153. tfidf_stability-0.2.0/src/tfidf_stability/ranking/margins.py +215 -0
  154. tfidf_stability-0.2.0/src/tfidf_stability/ranking/ranker.py +321 -0
  155. tfidf_stability-0.2.0/src/tfidf_stability/ranking/sort_keys.py +160 -0
  156. tfidf_stability-0.2.0/src/tfidf_stability/ranking/tie_groups.py +364 -0
  157. tfidf_stability-0.2.0/src/tfidf_stability/similarity/__init__.py +1 -0
  158. tfidf_stability-0.2.0/src/tfidf_stability/similarity/cosine.py +107 -0
  159. tfidf_stability-0.2.0/src/tfidf_stability/similarity/geometry.py +208 -0
  160. tfidf_stability-0.2.0/src/tfidf_stability/similarity/scoring.py +379 -0
  161. tfidf_stability-0.2.0/src/tfidf_stability/types.py +69 -0
  162. tfidf_stability-0.2.0/src/tfidf_stability/utils/__init__.py +1 -0
  163. tfidf_stability-0.2.0/src/tfidf_stability/utils/hashing.py +125 -0
  164. tfidf_stability-0.2.0/src/tfidf_stability/utils/io.py +182 -0
  165. tfidf_stability-0.2.0/src/tfidf_stability/utils/logging.py +306 -0
  166. tfidf_stability-0.2.0/src/tfidf_stability/utils/numerics.py +377 -0
  167. tfidf_stability-0.2.0/src/tfidf_stability/utils/validation.py +245 -0
  168. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/__init__.py +1 -0
  169. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/df_counts.py +80 -0
  170. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/idf.py +168 -0
  171. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/sparse.py +237 -0
  172. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/tf.py +80 -0
  173. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/tfidf.py +250 -0
  174. tfidf_stability-0.2.0/src/tfidf_stability/vectorisation/vocabulary.py +299 -0
  175. tfidf_stability-0.2.0/tests/conftest.py +136 -0
  176. tfidf_stability-0.2.0/tests/fixtures/mini_corpus.jsonl +6 -0
  177. tfidf_stability-0.2.0/tests/fixtures/snowball/MANIFEST.sha256 +2 -0
  178. tfidf_stability-0.2.0/tests/fixtures/snowball/output.txt +42649 -0
  179. tfidf_stability-0.2.0/tests/fixtures/snowball/voc.txt +42649 -0
  180. tfidf_stability-0.2.0/tests/test_analysis_harness.py +1581 -0
  181. tfidf_stability-0.2.0/tests/test_benchmark_smoke.py +706 -0
  182. tfidf_stability-0.2.0/tests/test_canonical_bytes.py +927 -0
  183. tfidf_stability-0.2.0/tests/test_cli.py +1465 -0
  184. tfidf_stability-0.2.0/tests/test_cosine_edge_cases.py +700 -0
  185. tfidf_stability-0.2.0/tests/test_cpp_mutation_gate.py +431 -0
  186. tfidf_stability-0.2.0/tests/test_datasets.py +1569 -0
  187. tfidf_stability-0.2.0/tests/test_df_counts_oracle.py +193 -0
  188. tfidf_stability-0.2.0/tests/test_df_idf_correctness.py +865 -0
  189. tfidf_stability-0.2.0/tests/test_doc_references.py +253 -0
  190. tfidf_stability-0.2.0/tests/test_fuzz_parsers.py +335 -0
  191. tfidf_stability-0.2.0/tests/test_lemmatiser_backends.py +376 -0
  192. tfidf_stability-0.2.0/tests/test_logging.py +449 -0
  193. tfidf_stability-0.2.0/tests/test_margins_and_flip_radii.py +1132 -0
  194. tfidf_stability-0.2.0/tests/test_mutation_gate.py +876 -0
  195. tfidf_stability-0.2.0/tests/test_native_differential.py +463 -0
  196. tfidf_stability-0.2.0/tests/test_native_distances_differential.py +261 -0
  197. tfidf_stability-0.2.0/tests/test_native_ranking_differential.py +499 -0
  198. tfidf_stability-0.2.0/tests/test_native_selection.py +380 -0
  199. tfidf_stability-0.2.0/tests/test_ordering_distances.py +617 -0
  200. tfidf_stability-0.2.0/tests/test_packaged_assets.py +168 -0
  201. tfidf_stability-0.2.0/tests/test_persistence_roundtrip.py +976 -0
  202. tfidf_stability-0.2.0/tests/test_perturbation_bounds.py +1048 -0
  203. tfidf_stability-0.2.0/tests/test_perturbation_experiments.py +409 -0
  204. tfidf_stability-0.2.0/tests/test_preprocessing_determinism.py +1204 -0
  205. tfidf_stability-0.2.0/tests/test_profiles_and_loo.py +689 -0
  206. tfidf_stability-0.2.0/tests/test_public_api_surface.py +495 -0
  207. tfidf_stability-0.2.0/tests/test_query_grid_protocol.py +459 -0
  208. tfidf_stability-0.2.0/tests/test_ranking_tie_breaks.py +1698 -0
  209. tfidf_stability-0.2.0/tests/test_reduction_policies.py +905 -0
  210. tfidf_stability-0.2.0/tests/test_render_summary.py +180 -0
  211. tfidf_stability-0.2.0/tests/test_repository_gates.py +834 -0
  212. tfidf_stability-0.2.0/tests/test_reproducibility_snapshot.py +456 -0
  213. tfidf_stability-0.2.0/tests/test_scoring_kernels.py +603 -0
  214. tfidf_stability-0.2.0/tests/test_tfidf_sparse_ops.py +1040 -0
  215. tfidf_stability-0.2.0/tests/test_tie_break_ablations.py +587 -0
  216. tfidf_stability-0.2.0/tests/test_tie_groups_tau.py +883 -0
  217. tfidf_stability-0.2.0/tests/test_validation_contracts.py +450 -0
  218. tfidf_stability-0.2.0/tooling/__init__.py +11 -0
  219. tfidf_stability-0.2.0/tooling/allowlist.py +177 -0
  220. tfidf_stability-0.2.0/tooling/gate.py +32 -0
  221. tfidf_stability-0.2.0/tooling/mutation_cpp.py +472 -0
  222. tfidf_stability-0.2.0/tooling/mutation_python.py +512 -0
  223. tfidf_stability-0.2.0/tooling/renumber_allowlists.py +175 -0
@@ -0,0 +1,38 @@
1
+ ---
2
+ Language: Cpp
3
+ BasedOnStyle: LLVM
4
+ Standard: c++20
5
+
6
+ ColumnLimit: 100
7
+ IndentWidth: 4
8
+ TabWidth: 4
9
+ UseTab: Never
10
+
11
+ AccessModifierOffset: -4
12
+ AlignAfterOpenBracket: Align
13
+ AllowShortFunctionsOnASingleLine: Inline
14
+ AllowShortIfStatementsOnASingleLine: WithoutElse
15
+ AlwaysBreakTemplateDeclarations: Yes
16
+ BinPackArguments: false
17
+ BinPackParameters: false
18
+ BreakBeforeBraces: Attach
19
+ IndentPPDirectives: AfterHash
20
+ NamespaceIndentation: None
21
+ PointerAlignment: Left
22
+ SeparateDefinitionBlocks: Always
23
+ SpaceAfterTemplateKeyword: false
24
+
25
+ # Keep the public headers first, then the rest -- makes include cycles obvious.
26
+ SortIncludes: CaseSensitive
27
+ IncludeBlocks: Regroup
28
+ IncludeCategories:
29
+ - Regex: '^<tfidf/'
30
+ Priority: 1
31
+ - Regex: '^<nanobind/'
32
+ Priority: 2
33
+ - Regex: '^<doctest'
34
+ Priority: 3
35
+ - Regex: '^<'
36
+ Priority: 4
37
+ - Regex: '.*'
38
+ Priority: 5
@@ -0,0 +1,26 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+
10
+ [*.{py,pyi}]
11
+ indent_size = 4
12
+ max_line_length = 100
13
+
14
+ [*.{cpp,hpp,c,h,cc,cxx}]
15
+ indent_size = 4
16
+ max_line_length = 100
17
+
18
+ [*.{yaml,yml,json,toml}]
19
+ indent_size = 2
20
+
21
+ [*.{md,tex,bib}]
22
+ indent_size = 2
23
+ trim_trailing_whitespace = false
24
+
25
+ [Makefile]
26
+ indent_style = tab
@@ -0,0 +1,22 @@
1
+ # Normalise line endings so file hashes are platform-independent. This repository
2
+ # asserts byte-identical reproducibility across Linux, macOS and Windows, and CRLF
3
+ # drift would break every content hash in the manifests.
4
+ * text=auto eol=lf
5
+
6
+ # Binary artefacts must never be line-ending translated.
7
+ *.pdf binary
8
+ *.png binary
9
+ *.jpg binary
10
+ *.zip binary
11
+ *.pyd binary
12
+ *.so binary
13
+ *.dylib binary
14
+
15
+ # Fixtures and golden values are hashed byte-for-byte; pin them explicitly.
16
+ tests/fixtures/*.jsonl text eol=lf
17
+ tests/golden/*.json text eol=lf
18
+ data/assets/* text eol=lf
19
+ data/lexicon/* text eol=lf
20
+
21
+ # Notebooks diff poorly; mark them so GitHub collapses them in reviews.
22
+ *.ipynb linguist-documentation
@@ -0,0 +1,107 @@
1
+ # --- Python -----------------------------------------------------------------
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ .installed.cfg
7
+ dist/
8
+ sdist/
9
+ .venv/
10
+ venv/
11
+ env/
12
+ .python-version
13
+
14
+ # --- Test / type / lint caches ----------------------------------------------
15
+ .pytest_cache/
16
+ .hypothesis/
17
+ .mypy_cache/
18
+ .ruff_cache/
19
+ .coverage
20
+ .coverage.*
21
+ coverage.xml
22
+ htmlcov/
23
+ *.gcda
24
+ *.gcno
25
+ *.gcov
26
+
27
+ # --- CMake / native build ----------------------------------------------------
28
+ build/
29
+ # Every workflow builds into its own directory beside build/: build-tests,
30
+ # build-assert, build-bench, build-fastmath, build-asan, build-tsan. Only
31
+ # `build/` was ignored, so running any command from ci.yml or sanitizers.yml
32
+ # as documented left an untracked tree in `git status`.
33
+ build-*/
34
+ _skbuild/
35
+ CMakeUserPresets.json
36
+ compile_commands.json
37
+ *.o
38
+ *.obj
39
+ *.a
40
+ *.lib
41
+ *.exp
42
+ *.ilk
43
+ *.pdb
44
+
45
+ # Built extension modules land in the package tree; never commit them.
46
+ src/tfidf_stability/_native/*.pyd
47
+ src/tfidf_stability/_native/*.so
48
+ src/tfidf_stability/_native/*.dylib
49
+
50
+ # --- Data --------------------------------------------------------------------
51
+ # MovieLens may NOT be redistributed (see data/README.md). Fetched, never committed.
52
+ data/raw/
53
+ data/interim/
54
+ data/processed/
55
+ data/external/
56
+ !data/README.md
57
+ !data/assets/
58
+ !data/lexicon/
59
+
60
+ # Figures ARE committed. They are renderings, and matplotlib stamps its version
61
+ # into every PNG, so the bytes depend on the plotting library rather than on the
62
+ # result: two people regenerating from identical JSON get different files. That
63
+ # argued for keeping them out, and for a while they were.
64
+ #
65
+ # It was the wrong trade. reports/text/main.tex embeds seven of them, so a fresh
66
+ # clone built the report with seven "figure not generated" boxes, and the results
67
+ # were invisible to anyone reading the repository rather than running it. A
68
+ # figure nobody can see is worth less than a figure whose bytes are not
69
+ # reproducible. The JSON beside them is the reproducible artefact and the digest
70
+ # in each caption ties the image back to it, so the provenance claim survives.
71
+ #
72
+ # Consequence to know about: a regenerated PNG shows as modified whenever
73
+ # matplotlib changes, even with the underlying result identical. Check the digest
74
+ # in the caption, not the bytes.
75
+
76
+ reports/*.csv
77
+ !reports/text/
78
+
79
+ # The experiment JSON *is* committed, deliberately. A figure or a quoted number
80
+ # whose underlying data is absent from the tree is an assertion nobody can check,
81
+ # which is the one thing this repository is built not to be. Each file carries
82
+ # its own result digest and the provenance of the run that produced it, so a
83
+ # reader can regenerate it and compare rather than take it on trust.
84
+
85
+ # --- LaTeX -------------------------------------------------------------------
86
+ *.aux
87
+ *.bbl
88
+ *.blg
89
+ *.fdb_latexmk
90
+ *.fls
91
+ *.lof
92
+ *.log
93
+ *.lot
94
+ *.out
95
+ *.synctex.gz
96
+ *.toc
97
+ reports/text/*.pdf
98
+
99
+ # --- Notebooks ---------------------------------------------------------------
100
+ .ipynb_checkpoints/
101
+
102
+ # --- Editors / OS ------------------------------------------------------------
103
+ .vscode/
104
+ .idea/
105
+ *.swp
106
+ .DS_Store
107
+ Thumbs.db
@@ -0,0 +1,89 @@
1
+ # Local checks, mirroring the cheap half of ci.yml.
2
+ #
3
+ # Only the fast ones. A pre-commit hook that takes a minute gets
4
+ # bypassed with --no-verify, and a bypassed hook is worse than no hook: it
5
+ # trains the habit of skipping checks.
6
+
7
+ # The three rewriting hooks share one exclusion, defined on the first of them
8
+ # and referenced by the other two. Those files' bytes are the point:
9
+ # `scripts/check_vendored.py` verifies each against a recorded SHA-256, so a
10
+ # hook that rewrites one breaks the check that proves it is upstream code.
11
+
12
+ repos:
13
+ - repo: https://github.com/pre-commit/pre-commit-hooks
14
+ rev: v5.0.0
15
+ hooks:
16
+ - id: trailing-whitespace
17
+ # Two trailing spaces are a hard line break in Markdown. Stripping them
18
+ # reflows every paragraph that used one, which in README.md alone would
19
+ # silently rewrite 136 lines of rendered output.
20
+ args: [--markdown-linebreak-ext=md]
21
+ exclude: &verified_bytes >-
22
+ ^(cpp/third_party/|src/tfidf_stability/preprocessing/_snowball/|data/assets/|tests/fixtures/snowball/)
23
+ - id: end-of-file-fixer
24
+ exclude: *verified_bytes
25
+ - id: check-yaml
26
+ - id: check-toml
27
+ - id: check-added-large-files
28
+ args: [--maxkb=512]
29
+ - id: mixed-line-ending
30
+ args: [--fix=lf] # digests are taken over LF-normalised bytes
31
+ exclude: *verified_bytes
32
+
33
+ # ruff runs from the environment, not from a mirror pinned here.
34
+ #
35
+ # This used `astral-sh/ruff-pre-commit` at rev v0.7.4 while requirements-dev.txt
36
+ # pins ruff==0.16.2, so a contributor's hook and CI enforced two different
37
+ # linters nine minor versions apart -- and the newer one is strictly stricter.
38
+ # That is precisely the drift the exact pin exists to prevent: ruff 0.16
39
+ # stabilised PLR0917, which the tree had never been checked against, and the
40
+ # lint job failed on a commit that changed no Python at all. A local hook makes
41
+ # requirements-dev.txt the single place the version is stated.
42
+ #
43
+ # The cost is that `pre-commit` no longer installs ruff itself, so the hook
44
+ # needs the dev requirements present. That is already true of every other
45
+ # local hook here.
46
+ - repo: local
47
+ hooks:
48
+ - id: ruff
49
+ name: ruff (from requirements-dev.txt)
50
+ # `--force-exclude` is required, not optional. pre-commit passes explicit
51
+ # filenames, and ruff applies `extend-exclude` from pyproject.toml only
52
+ # to files it discovers itself -- so without this the hook lints and
53
+ # rewrites the vendored Snowball stemmer, breaking the SHA-256 that
54
+ # `scripts/check_vendored.py` verifies.
55
+ entry: python -m ruff check --force-exclude --fix
56
+ language: system
57
+ types_or: [python, pyi]
58
+ - id: ruff-format
59
+ name: ruff-format (from requirements-dev.txt)
60
+ # `--check`, not a rewrite. `ci.yml` gates on `ruff format --check`,
61
+ # so reporting here names the file before it reaches CI without mixing
62
+ # formatting churn into the diff being committed.
63
+ entry: python -m ruff format --force-exclude --check
64
+ language: system
65
+ types_or: [python, pyi]
66
+
67
+ - repo: local
68
+ hooks:
69
+ - id: vendored-digests
70
+ name: vendored assets match their manifests
71
+ # The provenance claims in THIRD_PARTY_NOTICES.md depend on this, and it
72
+ # is the one check that silently decays if left to CI alone.
73
+ entry: python scripts/check_vendored.py
74
+ language: system
75
+ pass_filenames: false
76
+ # Every directory holding a MANIFEST.sha256, which is what
77
+ # `check_vendored.py` discovers. `verified_bytes` above lists the same
78
+ # four, from the other side: these bytes are checked, so no hook may
79
+ # rewrite them.
80
+ files: ^(cpp/third_party/|src/tfidf_stability/preprocessing/_snowball/|data/assets/|tests/fixtures/snowball/)
81
+
82
+ - id: test-vacuity
83
+ name: no test passes without asserting anything
84
+ # Pure AST work over tests/, so it costs milliseconds and catches the
85
+ # guard-forgotten-on-a-new-test case at the moment it is written.
86
+ entry: python scripts/check_test_vacuity.py
87
+ language: system
88
+ pass_filenames: false
89
+ files: ^tests/.*\.py$
@@ -0,0 +1,29 @@
1
+ {
2
+ "title": "Numerical Stability and Perturbation Behaviour in TF-IDF-Based Similarity Systems",
3
+ "upload_type": "software",
4
+ "description": "<p>A self-contained implementation and analysis of a TF-IDF-based document similarity and ranking system, written to make the algebraic structure and perturbation behaviour of the pipeline explicit. The work treats ranking stability as a first-class object, characterising it through score-separation margin distributions, and isolates decision-level discontinuities introduced by deterministic tie-breaking rules.</p><p>It comprises a normative pure-Python reference implementation and a bit-identical optimised C++20 evaluator, whose equivalence is enforced by the test suite. Every published number is reproducible from a recorded pipeline digest.</p><p>The <code>license</code> field records the licence of the software. The prose, figures and generated reports are CC-BY-4.0; LICENSE.md sets out the split and REUSE.toml states it per file.</p>",
5
+ "creators": [
6
+ {
7
+ "name": "Miezaniec, Matthew Maksymilian",
8
+ "affiliation": "King's College London"
9
+ }
10
+ ],
11
+ "keywords": [
12
+ "TF-IDF",
13
+ "information retrieval",
14
+ "cosine similarity",
15
+ "numerical stability",
16
+ "perturbation analysis",
17
+ "ranking stability",
18
+ "reproducibility"
19
+ ],
20
+ "license": "Apache-2.0",
21
+ "access_right": "open",
22
+ "related_identifiers": [
23
+ {
24
+ "identifier": "https://github.com/Canon-Regularis/tfidf-stability-and-sensitivity",
25
+ "relation": "isSupplementTo",
26
+ "scheme": "url"
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+
3
+ Notable changes to this project, in [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
4
+ form. Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ Written by hand rather than generated. `release.yml` sets
7
+ `generate_release_notes: true`, which lists merged pull-request titles; this
8
+ repository's history is direct commits, so that list is close to empty and says
9
+ nothing about what moved. A published number changing is the thing a reader of
10
+ this project needs told, and no commit log states it.
11
+
12
+ **Every entry that moves a published number names the digest it moved to.** The
13
+ recorded values live in `configs/pipeline_digest.txt` and in each
14
+ `reports/*.json`, and `scripts/snapshot.py --check` is what compares them.
15
+
16
+ ## [Unreleased]
17
+
18
+ No tag has been cut yet, so everything below is the content of the first
19
+ release. The declared version is 0.2.0, and `scripts/check_versions.py --tag
20
+ v0.2.0` is what holds the tag and the four files that state it together.
21
+
22
+ ### Added
23
+
24
+ - `wheels.yml` and the reusable `build-wheels.yml`: the wheel build now runs
25
+ nightly, and on any push or pull request touching `cpp/**`, `CMakeLists.txt`,
26
+ `CMakePresets.json` or the build workflows, rather than only on a release
27
+ tag. The push trigger matters because this repository's history is direct
28
+ commits. The nightly run also builds cp314, which no release ships until a
29
+ nightly has produced it.
30
+ - `codeql.yml`: static analysis for `python` and `c-cpp`, the latter built
31
+ through the `ci` preset so the flags analysed are the flags shipped.
32
+ - `SECURITY.md`, and `REUSE.toml` giving the Apache-2.0 / CC-BY-4.0 split a
33
+ machine-readable form. `reuse lint` runs as the ninth repository gate.
34
+ - `reports/summary.md`, generated from the committed reports by
35
+ `scripts/render_summary.py`, with a `--check` mode that fails when the two
36
+ disagree.
37
+ - A TestPyPI rehearsal that blocks `publish`, build-provenance attestations over
38
+ the release assets, a CycloneDX SBOM generated from a clean runtime
39
+ environment, and recorded SHA-256 digests for everything published.
40
+
41
+ ### Changed
42
+
43
+ - `release.yml`: the `wheels` matrix now `needs: [sdist]`, so the tag-versus-
44
+ declared-version check stops the build before three platforms run rather than
45
+ only blocking publication.
46
+ - The wheel now carries `LICENSES/BSD-3-Clause.txt` and
47
+ `THIRD_PARTY_NOTICES.md`. The vendored Snowball stemmer is BSD-3-Clause and
48
+ nanobind is statically linked into the extension, so both the licence text
49
+ and the copyright notices it requires go out with the package.
50
+ - `THIRD_PARTY_NOTICES.md` records nanobind as linked into the distributed
51
+ package rather than as a build-time dependency, which is what
52
+ `nanobind_add_module(... NB_STATIC ...)` makes it.
53
+ - `REUSE.toml` names the vendored files individually. The three generated
54
+ Snowball modules and the two test vectors are BSD-3-Clause; the `__init__.py`
55
+ and the `MANIFEST.sha256` beside them are first-party and stay Apache-2.0.
56
+ Each upstream holder is recorded as a separate copyright statement, so the
57
+ generated SPDX document attributes the years correctly.
58
+ - Report payloads use one key per concept: `is_exact_tie` everywhere,
59
+ `E1_excluded_undefined` for what it counts, `trajectory_seed` distinct from
60
+ the run seed, and document ids rather than candidate indices.
61
+ `intermediates_*.json` gained the envelope its siblings carry, so it can be
62
+ identity-checked for the first time.
63
+ - The seven figures are one visual system: a shared style, a palette in which a
64
+ colour means one thing throughout, and a stamp grammar that is the same on
65
+ each. A measured zero is now drawn as a zero rather than as an absent bar.
66
+
67
+ ### Fixed
68
+
69
+ - `ruff check --fix` was rewriting the vendored Snowball stemmer through
70
+ pre-commit and breaking the SHA-256 that `scripts/check_vendored.py` verifies.
71
+ `extend-exclude` does not apply to filenames passed explicitly, which is what
72
+ pre-commit does; both ruff hooks now pass `--force-exclude`.
73
+ - The `vendored-digests` hook did not select `data/assets/`, so a change to a
74
+ hashed asset did not run the check that verifies it.
75
+ - The figures carried provenance stamps naming result digests that no longer
76
+ existed, because `reports/*.json` was regenerated without re-rendering them.
77
+ - The mutation sandbox did not copy `CMakePresets.json`, `.github`,
78
+ `requirements-dev.txt` or `reports/`, so a suite that reads any of them failed
79
+ the campaign baseline before a mutant was applied.
80
+
81
+ [Unreleased]: https://github.com/Canon-Regularis/tfidf-stability-and-sensitivity/commits/main
@@ -0,0 +1,47 @@
1
+ cff-version: 1.2.0
2
+ title: >-
3
+ Numerical Stability and Perturbation Behaviour in TF-IDF-Based
4
+ Similarity Systems
5
+ message: If you use this software or its results, please cite it.
6
+ type: software
7
+ authors:
8
+ - given-names: Matthew Maksymilian
9
+ family-names: Miezaniec
10
+ email: matthewmiezaniec1@gmail.com
11
+ affiliation: King's College London
12
+ repository-code: >-
13
+ https://github.com/Canon-Regularis/tfidf-stability-and-sensitivity
14
+ abstract: >-
15
+ A self-contained implementation and analysis of a TF-IDF-based document
16
+ similarity and ranking system, written to make the algebraic structure and
17
+ perturbation behaviour of the pipeline explicit. The work treats ranking
18
+ stability as a first-class object, characterising it through score-separation
19
+ margin distributions, and isolates decision-level discontinuities introduced
20
+ by deterministic tie-breaking rules. It comprises a normative pure-Python
21
+ reference implementation and a bit-identical optimised C++20 evaluator, whose
22
+ equivalence is enforced by the test suite.
23
+ keywords:
24
+ - TF-IDF
25
+ - information retrieval
26
+ - cosine similarity
27
+ - numerical stability
28
+ - perturbation analysis
29
+ - ranking stability
30
+ - reproducibility
31
+ license:
32
+ - Apache-2.0
33
+ - CC-BY-4.0
34
+ version: 0.2.0
35
+ # The date this version was released, not the date work began. It is checked
36
+ # against nothing, so it is the one field here that can drift silently; the git
37
+ # tag is the authority.
38
+ date-released: '2026-09-29'
39
+ # Filled in once Zenodo has minted one. Two DOIs exist: the concept DOI, which
40
+ # always resolves to the newest version, and a version DOI per release. The
41
+ # concept DOI belongs here, because a reader citing "this software" means the
42
+ # work rather than one snapshot of it.
43
+ #
44
+ # identifiers:
45
+ # - type: doi
46
+ # value: 10.5281/zenodo.XXXXXXX
47
+ # description: The concept DOI, resolving to the latest version.
@@ -0,0 +1,72 @@
1
+ # =============================================================================
2
+ # tfidf-stability, top-level build.
3
+ #
4
+ # The native backend is an OPTIONAL accelerator. The normative implementation is
5
+ # the pure-Python `reference` backend, which needs no compiler. Configure with
6
+ # -DTFIDF_BUILD_NATIVE=OFF for a fully functional reference-only install on a
7
+ # machine with no C++ toolchain.
8
+ # =============================================================================
9
+ cmake_minimum_required(VERSION 3.20)
10
+
11
+ project(tfidf_stability
12
+ VERSION 0.2.0
13
+ DESCRIPTION "Numerical stability and perturbation behaviour in TF-IDF similarity systems"
14
+ LANGUAGES CXX)
15
+
16
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cpp/cmake")
17
+
18
+ set(CMAKE_CXX_STANDARD 20)
19
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
20
+ set(CMAKE_CXX_EXTENSIONS OFF)
21
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
22
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
23
+
24
+ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
25
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
26
+ endif()
27
+
28
+ # -----------------------------------------------------------------------------
29
+ # Options
30
+ # -----------------------------------------------------------------------------
31
+ option(TFIDF_BUILD_NATIVE "Build the native (C++/nanobind) backend" ON)
32
+ option(TFIDF_BUILD_TESTS "Build the C++ unit-test binary" OFF)
33
+ option(TFIDF_BUILD_BENCH "Build the C++ microbenchmark binary" OFF)
34
+ option(TFIDF_WERROR "Treat compiler warnings as errors" OFF)
35
+
36
+ # NON-REPRODUCIBLE knobs. Both OFF for every published result. The manifest
37
+ # records their state and refuses to label a run reproducible when either is on.
38
+ option(TFIDF_ARCH_TUNE "Enable -march=native (NON-REPRODUCIBLE)" OFF)
39
+ option(TFIDF_FAST_MATH "Enable fast-math on purpose, to prove the numeric \
40
+ guard rails actually fire. Never use for results." OFF)
41
+
42
+ set(TFIDF_SANITIZERS "" CACHE STRING
43
+ "Semicolon/comma list of sanitizers, e.g. 'address;undefined' or 'thread'")
44
+
45
+ # enable_testing() has to be called from the TOP-LEVEL list file. Called deeper,
46
+ # CTest writes no root CTestTestfile.cmake and `ctest` reports "No tests were
47
+ # found" while still exiting 0.
48
+ if(TFIDF_BUILD_TESTS)
49
+ enable_testing()
50
+ endif()
51
+
52
+ add_subdirectory(cpp)
53
+
54
+ # -----------------------------------------------------------------------------
55
+ # Configuration summary. Printed so a build's numeric policy is never implicit.
56
+ # -----------------------------------------------------------------------------
57
+ message(STATUS "")
58
+ message(STATUS "=== tfidf-stability ${PROJECT_VERSION} =====================================")
59
+ message(STATUS " compiler : ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
60
+ message(STATUS " build type : ${CMAKE_BUILD_TYPE}")
61
+ message(STATUS " native backend : ${TFIDF_BUILD_NATIVE}")
62
+ message(STATUS " C++ tests : ${TFIDF_BUILD_TESTS}")
63
+ message(STATUS " benchmarks : ${TFIDF_BUILD_BENCH}")
64
+ message(STATUS " sanitizers : '${TFIDF_SANITIZERS}'")
65
+ if(TFIDF_ARCH_TUNE OR TFIDF_FAST_MATH)
66
+ message(STATUS " reproducible : *** NO *** (arch-tune=${TFIDF_ARCH_TUNE} \
67
+ fast-math=${TFIDF_FAST_MATH})")
68
+ else()
69
+ message(STATUS " reproducible : yes (strict IEEE-754, no FMA contraction)")
70
+ endif()
71
+ message(STATUS "==============================================================")
72
+ message(STATUS "")
@@ -0,0 +1,136 @@
1
+ {
2
+ "version": 6,
3
+ "cmakeMinimumRequired": { "major": 3, "minor": 25, "patch": 0 },
4
+ "configurePresets": [
5
+ {
6
+ "name": "base",
7
+ "hidden": true,
8
+ "generator": "Ninja",
9
+ "binaryDir": "${sourceDir}/build/${presetName}",
10
+ "cacheVariables": {
11
+ "CMAKE_BUILD_TYPE": "Release",
12
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
13
+ "TFIDF_BUILD_NATIVE": "ON",
14
+ "TFIDF_BUILD_TESTS": "ON",
15
+ "TFIDF_WERROR": "ON"
16
+ }
17
+ },
18
+ {
19
+ "name": "ci",
20
+ "inherits": "base",
21
+ "displayName": "The default build, with whatever compiler the runner provides"
22
+ },
23
+ {
24
+ "name": "mingw",
25
+ "inherits": "base",
26
+ "displayName": "MinGW-w64 UCRT (this project's reference Windows toolchain)",
27
+ "cacheVariables": { "CMAKE_CXX_COMPILER": "g++" },
28
+ "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" }
29
+ },
30
+ {
31
+ "name": "msvc",
32
+ "inherits": "base",
33
+ "displayName": "MSVC (requires the Visual Studio C++ workload)",
34
+ "cacheVariables": { "CMAKE_CXX_COMPILER": "cl" },
35
+ "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" }
36
+ },
37
+ {
38
+ "name": "gcc",
39
+ "inherits": "base",
40
+ "displayName": "GCC (Linux)",
41
+ "cacheVariables": { "CMAKE_CXX_COMPILER": "g++" }
42
+ },
43
+ {
44
+ "name": "clang",
45
+ "inherits": "base",
46
+ "displayName": "Clang",
47
+ "cacheVariables": { "CMAKE_CXX_COMPILER": "clang++" }
48
+ },
49
+
50
+ {
51
+ "name": "debug",
52
+ "inherits": "base",
53
+ "displayName": "Unoptimised -- must produce byte-identical results to release",
54
+ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
55
+ },
56
+ {
57
+ "name": "mutation",
58
+ "inherits": "base",
59
+ "displayName": "The baseline the nightly mutation campaign scores against",
60
+ "description": "Warnings are not errors here. A mutation deliberately writes code that trips one -- `< -> <=` makes a comparison always true, `+ -> -` converts a sign -- so under -Werror those mutants fail to compile and score `stillborn` instead of being scored against the tests. The C++ extension is off because the campaign's verdict is ctest alone.",
61
+ "cacheVariables": { "TFIDF_BUILD_NATIVE": "OFF", "TFIDF_WERROR": "OFF" }
62
+ },
63
+ {
64
+ "name": "glibcxx-assertions",
65
+ "inherits": "base",
66
+ "displayName": "Debug with libstdc++ bounds assertions armed",
67
+ "cacheVariables": {
68
+ "CMAKE_BUILD_TYPE": "Debug",
69
+ "CMAKE_CXX_FLAGS": "-D_GLIBCXX_ASSERTIONS"
70
+ }
71
+ },
72
+ {
73
+ "name": "asan",
74
+ "inherits": "base",
75
+ "displayName": "AddressSanitizer + UndefinedBehaviorSanitizer",
76
+ "cacheVariables": {
77
+ "CMAKE_BUILD_TYPE": "RelWithDebInfo",
78
+ "TFIDF_SANITIZERS": "address;undefined"
79
+ }
80
+ },
81
+ {
82
+ "name": "tsan",
83
+ "inherits": "base",
84
+ "displayName": "ThreadSanitizer (exercises the query-parallel path)",
85
+ "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo", "TFIDF_SANITIZERS": "thread" }
86
+ },
87
+ {
88
+ "name": "fastmath-guard-check",
89
+ "inherits": "base",
90
+ "displayName": "Deliberately unsound build -- CI asserts the guards REJECT it",
91
+ "cacheVariables": { "TFIDF_FAST_MATH": "ON" }
92
+ },
93
+ {
94
+ "name": "bench",
95
+ "inherits": "base",
96
+ "displayName": "Benchmarks (arch-tuned; NOT reproducible)",
97
+ "cacheVariables": {
98
+ "TFIDF_BUILD_BENCH": "ON",
99
+ "TFIDF_ARCH_TUNE": "ON",
100
+ "TFIDF_BUILD_TESTS": "OFF"
101
+ }
102
+ }
103
+ ],
104
+ "buildPresets": [
105
+ { "name": "ci", "configurePreset": "ci" },
106
+ { "name": "mingw", "configurePreset": "mingw" },
107
+ { "name": "msvc", "configurePreset": "msvc" },
108
+ { "name": "gcc", "configurePreset": "gcc" },
109
+ { "name": "clang", "configurePreset": "clang" },
110
+ { "name": "debug", "configurePreset": "debug" },
111
+ { "name": "mutation", "configurePreset": "mutation" },
112
+ { "name": "glibcxx-assertions", "configurePreset": "glibcxx-assertions" },
113
+ { "name": "asan", "configurePreset": "asan" },
114
+ { "name": "tsan", "configurePreset": "tsan" },
115
+ { "name": "bench", "configurePreset": "bench" },
116
+ { "name": "fastmath-guard-check", "configurePreset": "fastmath-guard-check" }
117
+ ],
118
+ "testPresets": [
119
+ {
120
+ "name": "base",
121
+ "hidden": true,
122
+ "output": { "outputOnFailure": true },
123
+ "execution": { "noTestsAction": "error", "stopOnFailure": false }
124
+ },
125
+ { "name": "ci", "inherits": "base", "configurePreset": "ci" },
126
+ { "name": "mingw", "inherits": "base", "configurePreset": "mingw" },
127
+ { "name": "msvc", "inherits": "base", "configurePreset": "msvc" },
128
+ { "name": "gcc", "inherits": "base", "configurePreset": "gcc" },
129
+ { "name": "clang", "inherits": "base", "configurePreset": "clang" },
130
+ { "name": "debug", "inherits": "base", "configurePreset": "debug" },
131
+ { "name": "mutation", "inherits": "base", "configurePreset": "mutation" },
132
+ { "name": "glibcxx-assertions", "inherits": "base", "configurePreset": "glibcxx-assertions" },
133
+ { "name": "asan", "inherits": "base", "configurePreset": "asan" },
134
+ { "name": "tsan", "inherits": "base", "configurePreset": "tsan" }
135
+ ]
136
+ }