PyAntiGen 2.1.1__tar.gz → 2.1.3__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 (112) hide show
  1. {pyantigen-2.1.1 → pyantigen-2.1.3}/LICENSE +1 -1
  2. {pyantigen-2.1.1 → pyantigen-2.1.3}/PKG-INFO +1 -1
  3. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/PKG-INFO +1 -1
  4. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/SOURCES.txt +6 -0
  5. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/scm_file_list.json +16 -0
  6. pyantigen-2.1.3/PyAntiGen.egg-info/scm_version.json +8 -0
  7. pyantigen-2.1.3/docs/ANALYTIC_GRADIENT.md +134 -0
  8. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/_version.py +3 -3
  9. pyantigen-2.1.3/pyantigen/engine/Analytic_gradient.py +619 -0
  10. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Multistart.py +65 -0
  11. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Optimize.py +173 -26
  12. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Preequil_cache.py +9 -0
  13. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Profile_plan.py +249 -100
  14. pyantigen-2.1.3/pyantigen/engine/Scaled_amici.py +269 -0
  15. pyantigen-2.1.3/pyantigen/engine/Segmented.py +181 -0
  16. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Simulate.py +104 -12
  17. pyantigen-2.1.3/pyantigen/generate/input_schedule.py +1015 -0
  18. pyantigen-2.1.3/pyantigen/generate/scaled_time.py +299 -0
  19. pyantigen-2.1.1/PyAntiGen.egg-info/scm_version.json +0 -8
  20. {pyantigen-2.1.1 → pyantigen-2.1.3}/.github/workflows/publish.yml +0 -0
  21. {pyantigen-2.1.1 → pyantigen-2.1.3}/.github/workflows/tests.yml +0 -0
  22. {pyantigen-2.1.1 → pyantigen-2.1.3}/.gitignore +0 -0
  23. {pyantigen-2.1.1 → pyantigen-2.1.3}/.vscode/launch.json +0 -0
  24. {pyantigen-2.1.1 → pyantigen-2.1.3}/MANIFEST.in +0 -0
  25. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/dependency_links.txt +0 -0
  26. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/entry_points.txt +0 -0
  27. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/requires.txt +0 -0
  28. {pyantigen-2.1.1 → pyantigen-2.1.3}/PyAntiGen.egg-info/top_level.txt +0 -0
  29. {pyantigen-2.1.1 → pyantigen-2.1.3}/README.md +0 -0
  30. {pyantigen-2.1.1 → pyantigen-2.1.3}/docs/MULTISTART.md +0 -0
  31. {pyantigen-2.1.1 → pyantigen-2.1.3}/docs/PROTOCOL_LAYER.md +0 -0
  32. {pyantigen-2.1.1 → pyantigen-2.1.3}/docs/V2_DESIGN.md +0 -0
  33. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/.agents/skills/module_generation/SKILL.md +0 -0
  34. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/.agents/skills/ode_conversion_antimony/SKILL.md +0 -0
  35. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/.agents/skills/ode_extraction_pipeline/SKILL.md +0 -0
  36. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/.gitignore +0 -0
  37. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/__init__.py +0 -0
  38. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/cli.py +0 -0
  39. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Anchor_cache.py +0 -0
  40. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Deadline.py +0 -0
  41. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Differential_evolution.py +0 -0
  42. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Evaluator.py +0 -0
  43. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Event_times.py +0 -0
  44. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Fast_profile.py +0 -0
  45. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Fit_cache.py +0 -0
  46. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Identifiability.py +0 -0
  47. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Model_cache.py +0 -0
  48. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Model_optimize.py +0 -0
  49. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Model_simulate.py +0 -0
  50. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Nelder_mead.py +0 -0
  51. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Noise_floor.py +0 -0
  52. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Petab_export.py +0 -0
  53. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Profile_checkpoint.py +0 -0
  54. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/README.md +0 -0
  55. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Results.py +0 -0
  56. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Sensitivity_analysis.py +0 -0
  57. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/Stop_rules.py +0 -0
  58. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/engine/__init__.py +0 -0
  59. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/AntimonyGen.py +0 -0
  60. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/RxnDict_to_antimony.py +0 -0
  61. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/TelluriumGen.py +0 -0
  62. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/__init__.py +0 -0
  63. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/antimony_utils.py +0 -0
  64. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/data_interpolation.py +0 -0
  65. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/isotopomer_tools.py +0 -0
  66. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/model_generation.py +0 -0
  67. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/models.py +0 -0
  68. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/module_base.py +0 -0
  69. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/pyantigen.py +0 -0
  70. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/rate_laws.py +0 -0
  71. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/generate/reaction_creation.py +0 -0
  72. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/__init__.py +0 -0
  73. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/assay.py +0 -0
  74. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/describe.py +0 -0
  75. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/design.py +0 -0
  76. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/lower_v1.py +0 -0
  77. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/optimization.py +0 -0
  78. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/params.py +0 -0
  79. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/quantity.py +0 -0
  80. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/reagent.py +0 -0
  81. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/refs.py +0 -0
  82. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/remarks.py +0 -0
  83. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/serialize.py +0 -0
  84. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/study/validate.py +0 -0
  85. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/AntiGen_paths.py +0 -0
  86. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Flipflop_reference.py +0 -0
  87. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Model_generate.py +0 -0
  88. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Model_run.py +0 -0
  89. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Data.py +0 -0
  90. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Events.py +0 -0
  91. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Experiment.py +0 -0
  92. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Loss_config.py +0 -0
  93. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Observed_species.py +0 -0
  94. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Optimizer_settings.py +0 -0
  95. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Plots.py +0 -0
  96. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Solver_settings.py +0 -0
  97. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Update_opt_parameters.py +0 -0
  98. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/Modules/Update_parameters.py +0 -0
  99. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/optimizations/Example1_ADneg.json +0 -0
  100. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/optimizations/Example1_ADpos.json +0 -0
  101. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/optimizations/Example3_joint.json +0 -0
  102. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/optimizations/Example4_flipflop.json +0 -0
  103. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/optimizations/example.py +0 -0
  104. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/studies/example.json +0 -0
  105. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/studies/example.py +0 -0
  106. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/Example/studies/flipflop.json +0 -0
  107. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/data/ADneg.csv +0 -0
  108. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/data/ADpos.csv +0 -0
  109. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/data/Flipflop.csv +0 -0
  110. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyantigen/template/data/make_flipflop_data.py +0 -0
  111. {pyantigen-2.1.1 → pyantigen-2.1.3}/pyproject.toml +0 -0
  112. {pyantigen-2.1.1 → pyantigen-2.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 UW Elbert Lab
3
+ Copyright (c) 2026 University of Washington - Elbert Lab
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyAntiGen
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: Declarative generation, simulation and identifiability analysis of compartmental Antimony/SBML models
5
5
  Author-email: Don Elbert <elbert5770@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyAntiGen
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: Declarative generation, simulation and identifiability analysis of compartmental Antimony/SBML models
5
5
  Author-email: Don Elbert <elbert5770@gmail.com>
6
6
  License-Expression: MIT
@@ -14,6 +14,7 @@ PyAntiGen.egg-info/requires.txt
14
14
  PyAntiGen.egg-info/scm_file_list.json
15
15
  PyAntiGen.egg-info/scm_version.json
16
16
  PyAntiGen.egg-info/top_level.txt
17
+ docs/ANALYTIC_GRADIENT.md
17
18
  docs/MULTISTART.md
18
19
  docs/PROTOCOL_LAYER.md
19
20
  docs/V2_DESIGN.md
@@ -24,6 +25,7 @@ pyantigen/cli.py
24
25
  pyantigen/.agents/skills/module_generation/SKILL.md
25
26
  pyantigen/.agents/skills/ode_conversion_antimony/SKILL.md
26
27
  pyantigen/.agents/skills/ode_extraction_pipeline/SKILL.md
28
+ pyantigen/engine/Analytic_gradient.py
27
29
  pyantigen/engine/Anchor_cache.py
28
30
  pyantigen/engine/Deadline.py
29
31
  pyantigen/engine/Differential_evolution.py
@@ -45,6 +47,8 @@ pyantigen/engine/Profile_checkpoint.py
45
47
  pyantigen/engine/Profile_plan.py
46
48
  pyantigen/engine/README.md
47
49
  pyantigen/engine/Results.py
50
+ pyantigen/engine/Scaled_amici.py
51
+ pyantigen/engine/Segmented.py
48
52
  pyantigen/engine/Sensitivity_analysis.py
49
53
  pyantigen/engine/Simulate.py
50
54
  pyantigen/engine/Stop_rules.py
@@ -55,6 +59,7 @@ pyantigen/generate/TelluriumGen.py
55
59
  pyantigen/generate/__init__.py
56
60
  pyantigen/generate/antimony_utils.py
57
61
  pyantigen/generate/data_interpolation.py
62
+ pyantigen/generate/input_schedule.py
58
63
  pyantigen/generate/isotopomer_tools.py
59
64
  pyantigen/generate/model_generation.py
60
65
  pyantigen/generate/models.py
@@ -62,6 +67,7 @@ pyantigen/generate/module_base.py
62
67
  pyantigen/generate/pyantigen.py
63
68
  pyantigen/generate/rate_laws.py
64
69
  pyantigen/generate/reaction_creation.py
70
+ pyantigen/generate/scaled_time.py
65
71
  pyantigen/study/__init__.py
66
72
  pyantigen/study/assay.py
67
73
  pyantigen/study/describe.py
@@ -7,6 +7,7 @@
7
7
  "LICENSE",
8
8
  "MANIFEST.in",
9
9
  "README.md",
10
+ "docs/ANALYTIC_GRADIENT.md",
10
11
  "docs/MULTISTART.md",
11
12
  "docs/PROTOCOL_LAYER.md",
12
13
  "docs/V2_DESIGN.md",
@@ -16,6 +17,7 @@
16
17
  "pyantigen/.gitignore",
17
18
  "pyantigen/__init__.py",
18
19
  "pyantigen/cli.py",
20
+ "pyantigen/engine/Analytic_gradient.py",
19
21
  "pyantigen/engine/Anchor_cache.py",
20
22
  "pyantigen/engine/Deadline.py",
21
23
  "pyantigen/engine/Differential_evolution.py",
@@ -37,6 +39,8 @@
37
39
  "pyantigen/engine/Profile_plan.py",
38
40
  "pyantigen/engine/README.md",
39
41
  "pyantigen/engine/Results.py",
42
+ "pyantigen/engine/Scaled_amici.py",
43
+ "pyantigen/engine/Segmented.py",
40
44
  "pyantigen/engine/Sensitivity_analysis.py",
41
45
  "pyantigen/engine/Simulate.py",
42
46
  "pyantigen/engine/Stop_rules.py",
@@ -47,6 +51,7 @@
47
51
  "pyantigen/generate/__init__.py",
48
52
  "pyantigen/generate/antimony_utils.py",
49
53
  "pyantigen/generate/data_interpolation.py",
54
+ "pyantigen/generate/input_schedule.py",
50
55
  "pyantigen/generate/isotopomer_tools.py",
51
56
  "pyantigen/generate/model_generation.py",
52
57
  "pyantigen/generate/models.py",
@@ -54,6 +59,7 @@
54
59
  "pyantigen/generate/pyantigen.py",
55
60
  "pyantigen/generate/rate_laws.py",
56
61
  "pyantigen/generate/reaction_creation.py",
62
+ "pyantigen/generate/scaled_time.py",
57
63
  "pyantigen/study/__init__.py",
58
64
  "pyantigen/study/assay.py",
59
65
  "pyantigen/study/describe.py",
@@ -97,6 +103,10 @@
97
103
  "tests/README.md",
98
104
  "tests/__init__.py",
99
105
  "tests/conftest.py",
106
+ "tests/engine/test_amici_jumps.py",
107
+ "tests/engine/test_amici_sensitivity.py",
108
+ "tests/engine/test_analytic_gradient.py",
109
+ "tests/engine/test_analytic_gradient_amici.py",
100
110
  "tests/engine/test_anchor_cache.py",
101
111
  "tests/engine/test_better_point.py",
102
112
  "tests/engine/test_de_fit.py",
@@ -121,7 +131,11 @@
121
131
  "tests/engine/test_profile_records.py",
122
132
  "tests/engine/test_profile_stream.py",
123
133
  "tests/engine/test_results_csv_policy.py",
134
+ "tests/engine/test_schedule_bounds.py",
124
135
  "tests/engine/test_search_mode.py",
136
+ "tests/engine/test_segment_jumps.py",
137
+ "tests/engine/test_segment_sensitivity.py",
138
+ "tests/engine/test_segmented.py",
125
139
  "tests/engine/test_sigma_floor.py",
126
140
  "tests/engine/test_slice_screen.py",
127
141
  "tests/engine/test_slice_window.py",
@@ -131,9 +145,11 @@
131
145
  "tests/engine/test_wald_units.py",
132
146
  "tests/generate/test_gen_antimony_utils.py",
133
147
  "tests/generate/test_gen_data_interpolation.py",
148
+ "tests/generate/test_gen_input_schedule.py",
134
149
  "tests/generate/test_gen_models.py",
135
150
  "tests/generate/test_gen_pyantigen_api.py",
136
151
  "tests/generate/test_gen_rxndict_to_antimony.py",
152
+ "tests/generate/test_gen_scaled_time.py",
137
153
  "tests/silk_fixtures/antimony_models/Antimony_Bloomingdale_2021_1a_all_reactions.txt",
138
154
  "tests/silk_fixtures/antimony_models/Antimony_Bloomingdale_2021_1a_rules.txt",
139
155
  "tests/silk_fixtures/antimony_models/Antimony_Elbert_2022_1a_all_reactions.txt",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.1.3",
3
+ "distance": 0,
4
+ "node": "g45ef1dd293ac66f01a48a35895aa0b83ec9a6b96",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-13"
8
+ }
@@ -0,0 +1,134 @@
1
+ # Fitting with a schedule: the bounds check and the AMICI gradient
2
+
3
+ Two options of `optimizer_kwargs` for a spec whose simulations take their clock-driven inputs from
4
+ an `InputSchedule` (see `pyantigen/generate/input_schedule.py`). Both leave a spec without a
5
+ schedule exactly as it was.
6
+
7
+ ## `schedule_bounds`: keep the box inside the region the schedule can be integrated in
8
+
9
+ A schedule can only be integrated while its switches keep their order (`InputSchedule.validate`):
10
+ in the SILK hour `0 < t_CSFdraw < V_LP/Q_CSF < 1`. A parameter set where they cross is a failed
11
+ evaluation, and a gradient method reads the failure as a cliff. Before the first evaluation the
12
+ optimizer checks the bounds of every fitted parameter that moves a switch time against each
13
+ simulation's schedule (`InputSchedule.check_box`: the corners of the box, the starting point, and
14
+ 64 pseudo-random points inside it).
15
+
16
+ ```python
17
+ optimizer_kwargs = {"schedule_bounds": "warn"} # "warn" (default) | "error" | "clip" | "ignore"
18
+ ```
19
+
20
+ * `"warn"` prints which corner is infeasible and goes on. A box wider than the region is not
21
+ necessarily wrong, but those evaluations will fail.
22
+ * `"error"` raises `ScheduleError` with the same message.
23
+ * `"clip"` cuts the bounds of the switch-moving parameters toward x0, by the largest common factor
24
+ for which the box is feasible (`InputSchedule.shrink_box`), and prints what it did.
25
+ * A starting point that is itself infeasible stops the fit in every mode except `"ignore"`.
26
+
27
+ Only simulations whose solver settings carry a `schedule` are checked, and the fitted names are taken
28
+ to be the schedule's parameters: a parameter a hook derives from them is not followed.
29
+
30
+ ## `analytic_gradient`: the gradient from AMICI's forward sensitivities
31
+
32
+ ```python
33
+ optimizer_kwargs = {
34
+ "method": "L-BFGS-B",
35
+ "analytic_gradient": True, # or a dict of the settings below
36
+ }
37
+ ```
38
+
39
+ Used by every gradient method (`L-BFGS-B`, `BFGS`, `CG`, `TNC`, `SLSQP`): in a single fit and in the
40
+ local fits of the multi-start stage, in place of the finite differences. With a gradient-free method it
41
+ is ignored (with a note). Needs AMICI >= 1.1 (on Windows, under WSL) and the simulations' inputs as an
42
+ `InputSchedule`, or as `at (time >= ...)` event lines `InputSchedule.from_antimony_events` can read.
43
+ A problem it cannot handle stops the run before any fit (`Multistart.GradientSetupError`).
44
+
45
+ | key | default | meaning |
46
+ | --- | --- | --- |
47
+ | `rtol`, `atol` | 1e-10, 1e-12 | AMICI's tolerances (state and sensitivities) |
48
+ | `max_steps` | 2 000 000 | AMICI step cap; the 10 000 h pre-equilibration of SILK needs it |
49
+ | `rel_step` | 1e-5 | step of the loss differentiation (below) |
50
+ | `cache_dir` | `<plot_path>/amici_models` | compiled models; one directory per distinct model |
51
+ | `seed` | none | `{state: amount}` given to AMICI at the start of every run, on top of the model's own initial state (see "A model that starts at zero") |
52
+
53
+ ### What it computes
54
+
55
+ The objective is the engine's concentrated NLL. Its derivative is not written out again; it is split by
56
+ the chain rule into the part AMICI knows and the part the loss knows:
57
+
58
+ 1. AMICI integrates the event-free model of `generate/scaled_time.py` and differentiates every
59
+ observed column (concentrations as `species / compartment`, assigned variables, parameters) with
60
+ respect to the model parameters the fitted ones reach. That table is mapped to the fitted parameters by
61
+ the Jacobian of the engine's own parameter updates (`Update_parameters`, `parameter_hooks`,
62
+ `Update_opt_parameters`), obtained by replaying them on the RoadRunner model.
63
+ 2. `LossGradient` differentiates the engine's own loss (`collect_loss_blocks`, `concentrated_nll`:
64
+ groups, pooled sigma blocks, sigma floors, observable expressions such as
65
+ `np.log10(np.maximum(predicted_B, 1e-12))`) along that table, by a Richardson central difference of the
66
+ loss alone. It re-does arithmetic on tables in memory: no integration, no noise. A parameter the loss
67
+ names (`SF*predicted_B`) gets its explicit partial derivative too.
68
+
69
+ The value in the fit is still the engine's (`Multistart.AnalyticObjective`: value from the objective,
70
+ gradient from the provider), so the best-so-far tracking, caches and failure handling are unchanged.
71
+ If AMICI fails at one point (a solver error, a non-finite sensitivity) that gradient is taken by forward
72
+ differences of the objective, counted, and reported with the fit; a zero gradient there would read as
73
+ convergence.
74
+
75
+ ### It differentiates the engine's objective, not the model's formulas
76
+
77
+ Where the two differ, the gradient follows the engine:
78
+
79
+ * **RoadRunner's `reset()` re-derives a species' initial assignment from the current parameters but not a
80
+ parameter's.** A parameter defined by an initial assignment from a fitted one (SILK's `Q_glymph = Q_CSF`,
81
+ `Q_SN = Q_CSF*f_SN`) keeps the value it had when the model was built while the optimizer moves `Q_CSF`.
82
+ The AMICI model gets those parameters as plain numbers at the engine's values
83
+ (`freeze_stale_assignments`); a schedule input among them keeps its stale starting value when it
84
+ differs from the formula. The stale value is a property of the in-place simulation, and the gradient
85
+ matches it.
86
+ * **Every parameter with an initial assignment is frozen**, not only those that read a fitted one. A model
87
+ whose constants are written as expressions (`k = 9.56e-7*70`, `V = V_base`) has them as initial
88
+ assignments, and a project's `Update_parameters` or hooks may overwrite them on the RoadRunner model.
89
+ Each becomes a plain parameter at the value RoadRunner holds, so AMICI integrates what the engine
90
+ integrates, and a hook that moves it is seen by the replay. (Before, only those reading a fitted parameter
91
+ were frozen; the others stayed NaN placeholders that reached AMICI's parameter vector, and a value a hook
92
+ had overwritten was not the one AMICI used.) Variables the schedule assigns, and what their initial values
93
+ are built from, are left alone.
94
+ * A species a hook sets directly is handed to AMICI as an initial value (without sensitivities; a hook
95
+ whose value depends on the fitted parameters is refused).
96
+
97
+ ### A model that starts at zero
98
+
99
+ AMICI differentiates the right-hand side symbolically and evaluates it at the first instant. A rate law
100
+ with a fractional power of an amount that is exactly zero there, `(Total/V)^0.8`, has an infinite derivative
101
+ at 0, and `0 * inf` is NaN: the run fails at t = 0 with status -42 ("NaN value for sxdot"). RoadRunner does
102
+ not differentiate, so the same model integrates without complaint. Give the states in question a negligible
103
+ amount, in AMICI only:
104
+
105
+ ```python
106
+ optimizer_kwargs = {"analytic_gradient": {"seed": {"AB40_BrainISF": 1e-12, "AB42_BrainISF": 1e-12}}}
107
+ ```
108
+
109
+ Read the AMICI log for the names: it lists the first states and rates that were NaN. The effect on the
110
+ trajectory is of the order of the seed, forgotten within the first steps of a stable system; check it for
111
+ yours by comparing the AMICI values with the engine's, as `Checks/wsl/` does. Unguarded ratios of two
112
+ zero amounts (`A / B` as an output) also print a NaN warning at t = 0 but do not stop the run unless the
113
+ dynamics read them.
114
+
115
+ ### Limits
116
+
117
+ * Time points: the loss is differentiated at the data times and the ends of the tracked window; the
118
+ engine interpolates a dense grid linearly between them. The two differ by the interpolation error
119
+ (a few 1e-4 of the gradient's scale on SILK).
120
+ * The fitted parameters must reach the model through plain parameters (constants without rule or
121
+ initial assignment) or hooks onto them. A fitted species initial value, or a parameter with an initial
122
+ assignment, is refused with a message naming it.
123
+ * Columns that are not species, parameters or compartments (reaction rates) are not available to the
124
+ loss; the gradient is then zero for anything that depends only on them.
125
+ * The profile-likelihood stage keeps its own optimizers.
126
+ * Cost: the gradient costs one AMICI forward-sensitivity run, which grows with the number of
127
+ parameters it differentiates. On SILK, 8 parameters: about 1.2 s a gradient against 9 objective
128
+ evaluations (about 1.4 s) for forward differences; with all 48 parameters AMICI needs about 40 s a
129
+ gradient against about 8 s for 49 evaluations. The case for it is a gradient without the noise of the
130
+ integrator tolerance and without a step to choose, not speed at every size. Fit only the parameters
131
+ that need fitting: the model is compiled for exactly those.
132
+
133
+ Checks on the real SILK model are in the examples repository,
134
+ `Projects/Elbert_2022_PyAntiGen_v4/Checks/wsl/fit_gradient.py`.
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.1.1'
22
- __version_tuple__ = version_tuple = (2, 1, 1)
21
+ __version__ = version = '2.1.3'
22
+ __version_tuple__ = version_tuple = (2, 1, 3)
23
23
 
24
- __commit_id__ = commit_id = 'g6282b0d51'
24
+ __commit_id__ = commit_id = 'g45ef1dd29'