natal-core 0.1.0.dev1__tar.gz → 0.1.0.dev2__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 (222) hide show
  1. natal_core-0.1.0.dev2/.github/copilot-instructions.md +55 -0
  2. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/.gitignore +2 -0
  3. natal_core-0.1.0.dev2/.python-version +1 -0
  4. natal_core-0.1.0.dev2/.readthedocs.yaml +15 -0
  5. natal_core-0.1.0.dev2/.vscode/settings.json +5 -0
  6. natal_core-0.1.0.dev2/AGENTS.md +63 -0
  7. natal_core-0.1.0.dev2/CHANGELOG.md +109 -0
  8. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/PKG-INFO +4 -2
  9. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/README.md +3 -1
  10. natal_core-0.1.0.dev2/TODO.md +20 -0
  11. natal_core-0.1.0.dev2/benchmarks/README.md +100 -0
  12. natal_core-0.1.0.dev2/benchmarks/benchmark_kernel_overhead.py +126 -0
  13. natal_core-0.1.0.dev2/benchmarks/benchmark_stages.py +44 -0
  14. natal_core-0.1.0.dev2/benchmarks/profile_numba_step_breakdown.py +321 -0
  15. natal_core-0.1.0.dev2/benchmarks/profile_random_modes.py +164 -0
  16. natal_core-0.1.0.dev2/benchmarks/profile_repro_direct.py +153 -0
  17. natal_core-0.1.0.dev2/benchmarks/profile_single_deme_repro.py +146 -0
  18. natal_core-0.1.0.dev2/benchmarks/profile_spatial_hex_run.py +49 -0
  19. natal_core-0.1.0.dev2/count_errors.py +59 -0
  20. natal_core-0.1.0.dev2/demos/discrete.py +74 -0
  21. natal_core-0.1.0.dev2/demos/discrete_ui.py +65 -0
  22. natal_core-0.1.0.dev2/demos/mosquito.py +103 -0
  23. natal_core-0.1.0.dev2/demos/mosquito_ui.py +105 -0
  24. natal_core-0.1.0.dev2/demos/spatial.py +153 -0
  25. natal_core-0.1.0.dev2/demos/spatial_hex.py +124 -0
  26. natal_core-0.1.0.dev2/demos/spatial_hex_discrete.py +130 -0
  27. natal_core-0.1.0.dev2/demos/spatial_hex_ui.py +116 -0
  28. natal_core-0.1.0.dev2/demos/spatial_ui.py +123 -0
  29. natal_core-0.1.0.dev2/docs/allele_conversion_rules.md +160 -0
  30. natal_core-0.1.0.dev2/docs/api/age_structured_population.md +13 -0
  31. natal_core-0.1.0.dev2/docs/api/algorithms.md +13 -0
  32. natal_core-0.1.0.dev2/docs/api/base_population.md +13 -0
  33. natal_core-0.1.0.dev2/docs/api/discrete_generation_population.md +15 -0
  34. natal_core-0.1.0.dev2/docs/api/genetic_entities.md +13 -0
  35. natal_core-0.1.0.dev2/docs/api/genetic_patterns.md +13 -0
  36. natal_core-0.1.0.dev2/docs/api/genetic_presets.md +15 -0
  37. natal_core-0.1.0.dev2/docs/api/genetic_structures.md +13 -0
  38. natal_core-0.1.0.dev2/docs/api/hook_dsl.md +13 -0
  39. natal_core-0.1.0.dev2/docs/api/index.md +27 -0
  40. natal_core-0.1.0.dev2/docs/api/modifiers.md +13 -0
  41. natal_core-0.1.0.dev2/docs/api/population_builder.md +13 -0
  42. natal_core-0.1.0.dev2/docs/api/population_config.md +14 -0
  43. natal_core-0.1.0.dev2/docs/api/population_state.md +13 -0
  44. natal_core-0.1.0.dev2/docs/api/simulation_kernels.md +13 -0
  45. natal_core-0.1.0.dev2/docs/api/state_translation.md +16 -0
  46. natal_core-0.1.0.dev2/docs/builder_system.md +420 -0
  47. natal_core-0.1.0.dev2/docs/en/.readthedocs.yaml +1 -0
  48. natal_core-0.1.0.dev2/docs/en/allele_conversion_rules.md +1 -0
  49. natal_core-0.1.0.dev2/docs/en/api/age_structured_population.md +1 -0
  50. natal_core-0.1.0.dev2/docs/en/api/algorithms.md +1 -0
  51. natal_core-0.1.0.dev2/docs/en/api/base_population.md +1 -0
  52. natal_core-0.1.0.dev2/docs/en/api/discrete_generation_population.md +1 -0
  53. natal_core-0.1.0.dev2/docs/en/api/genetic_entities.md +1 -0
  54. natal_core-0.1.0.dev2/docs/en/api/genetic_patterns.md +1 -0
  55. natal_core-0.1.0.dev2/docs/en/api/genetic_presets.md +1 -0
  56. natal_core-0.1.0.dev2/docs/en/api/genetic_structures.md +1 -0
  57. natal_core-0.1.0.dev2/docs/en/api/hook_dsl.md +1 -0
  58. natal_core-0.1.0.dev2/docs/en/api/index.md +1 -0
  59. natal_core-0.1.0.dev2/docs/en/api/modifiers.md +1 -0
  60. natal_core-0.1.0.dev2/docs/en/api/population_builder.md +1 -0
  61. natal_core-0.1.0.dev2/docs/en/api/population_config.md +1 -0
  62. natal_core-0.1.0.dev2/docs/en/api/population_state.md +1 -0
  63. natal_core-0.1.0.dev2/docs/en/api/simulation_kernels.md +1 -0
  64. natal_core-0.1.0.dev2/docs/en/api/state_translation.md +1 -0
  65. natal_core-0.1.0.dev2/docs/en/builder_system.md +1 -0
  66. natal_core-0.1.0.dev2/docs/en/genetic_presets.md +1 -0
  67. natal_core-0.1.0.dev2/docs/en/genetic_structures.md +1 -0
  68. natal_core-0.1.0.dev2/docs/en/genotype_filter.md +1 -0
  69. natal_core-0.1.0.dev2/docs/en/genotype_patterns.md +1 -0
  70. natal_core-0.1.0.dev2/docs/en/hooks.md +1 -0
  71. natal_core-0.1.0.dev2/docs/en/index.md +1 -0
  72. natal_core-0.1.0.dev2/docs/en/index_registry.md +1 -0
  73. natal_core-0.1.0.dev2/docs/en/modifiers.md +1 -0
  74. natal_core-0.1.0.dev2/docs/en/natal-brand.svg +1 -0
  75. natal_core-0.1.0.dev2/docs/en/numba_optimization.md +1 -0
  76. natal_core-0.1.0.dev2/docs/en/observation_rules.md +1 -0
  77. natal_core-0.1.0.dev2/docs/en/population_state_config.md +1 -0
  78. natal_core-0.1.0.dev2/docs/en/preset_encapsulation_and_validation.md +1 -0
  79. natal_core-0.1.0.dev2/docs/en/quickstart.md +1 -0
  80. natal_core-0.1.0.dev2/docs/en/simulation_kernels.md +1 -0
  81. natal_core-0.1.0.dev2/docs/en/spatial_simulation_guide.md +1 -0
  82. natal_core-0.1.0.dev2/docs/genetic_presets.md +515 -0
  83. natal_core-0.1.0.dev2/docs/genetic_structures.md +500 -0
  84. natal_core-0.1.0.dev2/docs/genotype_filter.md +136 -0
  85. natal_core-0.1.0.dev2/docs/genotype_patterns.md +149 -0
  86. natal_core-0.1.0.dev2/docs/hooks.md +185 -0
  87. natal_core-0.1.0.dev2/docs/index.md +88 -0
  88. natal_core-0.1.0.dev2/docs/index_registry.md +337 -0
  89. natal_core-0.1.0.dev2/docs/modifiers.md +212 -0
  90. natal_core-0.1.0.dev2/docs/natal-brand.svg +21246 -0
  91. natal_core-0.1.0.dev2/docs/numba_optimization.md +172 -0
  92. natal_core-0.1.0.dev2/docs/observation_rules.md +660 -0
  93. natal_core-0.1.0.dev2/docs/population_state_config.md +272 -0
  94. natal_core-0.1.0.dev2/docs/preset_encapsulation_and_validation.md +114 -0
  95. natal_core-0.1.0.dev2/docs/quickstart.md +468 -0
  96. natal_core-0.1.0.dev2/docs/requirements-rtd.txt +5 -0
  97. natal_core-0.1.0.dev2/docs/requirements-zh.txt +4 -0
  98. natal_core-0.1.0.dev2/docs/requirements.txt +4 -0
  99. natal_core-0.1.0.dev2/docs/simulation_kernels.md +222 -0
  100. natal_core-0.1.0.dev2/docs/spatial_simulation_guide.md +246 -0
  101. natal_core-0.1.0.dev2/docs/zh/.readthedocs.yaml +15 -0
  102. natal_core-0.1.0.dev2/docs/zh/allele_conversion_rules.md +160 -0
  103. natal_core-0.1.0.dev2/docs/zh/builder_system.md +420 -0
  104. natal_core-0.1.0.dev2/docs/zh/genetic_presets.md +509 -0
  105. natal_core-0.1.0.dev2/docs/zh/genetic_structures.md +500 -0
  106. natal_core-0.1.0.dev2/docs/zh/genotype_filter.md +136 -0
  107. natal_core-0.1.0.dev2/docs/zh/genotype_patterns.md +149 -0
  108. natal_core-0.1.0.dev2/docs/zh/hooks.md +185 -0
  109. natal_core-0.1.0.dev2/docs/zh/index.md +88 -0
  110. natal_core-0.1.0.dev2/docs/zh/index_registry.md +337 -0
  111. natal_core-0.1.0.dev2/docs/zh/modifiers.md +212 -0
  112. natal_core-0.1.0.dev2/docs/zh/natal-brand.svg +21246 -0
  113. natal_core-0.1.0.dev2/docs/zh/numba_optimization.md +173 -0
  114. natal_core-0.1.0.dev2/docs/zh/observation_rules.md +708 -0
  115. natal_core-0.1.0.dev2/docs/zh/population_state_config.md +272 -0
  116. natal_core-0.1.0.dev2/docs/zh/preset_encapsulation_and_validation.md +114 -0
  117. natal_core-0.1.0.dev2/docs/zh/quickstart.md +468 -0
  118. natal_core-0.1.0.dev2/docs/zh/simulation_kernels.md +222 -0
  119. natal_core-0.1.0.dev2/docs/zh/spatial_simulation_guide.md +246 -0
  120. natal_core-0.1.0.dev2/docstring_spec.md +293 -0
  121. natal_core-0.1.0.dev2/docstring_spec_cn.md +300 -0
  122. natal_core-0.1.0.dev2/example_google.py +296 -0
  123. natal_core-0.1.0.dev2/mkdocs.en.yml +121 -0
  124. natal_core-0.1.0.dev2/mkdocs.yml +121 -0
  125. natal_core-0.1.0.dev2/mkdocs.zh.yml +121 -0
  126. natal_core-0.1.0.dev2/natal-brand.svg +21246 -0
  127. natal_core-0.1.0.dev2/natal.svg +8647 -0
  128. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/pyproject.toml +4 -6
  129. natal_core-0.1.0.dev2/quality_checks_spec.md +196 -0
  130. natal_core-0.1.0.dev2/quality_checks_spec_cn.md +194 -0
  131. natal_core-0.1.0.dev2/scripts/check_docstring_fields.py +304 -0
  132. natal_core-0.1.0.dev2/scripts/cleanup_docs.py +62 -0
  133. natal_core-0.1.0.dev2/scripts/docstring_standardizer.py +262 -0
  134. natal_core-0.1.0.dev2/scripts/final_docstring_cleanup.py +233 -0
  135. natal_core-0.1.0.dev2/scripts/generate_api_docs.py +155 -0
  136. natal_core-0.1.0.dev2/scripts/generate_enhanced_api_docs.py +228 -0
  137. natal_core-0.1.0.dev2/scripts/generate_init_pyi.py +111 -0
  138. natal_core-0.1.0.dev2/scripts/normalize_docstrings.py +181 -0
  139. natal_core-0.1.0.dev2/src/natal/__init__.py +131 -0
  140. natal_core-0.1.0.dev2/src/natal/__init__.pyi +359 -0
  141. natal_core-0.1.0.dev2/src/natal/age_structured_population.py +787 -0
  142. natal_core-0.1.0.dev2/src/natal/algorithms.py +1475 -0
  143. natal_core-0.1.0.dev2/src/natal/base_population.py +1411 -0
  144. natal_core-0.1.0.dev2/src/natal/discrete_generation_population.py +423 -0
  145. natal_core-0.1.0.dev2/src/natal/gamete_allele_conversion.py +667 -0
  146. natal_core-0.1.0.dev2/src/natal/genetic_entities.py +1093 -0
  147. natal_core-0.1.0.dev2/src/natal/genetic_patterns.py +1028 -0
  148. natal_core-0.1.0.dev2/src/natal/genetic_presets.py +1342 -0
  149. natal_core-0.1.0.dev2/src/natal/genetic_structures.py +3342 -0
  150. natal_core-0.1.0.dev2/src/natal/helpers.py +45 -0
  151. natal_core-0.1.0.dev2/src/natal/hook_dsl.py +53 -0
  152. natal_core-0.1.0.dev2/src/natal/hooks/__init__.py +93 -0
  153. natal_core-0.1.0.dev2/src/natal/hooks/compiler.py +370 -0
  154. natal_core-0.1.0.dev2/src/natal/hooks/declarative.py +710 -0
  155. natal_core-0.1.0.dev2/src/natal/hooks/executor.py +610 -0
  156. natal_core-0.1.0.dev2/src/natal/hooks/selector.py +247 -0
  157. natal_core-0.1.0.dev2/src/natal/hooks/types.py +288 -0
  158. natal_core-0.1.0.dev2/src/natal/index_registry.py +600 -0
  159. natal_core-0.1.0.dev2/src/natal/kernels/__init__.py +2 -0
  160. natal_core-0.1.0.dev2/src/natal/kernels/codegen.py +170 -0
  161. natal_core-0.1.0.dev2/src/natal/kernels/simulation_kernels.py +519 -0
  162. natal_core-0.1.0.dev2/src/natal/kernels/spatial_simulation_kernels.py +1670 -0
  163. natal_core-0.1.0.dev2/src/natal/modifiers.py +547 -0
  164. natal_core-0.1.0.dev2/src/natal/numba_compat.py +460 -0
  165. natal_core-0.1.0.dev2/src/natal/numba_utils.py +718 -0
  166. natal_core-0.1.0.dev2/src/natal/observation.py +533 -0
  167. natal_core-0.1.0.dev2/src/natal/population_builder.py +1908 -0
  168. natal_core-0.1.0.dev2/src/natal/population_config.py +875 -0
  169. natal_core-0.1.0.dev2/src/natal/population_state.py +358 -0
  170. natal_core-0.1.0.dev2/src/natal/py.typed +0 -0
  171. natal_core-0.1.0.dev2/src/natal/simulation_kernels.py +30 -0
  172. natal_core-0.1.0.dev2/src/natal/spatial_population.py +695 -0
  173. natal_core-0.1.0.dev2/src/natal/spatial_simulation_kernels.py +29 -0
  174. natal_core-0.1.0.dev2/src/natal/spatial_topology.py +522 -0
  175. natal_core-0.1.0.dev2/src/natal/state_translation.py +543 -0
  176. natal_core-0.1.0.dev2/src/natal/type_def.py +121 -0
  177. natal_core-0.1.0.dev2/src/natal/ui/__init__.py +25 -0
  178. natal_core-0.1.0.dev2/src/natal/ui/dashboard.py +34 -0
  179. natal_core-0.1.0.dev2/src/natal/ui/dashboard_population.py +1366 -0
  180. natal_core-0.1.0.dev2/src/natal/ui/spatial_dashboard.py +975 -0
  181. natal_core-0.1.0.dev2/src/natal/visualization.py +110 -0
  182. natal_core-0.1.0.dev2/src/natal/zygote_allele_conversion.py +682 -0
  183. natal_core-0.1.0.dev2/tests/__init__.py +1 -0
  184. natal_core-0.1.0.dev2/tests/conftest.py +55 -0
  185. natal_core-0.1.0.dev2/tests/test_age_structured_population.py +150 -0
  186. natal_core-0.1.0.dev2/tests/test_bracket_patterns.py +129 -0
  187. natal_core-0.1.0.dev2/tests/test_corrected_sampling.py +53 -0
  188. natal_core-0.1.0.dev2/tests/test_discrete_builder_initial_state.py +113 -0
  189. natal_core-0.1.0.dev2/tests/test_discrete_population.py +194 -0
  190. natal_core-0.1.0.dev2/tests/test_genetic_entities.py +206 -0
  191. natal_core-0.1.0.dev2/tests/test_genetic_patterns.py +113 -0
  192. natal_core-0.1.0.dev2/tests/test_genetic_structures.py +189 -0
  193. natal_core-0.1.0.dev2/tests/test_helpers.py +97 -0
  194. natal_core-0.1.0.dev2/tests/test_hook_condition_interpreter.py +69 -0
  195. natal_core-0.1.0.dev2/tests/test_hook_deme_selector.py +108 -0
  196. natal_core-0.1.0.dev2/tests/test_hook_kernel_ops.py +272 -0
  197. natal_core-0.1.0.dev2/tests/test_hook_numba_strict_mode.py +131 -0
  198. natal_core-0.1.0.dev2/tests/test_improved_sampling.py +57 -0
  199. natal_core-0.1.0.dev2/tests/test_index_registry.py +145 -0
  200. natal_core-0.1.0.dev2/tests/test_packaging.py +12 -0
  201. natal_core-0.1.0.dev2/tests/test_pattern_comprehensive.py +264 -0
  202. natal_core-0.1.0.dev2/tests/test_pattern_omission_syntax.py +336 -0
  203. natal_core-0.1.0.dev2/tests/test_population_builder_fitness_patterns.py +259 -0
  204. natal_core-0.1.0.dev2/tests/test_population_builder_initial_injection.py +112 -0
  205. natal_core-0.1.0.dev2/tests/test_recipe_fitness_patch.py +106 -0
  206. natal_core-0.1.0.dev2/tests/test_recipe_species_binding.py +100 -0
  207. natal_core-0.1.0.dev2/tests/test_sampling_consistency.py +78 -0
  208. natal_core-0.1.0.dev2/tests/test_spatial_codegen_wrappers.py +40 -0
  209. natal_core-0.1.0.dev2/tests/test_spatial_dashboard.py +157 -0
  210. natal_core-0.1.0.dev2/tests/test_spatial_kernel_template_order.py +21 -0
  211. natal_core-0.1.0.dev2/tests/test_spatial_population_integration.py +198 -0
  212. natal_core-0.1.0.dev2/tests/test_spatial_population_run.py +419 -0
  213. natal_core-0.1.0.dev2/tests/test_spatial_population_structure.py +138 -0
  214. natal_core-0.1.0.dev2/tests/test_spatial_simulation_kernels.py +87 -0
  215. natal_core-0.1.0.dev2/tests/test_spatial_topology.py +166 -0
  216. natal_core-0.1.0.dev2/tests/test_state_translation.py +340 -0
  217. natal_core-0.1.0.dev2/tests/test_toxin_antidote_drive.py +399 -0
  218. natal_core-0.1.0.dev2/tests/test_type_def.py +100 -0
  219. natal_core-0.1.0.dev2/uv.lock +4370 -0
  220. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/LICENSE +0 -0
  221. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/src/natal/kernels/templates/kernel_wrappers.py.tmpl +0 -0
  222. {natal_core-0.1.0.dev1 → natal_core-0.1.0.dev2}/src/natal/kernels/templates/spatial_kernel_wrappers.py.tmpl +0 -0
@@ -0,0 +1,55 @@
1
+ # Copilot Workspace Instructions for NATAL Core
2
+
3
+ Apply these rules for all tasks in this repository.
4
+
5
+ ## Rule Priority
6
+
7
+ Use this priority order when rules overlap:
8
+ 1. docstring_spec.md
9
+ 2. quality_checks_spec.md
10
+ 3. docstring_spec_cn.md
11
+ 4. quality_checks_spec_cn.md
12
+ 5. AGENTS.md
13
+
14
+ ## Mandatory Validation
15
+
16
+ Before finalizing any code change, run and pass:
17
+ - pytest
18
+ - pyright
19
+ - ruff check src demos
20
+
21
+ If public exports changed, also run:
22
+ - python scripts/generate_init_pyi.py
23
+
24
+ ## Docstring Rules
25
+
26
+ - Follow Google style section names only.
27
+ - Keep docstring content in English.
28
+ - Ensure typed parameters, returns, and attributes.
29
+
30
+ ## Testing Rules
31
+
32
+ - Add or update tests for non-trivial behavior changes.
33
+ - Include boundary and error-path coverage when relevant.
34
+ - Prefer pytest-collected tests over script-style smoke tests.
35
+ - Keep tests deterministic.
36
+
37
+ ## Type and Lint Rules
38
+
39
+ - Avoid new implicit Any in modified code.
40
+ - Do not add # type: ignore unless necessary and justified.
41
+ - Do not add broad Ruff ignore rules.
42
+
43
+ ## Response Requirements
44
+
45
+ For implementation tasks, include:
46
+ - Changed files summary
47
+ - Behavior impact summary
48
+ - Validation commands executed
49
+ - Residual risks or follow-up items if any
50
+
51
+ ## Working Style
52
+
53
+ - Keep changes small and focused.
54
+ - Preserve existing behavior unless the task explicitly asks for behavior changes.
55
+ - Prefer minimal-scope refactors.
@@ -24,3 +24,5 @@ site/*
24
24
  .vscode/*
25
25
  !.vscode/settings.json
26
26
  !.vscode/extensions.json
27
+
28
+ .trae/*
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,15 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-24.04
5
+ tools:
6
+ python: "3.12"
7
+
8
+ python:
9
+ install:
10
+ - method: pip
11
+ path: .
12
+ - requirements: docs/requirements.txt
13
+
14
+ mkdocs:
15
+ configuration: mkdocs.en.yml
@@ -0,0 +1,5 @@
1
+ {
2
+ "files.trimTrailingWhitespace": true,
3
+ "python.analysis.autoImportCompletions": true,
4
+ "C_Cpp_Runner.msvcBatchPath": ""
5
+ }
@@ -0,0 +1,63 @@
1
+ # NATAL Core Agent Rules
2
+
3
+ This file defines default instructions for AI Agents working in this repository.
4
+ These rules are always-on at repository scope.
5
+
6
+ ## 1) Source of truth
7
+
8
+ Follow these documents in descending priority:
9
+ 1. docstring_spec.md
10
+ 2. quality_checks_spec.md
11
+ 3. docstring_spec_cn.md (Chinese explanation)
12
+ 4. quality_checks_spec_cn.md (Chinese explanation)
13
+
14
+ If rules conflict, prefer the English specification files.
15
+
16
+ ## 2) Mandatory quality gates before proposing completion
17
+
18
+ For code changes, run and pass all of the following:
19
+ - pytest
20
+ - pyright
21
+ - ruff check src demos
22
+
23
+ Activate the repository virtual environment before running `pyright` so it uses
24
+ the project-installed dependencies and configuration.
25
+
26
+ After those commands complete, review `docs/` for any needed documentation updates and apply them before finalizing the change.
27
+
28
+ If API exports changed, also run:
29
+ - python scripts/generate_init_pyi.py
30
+
31
+ ## 3) Docstring requirements
32
+
33
+ - Use Google style sections only.
34
+ - Keep docstring text in English.
35
+ - Ensure all parameters/returns/attributes are explicitly typed (annotation preferred).
36
+ - Do not invent section headers.
37
+
38
+ ## 4) Testing requirements
39
+
40
+ - Add or update tests for all non-trivial behavior changes.
41
+ - Cover happy path, boundaries, and error paths when relevant.
42
+ - Keep tests deterministic (fixed seeds for random behavior).
43
+ - Prefer pytest-collected tests over script-style smoke tests.
44
+
45
+ ## 5) Typing and linting requirements
46
+
47
+ - Do not introduce new implicit Any in modified code.
48
+ - Do not add # type: ignore unless absolutely necessary with a clear reason.
49
+ - Do not add broad Ruff ignores; keep exceptions minimal and documented.
50
+
51
+ ## 6) Change note requirements (human and AI)
52
+
53
+ Every change summary must include:
54
+ - Files changed
55
+ - Behavior changes
56
+ - Validation commands executed
57
+ - Residual risks or follow-up items (if any)
58
+
59
+ ## 7) Working mode for this repository
60
+
61
+ - Repository is mainly solo-maintained with occasional external contributions.
62
+ - Keep changes small and focused.
63
+ - Lightweight review is acceptable, but quality gates are never optional.
@@ -0,0 +1,109 @@
1
+ # Changelog
2
+
3
+ ## 🎉 2026.4.4.b - v0.0.0-beta released!
4
+ - Refactor sampling method naming from 'use_dirichlet_sampling' to 'use_continuous_sampling'
5
+
6
+ ## 2026.4.4
7
+ - feat(spatial): Add support for sparse CSR adjacency matrices and extend migration strategy (heterogenic kernels / hybrid)
8
+ - feat(genetic_presets): Add ToxinAntidoteDrive preset and corresponding tests
9
+
10
+ ## 2026.4.3
11
+ implemented spatial population with stable numba cache & parallel computation
12
+
13
+ ## 2026.3.28.c
14
+ add type annotations
15
+
16
+ ## 2026.3.28.b
17
+ add tests
18
+
19
+ ## 2026.3.28
20
+ `Species.from_dict` (and any repeated child-structure creation) crashed with `ValueError: Child structure '…' already exists` on a second call with the same name, even though `GeneticStructure.__new__` and `_single_register` already silently return cached instances. The fix makes the entire singleton chain consistent.
21
+
22
+ ### Changes
23
+
24
+ - **`ChildStructureRegistry.add`** — return `_storage[name]` instead of raising when the name already exists. `add` is now idempotent, matching `__new__`/`_single_register` semantics.
25
+
26
+ ```python
27
+ # Before: second call raises
28
+ sp1 = Species.from_dict("Mosquito", {"chr1": {"loc": ["WT", "Dr"]}})
29
+ sp2 = Species.from_dict("Mosquito", {"chr1": {"loc": ["WT", "Dr"]}})
30
+ # → ValueError: Child structure 'chr1' already exists.
31
+
32
+ # After: same cached instance returned
33
+ assert sp1 is sp2 # ✓
34
+ ```
35
+
36
+ - **`tests/conftest.py`** — removed all cache-clearing fixtures (`_GLOBAL_STRUCTURE_CACHE`, `GeneticEntity._instance_cache`, `Genotype._cache`). Clearing entity caches while live `Locus._entities` sets retained old references caused `EntityRegistry` (identity-based deduplication) to register fresh objects as duplicates, producing spurious extra alleles. The singleton chain is now coherent end-to-end without manual clearing.
37
+
38
+ - **`tests/test_genetic_structures.py`** — two regression tests covering idempotent `from_dict` (same instance returned) and no chromosome duplication on repeated calls.
39
+
40
+ - **`.gitignore`** — removed `tests/` and `test_*` entries that were suppressing test file tracking.
41
+
42
+ ## 2026.3.27
43
+ - 提升数值稳定性:修复了连续化抽样中的数值稳定性问题,当 $n \le 1$ 时退化为确定性
44
+ - 初步重构文档和 docstring
45
+ - 部分公用代码迁移到其他模块
46
+
47
+ ## 2026.3.26.e
48
+ - 优化 UI 字体大小和绘图描点策略
49
+
50
+ ## 2026.3.26.d
51
+ - 修复了 algorithms 中未正确处理配子储存与替换的问题
52
+ - 为 algorithms 增加概率范围限制和异常报错
53
+ - 为 algorithms 支持完整的 mating rates
54
+ - 增加 numba 随机种子设置方法
55
+ - 优化 UI 界面
56
+
57
+ ## 2026.3.26.c
58
+ - 重命名 `hook/` -> `hooks/`,并同步更新相关导入路径
59
+ - 重命名 `kernel/` -> `kernels/`,并同步更新相关导入路径
60
+
61
+ ## 2026.3.26.b
62
+ - 移除 `simulation_kernels.py` 中未使用的 `run/run_tick` 旧入口,统一走 hook codegen 生成的 wrapper
63
+ - 将 kernel wrapper codegen 从 `hook/compiler.py` 拆分到 `natal/kernel/codegen.py`,并将模板外置到 `src/natal/kernel/templates/kernel_wrappers.py.tmpl`
64
+ - 将核心 `simulation_kernels` 实现迁移到 `natal/kernel/simulation_kernels.py`,保留 `natal/simulation_kernels.py` 兼容转发
65
+ - 包结构重命名:`natal/hook` -> `natal/hooks`,`natal/kernel` -> `natal/kernels`,并同步更新内部导入与模板引用
66
+
67
+ ## 2026.3.26
68
+ - 修复 `HomingDrive` 中 maternal deposition 总是有效的 bug
69
+ - 增加 spatial model 的一些模块
70
+
71
+ ## 2026.3.25
72
+ - 继续根据类型检查进行了一些修改,当前版本可用
73
+ - 修改 UI title 和 favicon
74
+
75
+ ## 2026.3.24
76
+ - 根据类型检查进行了一些修改,当前版本可用
77
+
78
+ ## 2026.3.23
79
+ - 创建 webui
80
+ - 部分概念重命名:`IndexCore` -> `IndexRegistry`,`recipe` -> `preset`
81
+ - 恢复 `AgeStructuredPopulation` 的生存率、初始状态构建逻辑
82
+ - 修复了 `gamete_allele_conversion.py` 中 `sex_filter` 无效的问题(现在可以识别字符串和数字表示的性别,且无效的表示会报错)
83
+ - 优化文档
84
+
85
+ ## 2026.3.21
86
+ - 重构 hook,优化 hook 缓存
87
+
88
+ ## 2026.3.20
89
+ - 移除 `jitclass`,`PopulationState`, `DiscretePopulationState` 和 `PopulationConfig` 全部改为用 `NamedTuple`
90
+ - 优化 `njit` 缓存
91
+ - 增加编译提示信息
92
+
93
+ ## 2026.3.18.b
94
+ - Hook 执行内核拆分:将 CSR 执行逻辑抽为外部函数 `execute_csr_event_arrays`,统一以 `HookProgram` 作为数据载体
95
+ - 新增 `HookProgram` 与 `build_hook_program` 作为非 jitclass 路径的数据接口(第一阶段)
96
+ - 完全移除 `HookRegistry` 符号,核心内核统一走 `HookProgram + execute_csr_event_program`
97
+ - 优化 Declarative `when` 表达式的解析,支持 `and`、`or`、`not` 等逻辑运算符,增强表达能力
98
+ - 为 `Op.scale` / `Op.subtract` / `Op.sample` / `Op.set_count` 增加抽样逻辑
99
+
100
+ ## 2026.3.18
101
+ - 完善 HomingModificationDrive 逻辑
102
+ - 修复了配子产生的默认逻辑,此前会产生各种 gamete label 的配子(且每一种归一化),现在只产生默认 label("default" 或 index 0)
103
+ - 修复了 hooks 的 bug(响应式 hook 被注册但未被使用)
104
+ - 临时移除 `algorithms.fertilize_with_mating_genotype` 中对 `P` 的归一化,以支持致死效应的模拟(需后续检查正确性)
105
+
106
+ ## 2026.3.14
107
+ - 优化种群初始化方式
108
+ - 加入高级转换规则和 recipe 支持
109
+ - 引入基因型 pattern 解析器
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: natal-core
3
- Version: 0.1.0.dev1
3
+ Version: 0.1.0.dev2
4
4
  Summary: Numba-Accelerated Toolkit for Analysis of Lifecycle-based population genetic dynamics
5
5
  Project-URL: Homepage, https://github.com/jyzhu-pointless/natal-core
6
6
  Project-URL: Documentation, https://natal-core.readthedocs.io/en/latest/
@@ -33,9 +33,11 @@ Requires-Dist: pytest>=7.0.0; extra == 'test'
33
33
  Description-Content-Type: text/markdown
34
34
 
35
35
  # ⚡️ NATAL Core
36
+
36
37
  **N**umba-**A**ccelerated **T**oolkit for **A**nalysis of **L**ifecycles.
37
38
 
38
- [![PyPI](https://img.shields.io/pypi/v/natal-core.svg)](https://pypi.org/project/natal-core/)
39
+ [![GitHub](https://img.shields.io/github/v/release/jyzhu-pointless/natal-core?label=GitHub&color=purple)](https://github.com/jyzhu-pointless/natal-core/releases/latest)
40
+ [![PyPI](https://img.shields.io/pypi/v/natal-core.svg?label=PyPI&color=yellow)](https://pypi.org/project/natal-core/)
39
41
  [![Python](https://img.shields.io/badge/Python-3.9+-blue.svg)](https://www.python.org/downloads/)
40
42
  [![NumPy](https://img.shields.io/badge/NumPy-2.0.0+-green.svg)](https://numpy.org/)
41
43
  [![Numba](https://img.shields.io/badge/Numba-0.60.0+-orange.svg)](https://numba.pydata.org/)
@@ -1,7 +1,9 @@
1
1
  # ⚡️ NATAL Core
2
+
2
3
  **N**umba-**A**ccelerated **T**oolkit for **A**nalysis of **L**ifecycles.
3
4
 
4
- [![PyPI](https://img.shields.io/pypi/v/natal-core.svg)](https://pypi.org/project/natal-core/)
5
+ [![GitHub](https://img.shields.io/github/v/release/jyzhu-pointless/natal-core?label=GitHub&color=purple)](https://github.com/jyzhu-pointless/natal-core/releases/latest)
6
+ [![PyPI](https://img.shields.io/pypi/v/natal-core.svg?label=PyPI&color=yellow)](https://pypi.org/project/natal-core/)
5
7
  [![Python](https://img.shields.io/badge/Python-3.9+-blue.svg)](https://www.python.org/downloads/)
6
8
  [![NumPy](https://img.shields.io/badge/NumPy-2.0.0+-green.svg)](https://numpy.org/)
7
9
  [![Numba](https://img.shields.io/badge/Numba-0.60.0+-orange.svg)](https://numba.pydata.org/)
@@ -0,0 +1,20 @@
1
+ # TODO
2
+
3
+ - 复用 `state_translation` 模块的翻译函数到 WebUI
4
+ - `Species.from_dict` 构建后,应当支持指定性染色体
5
+ - 检查性染色体的遗传逻辑是否正确(遗传张量雌雄 index 应该不同)
6
+
7
+ ## initialization / finish 现状
8
+
9
+ ```txt
10
+ 事件定义里仍有 initialization、finish(以及 first/early/late)。
11
+ base_population.py (line 51)
12
+ types.py (line 124)
13
+ kernel 加速路径目前只执行 first/early/late(CSR+chain)。
14
+ simulation_kernels.py (line 382)
15
+ finish 是 Python 层触发(run 结束或 finish_simulation()),不在 kernel 事件链里。
16
+ age_structured_population.py (line 878)
17
+ discrete_generation_population.py (line 233)
18
+ base_population.py (line 801)
19
+ initialization 目前也在 Python 事件体系里,不在 kernel 执行路径。
20
+ ```
@@ -0,0 +1,100 @@
1
+ # Benchmarking & Profiling Scripts
2
+
3
+ This directory contains performance analysis and optimization scripts for natal-core.
4
+
5
+ ## Scripts Overview
6
+
7
+ ### Profiling Scripts
8
+
9
+ - **profile_spatial_hex_run.py**: Profile spatial.run(5) with 100x100 demes using cProfile
10
+ ```bash
11
+ python benchmarks/profile_spatial_hex_run.py
12
+ ```
13
+ Identifies Python-layer hotspots and cumulative function call patterns.
14
+
15
+ - **profile_single_deme_repro.py**: Profile single-deme reproduction (older approach, may need updates)
16
+ ```bash
17
+ python benchmarks/profile_single_deme_repro.py
18
+ ```
19
+
20
+ - **profile_repro_direct.py**: Direct kernel profiling using low-level SimulationKernels API
21
+ ```bash
22
+ python benchmarks/profile_repro_direct.py
23
+ ```
24
+
25
+ ### Benchmarking Scripts
26
+
27
+ - **benchmark_kernel_overhead.py**: Compare state management overhead vs kernel execution time
28
+ ```bash
29
+ python benchmarks/benchmark_kernel_overhead.py
30
+ ```
31
+ Measures cost of stacking/unstacking arrays and compares with pure kernel time.
32
+
33
+ - **benchmark_stages.py**: Per-tick performance analysis
34
+ ```bash
35
+ python benchmarks/benchmark_stages.py
36
+ ```
37
+ Measures individual tick execution cost across multiple runs.
38
+
39
+ ## Usage Tips
40
+
41
+ ### Running from Project Root
42
+ All scripts use PYTHONPATH-relative imports, so run from project root:
43
+ ```bash
44
+ cd /Users/pointless/Desktop/work/natal-core
45
+ python benchmarks/profile_spatial_hex_run.py
46
+ ```
47
+
48
+ ### Interpreting Results
49
+
50
+ **cProfile Output**:
51
+ - Look for functions with high `cumtime` and high `ncalls`
52
+ - `tottime` shows time spent in function itself
53
+ - `cumtime` includes time in called functions
54
+
55
+ **Benchmark Output**:
56
+ - Average ± std dev gives performance stability indication
57
+ - Variance > 10% suggests system-level noise or thermal effects
58
+ - Single best/worst runs often excluded from analysis
59
+
60
+ ### Key Metrics from Last Run
61
+ - **Spatial.run(5) total**: ~2.74-2.88s (5 runs)
62
+ - **Per-tick cost**: ~0.574s ± 0.053s
63
+ - **Python overhead**: 1.4% (state management)
64
+ - **Numba kernel time**: 98.6% (bottleneck)
65
+
66
+ ## Performance Analysis Results
67
+
68
+ 📊 See `OPTIMIZATION_REPORT.md` in project root for detailed findings.
69
+
70
+ ### Recent Optimization
71
+ Copy removal in spatial kernels (run_spatial_reproduction, run_spatial_survival, run_spatial_aging) achieved:
72
+ - 29% speedup in state stack/unstack (3.74s → 2.64s)
73
+ - 56% faster pytest suite (15.83s → 6.89s)
74
+ - 1-2% overall demo improvement
75
+
76
+ ### Bottleneck Identified
77
+ 98.6% of time spent in @njit Numba code:
78
+ - Not visible in cProfile (Numba functions appear as single call)
79
+ - Dominated by algorithmic cost (mating, fertilization, offspring generation)
80
+ - Further optimization requires:
81
+ - Numba algorithm tuning
82
+ - Parallelization flags adjustment
83
+ - Memory layout optimization
84
+
85
+ ## Future Optimization Directions
86
+
87
+ 1. **Numba Algorithm Level**
88
+ - Profile mating probability matrix computation
89
+ - Optimize offspring probability tensor construction
90
+ - Reduce allocations in inner loops
91
+
92
+ 2. **Parallelization**
93
+ - Test different n_jobs values
94
+ - Verify prange scheduling is optimal
95
+ - Check thread synchronization overhead
96
+
97
+ 3. **State Management** (higher risk)
98
+ - Cache frequently accessed arrays
99
+ - Consider mutable state structure (refactor from NamedTuple)
100
+ - Batch state updates
@@ -0,0 +1,126 @@
1
+ # type:ignore
2
+ """
3
+ Compare execution time of run_spatial_fn directly to identify if time is in Numba or Python.
4
+ """
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # Ensure project root is in path for imports
10
+ project_root = Path(__file__).parent.parent
11
+ if str(project_root) not in sys.path:
12
+ sys.path.insert(0, str(project_root))
13
+
14
+ import time
15
+ import numpy as np
16
+ from demos.spatial_hex import build_hex_spatial_population
17
+
18
+
19
+ def benchmark_runs():
20
+ """Run 3 iterations of spatial.run(5) and measure times."""
21
+ times = []
22
+
23
+ for run_idx in range(3):
24
+ spatial = build_hex_spatial_population()
25
+ spatial.run(1) # warmup
26
+
27
+ start = time.perf_counter()
28
+ spatial.run(5)
29
+ elapsed = time.perf_counter() - start
30
+ times.append(elapsed)
31
+
32
+ print(f"Run {run_idx + 1}: {elapsed:.4f}s")
33
+
34
+ print(f"\nAverage: {np.mean(times):.4f}s (±{np.std(times):.4f}s)")
35
+ return times
36
+
37
+
38
+ def benchmark_kernel_time():
39
+ """Measure just the Numba kernel call without state management."""
40
+ spatial = build_hex_spatial_population()
41
+ spatial.run(1) # warmup
42
+
43
+ # Manually reconstruct what run() does, but time only the kernel call
44
+ n_steps = 5
45
+
46
+ # Setup
47
+ hooks = spatial._demes[0].get_compiled_event_hooks()
48
+ run_fn = hooks.run_spatial_fn
49
+ registry = hooks.registry
50
+ config = spatial._shared_config()
51
+
52
+ # Method 1: Measure including state stack/unstack
53
+ print("=" * 60)
54
+ print("Method 1: Including state stack/unstack")
55
+ start = time.perf_counter()
56
+ for _ in range(3):
57
+ ind_all, sperm_all = spatial._stack_deme_state_arrays()
58
+ final_state_tuple, _history, was_stopped = run_fn(
59
+ ind_count_all=ind_all,
60
+ sperm_store_all=sperm_all,
61
+ config=config,
62
+ registry=registry,
63
+ tick=int(spatial._tick),
64
+ n_ticks=int(n_steps),
65
+ adjacency=spatial._adjacency,
66
+ migration_mode=spatial._migration_mode_code,
67
+ topology_rows=int(spatial._topology.rows),
68
+ topology_cols=int(spatial._topology.cols),
69
+ topology_wrap=bool(spatial._topology.wrap),
70
+ migration_kernel=spatial._migration_kernel_array(),
71
+ kernel_include_center=bool(spatial._kernel_include_center),
72
+ migration_rate=float(spatial._migration_rate),
73
+ )
74
+ spatial._apply_stacked_state(final_state_tuple[0], final_state_tuple[1], int(final_state_tuple[2]))
75
+ elapsed = time.perf_counter() - start
76
+ print(f" 3 runs (with stack/unstack): {elapsed:.4f}s ({elapsed/3:.4f}s per run)")
77
+
78
+ # Reset for next test
79
+ spatial = build_hex_spatial_population()
80
+ spatial.run(1) # warmup
81
+ hooks = spatial._demes[0].get_compiled_event_hooks()
82
+ run_fn = hooks.run_spatial_fn
83
+ registry = hooks.registry
84
+ config = spatial._shared_config()
85
+
86
+ # Method 2: Measure with pre-stacked arrays
87
+ print("=" * 60)
88
+ print("Method 2: Pre-stacked arrays (one allocation)")
89
+ start = time.perf_counter()
90
+
91
+ # Stack once
92
+ ind_all, sperm_all = spatial._stack_deme_state_arrays()
93
+
94
+ # Time 3 runs with same arrays
95
+ t0 = time.perf_counter()
96
+ for _ in range(3):
97
+ final_state_tuple, _history, was_stopped = run_fn(
98
+ ind_count_all=ind_all,
99
+ sperm_store_all=sperm_all,
100
+ config=config,
101
+ registry=registry,
102
+ tick=0,
103
+ n_ticks=5,
104
+ adjacency=spatial._adjacency,
105
+ migration_mode=spatial._migration_mode_code,
106
+ topology_rows=int(spatial._topology.rows),
107
+ topology_cols=int(spatial._topology.cols),
108
+ topology_wrap=bool(spatial._topology.wrap),
109
+ migration_kernel=spatial._migration_kernel_array(),
110
+ kernel_include_center=bool(spatial._kernel_include_center),
111
+ migration_rate=float(spatial._migration_rate),
112
+ )
113
+ # Don't apply state for this benchmark
114
+
115
+ elapsed = time.perf_counter() - t0
116
+ print(f" 3 runs (pre-stacked, no unstack): {elapsed:.4f}s ({elapsed/3:.4f}s per run)")
117
+
118
+
119
+ if __name__ == "__main__":
120
+ print("=" * 60)
121
+ print("BENCHMARK: spatial.run(5) with 100x100 demes (3 runs)")
122
+ print("=" * 60)
123
+ benchmark_runs()
124
+
125
+ print("\n")
126
+ benchmark_kernel_time()
@@ -0,0 +1,44 @@
1
+ # type:ignore
2
+ """
3
+ Micro-benchmark to measure individual tick costs in spatial simulation.
4
+ """
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # Ensure project root is in path for imports
10
+ project_root = Path(__file__).parent.parent
11
+ if str(project_root) not in sys.path:
12
+ sys.path.insert(0, str(project_root))
13
+
14
+ import time
15
+ import numpy as np
16
+ from demos.spatial_hex import build_hex_spatial_population
17
+
18
+
19
+ def benchmark_individual_stages():
20
+ """Measure cost of individual ticks."""
21
+ spatial = build_hex_spatial_population()
22
+ spatial.run(1) # warmup
23
+
24
+ print("=" * 60)
25
+ print("Per-tick Performance Analysis")
26
+ print("=" * 60)
27
+
28
+ times = []
29
+ for run_idx in range(3):
30
+ spatial = build_hex_spatial_population()
31
+ spatial.run(1) # warmup
32
+
33
+ start = time.perf_counter()
34
+ spatial.run(1) # measure 1 tick
35
+ elapsed = time.perf_counter() - start
36
+ times.append(elapsed)
37
+
38
+ print(f"Run {run_idx + 1}, 1 tick: {elapsed:.4f}s")
39
+
40
+ print(f"\nAverage per tick: {np.mean(times):.4f}s (±{np.std(times):.4f}s)")
41
+
42
+
43
+ if __name__ == "__main__":
44
+ benchmark_individual_stages()