commol 0.1.0b2__cp314-cp314-macosx_11_0_arm64.whl
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.
- commol-0.1.0b2.dist-info/METADATA +555 -0
- commol-0.1.0b2.dist-info/RECORD +6 -0
- commol-0.1.0b2.dist-info/WHEEL +4 -0
- commol_rs/__init__.py +0 -0
- commol_rs/commol_rs.cpython-314-darwin.so +0 -0
- commol_rs/commol_rs.pyi +464 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commol
|
|
3
|
+
Version: 0.1.0b2
|
|
4
|
+
Requires-Dist: cffi>=2.0,<3.0
|
|
5
|
+
Requires-Dist: numpy>=2.4.0,<3.0
|
|
6
|
+
Requires-Dist: pint>=0.25.2,<0.26.0
|
|
7
|
+
Requires-Dist: pydantic>=2.0,<3.0
|
|
8
|
+
Requires-Dist: scikit-learn>=1.8,<2.0
|
|
9
|
+
Requires-Dist: seaborn>=0.13.2,<0.14.0
|
|
10
|
+
Requires-Dist: maturin>=1.9.1,<1.10.0 ; extra == 'dev'
|
|
11
|
+
Requires-Dist: pre-commit>=3.8,<4.0 ; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest>=8.4,<9.0 ; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest-cov>=6.2,<7.0 ; extra == 'dev'
|
|
14
|
+
Requires-Dist: ruff>=0.12,<0.13 ; extra == 'dev'
|
|
15
|
+
Requires-Dist: twine>=6.2.0,<7.0.0 ; extra == 'dev'
|
|
16
|
+
Requires-Dist: ty>=0.0.9,<0.0.10 ; extra == 'dev'
|
|
17
|
+
Requires-Dist: vulture>=2.14,<3.0 ; extra == 'dev'
|
|
18
|
+
Requires-Dist: mike>=2.0,<3.0 ; extra == 'docs'
|
|
19
|
+
Requires-Dist: mkdocs>=1.6,<2.0 ; extra == 'docs'
|
|
20
|
+
Requires-Dist: mkdocstrings[python]>=0.26,<1.0 ; extra == 'docs'
|
|
21
|
+
Requires-Dist: mkdocs-autorefs>=1.2,<2.0 ; extra == 'docs'
|
|
22
|
+
Requires-Dist: mkdocs-material>=9.5,<10.0 ; extra == 'docs'
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Summary: A high-performance compartment modelling library in Rust and Python.
|
|
26
|
+
Author-email: "Rafael J. Villanueva Micó" <rjvillan@imm.upv.es>, Carlos Andreu Vilarroig <caranvi1@upv.es>, David Martínez Rodríguez <damarro3@upv.es>
|
|
27
|
+
License-Expression: MIT
|
|
28
|
+
Requires-Python: >=3.12.0
|
|
29
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
30
|
+
Project-URL: Homepage, https://github.com/MUNQU/commol
|
|
31
|
+
Project-URL: Documentation, https://munqu.github.io/commol
|
|
32
|
+
Project-URL: Repository, https://github.com/MUNQU/commol
|
|
33
|
+
Project-URL: Bug Tracker, https://github.com/MUNQU/commol/issues
|
|
34
|
+
|
|
35
|
+
# Commol
|
|
36
|
+
|
|
37
|
+
A high-performance compartment modelling library for mathematical modeling using difference equations. Commol provides a clean Python API backed by a fast Rust engine for numerical computations.
|
|
38
|
+
|
|
39
|
+
> ⚠️ **Alpha Stage Warning**: Commol is currently in alpha development. The API is not yet stable and may change between versions without backward compatibility guarantees. Use in production at your own risk.
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- **Intuitive Model Building**: Fluent API for constructing compartment models
|
|
44
|
+
- **Mathematical Expressions**: Support for complex mathematical formulas in transition rates (sin, cos, exp, log, etc.)
|
|
45
|
+
- **Unit Checking**: Automatic dimensional analysis to catch unit errors before simulation
|
|
46
|
+
- **High Performance**: Rust-powered simulation engine for fast computations
|
|
47
|
+
- **Flexible Architecture**: Support for stratified populations and conditional transitions
|
|
48
|
+
- **Type Safety**: Comprehensive validation using Pydantic models
|
|
49
|
+
- **Multiple Output Formats**: Get results as dictionaries or lists for easy analysis
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Install from PyPI (once published)
|
|
55
|
+
pip install commol
|
|
56
|
+
|
|
57
|
+
# Or install from source
|
|
58
|
+
git clone https://github.com/MUNQU/commol.git
|
|
59
|
+
cd commol/py-commol
|
|
60
|
+
pip install maturin
|
|
61
|
+
|
|
62
|
+
# If using a virtual environment, activate it first
|
|
63
|
+
# source venv/bin/activate # On Linux/macOS
|
|
64
|
+
# venv\Scripts\activate # On Windows
|
|
65
|
+
|
|
66
|
+
maturin develop --release
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> **⚠️ Important**: The project directory path must not contain tildes (`~`) or spaces. Maturin may fail with paths like `~/projects/commol` or `/home/my projects/commol`. Use full paths like `/home/username/projects/commol` instead.
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from commol import ModelBuilder, Simulation
|
|
75
|
+
|
|
76
|
+
# Build a simple SIR model
|
|
77
|
+
model = (
|
|
78
|
+
ModelBuilder(name="Basic SIR", version="1.0")
|
|
79
|
+
.add_bin(id="S", name="Susceptible")
|
|
80
|
+
.add_bin(id="I", name="Infected")
|
|
81
|
+
.add_bin(id="R", name="Recovered")
|
|
82
|
+
.add_parameter(id="beta", value=0.3)
|
|
83
|
+
.add_parameter(id="gamma", value=0.1)
|
|
84
|
+
.add_transition(
|
|
85
|
+
id="infection",
|
|
86
|
+
source=["S"],
|
|
87
|
+
target=["I"],
|
|
88
|
+
rate="beta * S * I / N"
|
|
89
|
+
)
|
|
90
|
+
.add_transition(
|
|
91
|
+
id="recovery",
|
|
92
|
+
source=["I"],
|
|
93
|
+
target=["R"],
|
|
94
|
+
rate="gamma"
|
|
95
|
+
)
|
|
96
|
+
.set_initial_conditions(
|
|
97
|
+
population_size=1000,
|
|
98
|
+
bin_fractions=[
|
|
99
|
+
{"bin": "S", "fraction": 0.99},
|
|
100
|
+
{"bin": "I", "fraction": 0.01},
|
|
101
|
+
{"bin": "R", "fraction": 0.0}
|
|
102
|
+
]
|
|
103
|
+
)
|
|
104
|
+
.build(typology="DifferenceEquations")
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Run simulation
|
|
108
|
+
simulation = Simulation(model)
|
|
109
|
+
results = simulation.run(num_steps=100)
|
|
110
|
+
|
|
111
|
+
# Display results
|
|
112
|
+
print(f"Final infected: {results['I'][-1]:.0f}")
|
|
113
|
+
|
|
114
|
+
# Visualize results
|
|
115
|
+
from commol import SimulationPlotter
|
|
116
|
+
|
|
117
|
+
plotter = SimulationPlotter(simulation, results)
|
|
118
|
+
plotter.plot_series(output_file="sir_model.png")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Using $compartment Placeholder for Multiple Transitions
|
|
122
|
+
|
|
123
|
+
When you need to apply the same transition to multiple compartments (like death rates), use the `$compartment` placeholder instead of writing repetitive code:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
model = (
|
|
127
|
+
ModelBuilder(name="SLIR with Deaths", version="1.0")
|
|
128
|
+
.add_bin(id="S", name="Susceptible")
|
|
129
|
+
.add_bin(id="L", name="Latent")
|
|
130
|
+
.add_bin(id="I", name="Infected")
|
|
131
|
+
.add_bin(id="R", name="Recovered")
|
|
132
|
+
.add_parameter(id="beta", value=0.3, unit="1/day")
|
|
133
|
+
.add_parameter(id="gamma", value=0.2, unit="1/day")
|
|
134
|
+
.add_parameter(id="delta", value=0.1, unit="1/day")
|
|
135
|
+
.add_parameter(id="d", value=0.01, unit="1/day") # Death rate
|
|
136
|
+
.add_transition(
|
|
137
|
+
id="infection",
|
|
138
|
+
source=["S"],
|
|
139
|
+
target=["L"],
|
|
140
|
+
rate="beta * S * I / N"
|
|
141
|
+
)
|
|
142
|
+
.add_transition(
|
|
143
|
+
id="progression",
|
|
144
|
+
source=["L"],
|
|
145
|
+
target=["I"],
|
|
146
|
+
rate="gamma * L"
|
|
147
|
+
)
|
|
148
|
+
.add_transition(
|
|
149
|
+
id="recovery",
|
|
150
|
+
source=["I"],
|
|
151
|
+
target=["R"],
|
|
152
|
+
rate="delta * I"
|
|
153
|
+
)
|
|
154
|
+
# Single transition automatically expands to 4 separate death transitions
|
|
155
|
+
.add_transition(
|
|
156
|
+
id="death",
|
|
157
|
+
source=["S", "L", "I", "R"],
|
|
158
|
+
target=[],
|
|
159
|
+
rate="d * $compartment" # Expands to: d*S, d*L, d*I, d*R
|
|
160
|
+
)
|
|
161
|
+
.set_initial_conditions(
|
|
162
|
+
population_size=1000,
|
|
163
|
+
bin_fractions=[
|
|
164
|
+
{"bin": "S", "fraction": 0.99},
|
|
165
|
+
{"bin": "L", "fraction": 0.005},
|
|
166
|
+
{"bin": "I", "fraction": 0.005},
|
|
167
|
+
{"bin": "R", "fraction": 0.0}
|
|
168
|
+
]
|
|
169
|
+
)
|
|
170
|
+
.build(typology="DifferenceEquations")
|
|
171
|
+
)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**The `$compartment` placeholder:**
|
|
175
|
+
|
|
176
|
+
- Automatically expands to multiple transitions (one per source compartment)
|
|
177
|
+
- Replaces `$compartment` with the actual compartment name in the rate formula
|
|
178
|
+
- Works with stratified rates for age-structured or location-based models
|
|
179
|
+
- Reduces code duplication and improves maintainability
|
|
180
|
+
|
|
181
|
+
**Example with stratified rates:**
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
.add_transition(
|
|
185
|
+
id="death",
|
|
186
|
+
source=["S", "I", "R"],
|
|
187
|
+
target=[],
|
|
188
|
+
rate="d_base * $compartment", # Fallback rate
|
|
189
|
+
stratified_rates=[
|
|
190
|
+
{
|
|
191
|
+
"conditions": [{"stratification": "age", "category": "young"}],
|
|
192
|
+
"rate": "d_young * $compartment" # Lower death rate for young
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"conditions": [{"stratification": "age", "category": "old"}],
|
|
196
|
+
"rate": "d_old * $compartment" # Higher death rate for old
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### With Unit Checking
|
|
203
|
+
|
|
204
|
+
Add units to parameters and bins for automatic dimensional validation and annotated equation display:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
model = (
|
|
208
|
+
ModelBuilder(name="SIR with Units", version="1.0", bin_unit="person")
|
|
209
|
+
.add_bin(id="S", name="Susceptible")
|
|
210
|
+
.add_bin(id="I", name="Infected")
|
|
211
|
+
.add_bin(id="R", name="Recovered")
|
|
212
|
+
.add_parameter(id="beta", value=0.5, unit="1/day") # Rate with units
|
|
213
|
+
.add_parameter(id="gamma", value=0.1, unit="1/day")
|
|
214
|
+
.add_transition(
|
|
215
|
+
id="infection",
|
|
216
|
+
source=["S"],
|
|
217
|
+
target=["I"],
|
|
218
|
+
rate="beta * S * I / N"
|
|
219
|
+
)
|
|
220
|
+
.add_transition(
|
|
221
|
+
id="recovery",
|
|
222
|
+
source=["I"],
|
|
223
|
+
target=["R"],
|
|
224
|
+
rate="gamma * I"
|
|
225
|
+
)
|
|
226
|
+
.set_initial_conditions(
|
|
227
|
+
population_size=1000,
|
|
228
|
+
bin_fractions=[
|
|
229
|
+
{"bin": "S", "fraction": 0.99},
|
|
230
|
+
{"bin": "I", "fraction": 0.01},
|
|
231
|
+
{"bin": "R", "fraction": 0.0}
|
|
232
|
+
]
|
|
233
|
+
)
|
|
234
|
+
.build(typology="DifferenceEquations")
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Validate dimensional consistency
|
|
238
|
+
model.check_unit_consistency() # Ensures all equations have correct units
|
|
239
|
+
|
|
240
|
+
# Print equations with unit annotations
|
|
241
|
+
model.print_equations()
|
|
242
|
+
# Output shows:
|
|
243
|
+
# S -> I: beta(1/day) * S(person) * I(person) / N(person) [person/day]
|
|
244
|
+
# I -> R: gamma(1/day) * I(person) [person/day]
|
|
245
|
+
|
|
246
|
+
# Export equations in LaTeX format for publications
|
|
247
|
+
model.print_equations(format="latex")
|
|
248
|
+
# Output: \[\frac{dS}{dt} = - (\beta \cdot S \cdot I / N)\]
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Note**: Units must be defined for ALL parameters and bins, or for NONE. Partial unit definitions will raise a `ValueError` to prevent inconsistent models.
|
|
252
|
+
|
|
253
|
+
### Model Calibration
|
|
254
|
+
|
|
255
|
+
Fit model parameters to observed data using optimization algorithms. Parameters to be calibrated should be set to `None`:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from commol import (
|
|
259
|
+
ModelBuilder,
|
|
260
|
+
Simulation,
|
|
261
|
+
Calibrator,
|
|
262
|
+
CalibrationProblem,
|
|
263
|
+
CalibrationParameter,
|
|
264
|
+
ObservedDataPoint,
|
|
265
|
+
ParticleSwarmConfig,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Build model with unknown parameters
|
|
269
|
+
model = (
|
|
270
|
+
ModelBuilder(name="SIR Model", version="1.0")
|
|
271
|
+
.add_bin(id="S", name="Susceptible")
|
|
272
|
+
.add_bin(id="I", name="Infected")
|
|
273
|
+
.add_bin(id="R", name="Recovered")
|
|
274
|
+
.add_parameter(id="beta", value=None) # To be calibrated
|
|
275
|
+
.add_parameter(id="gamma", value=None) # To be calibrated
|
|
276
|
+
.add_transition(
|
|
277
|
+
id="infection",
|
|
278
|
+
source=["S"],
|
|
279
|
+
target=["I"],
|
|
280
|
+
rate="beta * S * I / N"
|
|
281
|
+
)
|
|
282
|
+
.add_transition(
|
|
283
|
+
id="recovery",
|
|
284
|
+
source=["I"],
|
|
285
|
+
target=["R"],
|
|
286
|
+
rate="gamma * I"
|
|
287
|
+
)
|
|
288
|
+
.set_initial_conditions(
|
|
289
|
+
population_size=1000,
|
|
290
|
+
bin_fractions=[
|
|
291
|
+
{"bin": "S", "fraction": 0.99},
|
|
292
|
+
{"bin": "I", "fraction": 0.01},
|
|
293
|
+
{"bin": "R", "fraction": 0.0}
|
|
294
|
+
]
|
|
295
|
+
)
|
|
296
|
+
.build(typology="DifferenceEquations")
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Define observed data from real outbreak
|
|
300
|
+
observed_data = [
|
|
301
|
+
ObservedDataPoint(step=10, compartment="I", value=45.2),
|
|
302
|
+
ObservedDataPoint(step=20, compartment="I", value=78.5),
|
|
303
|
+
ObservedDataPoint(step=30, compartment="I", value=62.3),
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
# Simulation can be created with None values for calibration
|
|
307
|
+
simulation = Simulation(model)
|
|
308
|
+
|
|
309
|
+
# Specify parameters to calibrate with bounds and initial guesses
|
|
310
|
+
parameters = [
|
|
311
|
+
CalibrationParameter(
|
|
312
|
+
id="beta",
|
|
313
|
+
parameter_type="parameter",
|
|
314
|
+
min_bound=0.0,
|
|
315
|
+
max_bound=1.0,
|
|
316
|
+
initial_guess=0.3 # Starting point
|
|
317
|
+
),
|
|
318
|
+
CalibrationParameter(
|
|
319
|
+
id="gamma",
|
|
320
|
+
parameter_type="parameter",
|
|
321
|
+
min_bound=0.0,
|
|
322
|
+
max_bound=1.0,
|
|
323
|
+
),
|
|
324
|
+
]
|
|
325
|
+
|
|
326
|
+
# Configure optimization algorithm (config type determines the algorithm)
|
|
327
|
+
pso_config = ParticleSwarmConfig(
|
|
328
|
+
num_particles=40,
|
|
329
|
+
max_iterations=300,
|
|
330
|
+
verbose=True
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Configure calibration problem
|
|
334
|
+
problem = CalibrationProblem(
|
|
335
|
+
observed_data=observed_data,
|
|
336
|
+
parameters=parameters,
|
|
337
|
+
loss_function="sse",
|
|
338
|
+
optimization_config=pso_config, # ParticleSwarmConfig or NelderMeadConfig
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
# Run calibration
|
|
342
|
+
calibrator = Calibrator(simulation, problem)
|
|
343
|
+
result = calibrator.run()
|
|
344
|
+
|
|
345
|
+
print(f"Calibrated beta: {result.best_parameters['beta']:.4f}")
|
|
346
|
+
print(f"Calibrated gamma: {result.best_parameters['gamma']:.4f}")
|
|
347
|
+
|
|
348
|
+
# Update model with calibrated parameters
|
|
349
|
+
model.update_parameters(result.best_parameters)
|
|
350
|
+
|
|
351
|
+
# Create new simulation with calibrated model
|
|
352
|
+
calibrated_simulation = Simulation(model)
|
|
353
|
+
calibrated_results = calibrated_simulation.run(num_steps=100)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Calibrating with Scale Parameters:**
|
|
357
|
+
|
|
358
|
+
When observed data is underreported, use scale parameters to estimate the reporting rate:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
# Reported cases (potentially underreported)
|
|
362
|
+
reported_cases = [10, 15, 25, 40, 60, 75, 85, 70, 50, 30]
|
|
363
|
+
|
|
364
|
+
# Link observed data to scale parameter
|
|
365
|
+
observed_data = [
|
|
366
|
+
ObservedDataPoint(
|
|
367
|
+
step=idx,
|
|
368
|
+
compartment="I",
|
|
369
|
+
value=cases,
|
|
370
|
+
scale_id="reporting_rate" # Links to scale parameter
|
|
371
|
+
)
|
|
372
|
+
for idx, cases in enumerate(reported_cases)
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
parameters = [
|
|
376
|
+
CalibrationParameter(
|
|
377
|
+
id="beta",
|
|
378
|
+
parameter_type="parameter",
|
|
379
|
+
min_bound=0.1,
|
|
380
|
+
max_bound=1.0
|
|
381
|
+
),
|
|
382
|
+
CalibrationParameter(
|
|
383
|
+
id="gamma",
|
|
384
|
+
parameter_type="parameter",
|
|
385
|
+
min_bound=0.05,
|
|
386
|
+
max_bound=0.5
|
|
387
|
+
),
|
|
388
|
+
CalibrationParameter(
|
|
389
|
+
id="reporting_rate",
|
|
390
|
+
parameter_type="scale",
|
|
391
|
+
min_bound=0.01,
|
|
392
|
+
max_bound=1.0
|
|
393
|
+
),
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
# Run calibration
|
|
397
|
+
result = calibrator.run()
|
|
398
|
+
|
|
399
|
+
# Separate parameters by type
|
|
400
|
+
scale_values = {
|
|
401
|
+
param.id: result.best_parameters[param.id]
|
|
402
|
+
for param in problem.parameters
|
|
403
|
+
if param.parameter_type == "scale"
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
print(f"Calibrated reporting rate: {scale_values['reporting_rate']:.2%}")
|
|
407
|
+
|
|
408
|
+
# Visualize with scale_values for correct display
|
|
409
|
+
plotter.plot_series(observed_data=observed_data, scale_values=scale_values)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Constraining Parameters:**
|
|
413
|
+
|
|
414
|
+
Apply constraints to enforce biological knowledge during calibration.
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
from commol import CalibrationConstraint
|
|
418
|
+
|
|
419
|
+
# Add constraint: beta/gamma <= 5 (written as 5 - beta/gamma >= 0)
|
|
420
|
+
constraints = [
|
|
421
|
+
CalibrationConstraint(
|
|
422
|
+
id="r0_bound",
|
|
423
|
+
expression="5.0 - beta/gamma",
|
|
424
|
+
description="R0 <= 5",
|
|
425
|
+
)
|
|
426
|
+
]
|
|
427
|
+
|
|
428
|
+
problem = CalibrationProblem(
|
|
429
|
+
observed_data=observed_data,
|
|
430
|
+
parameters=parameters,
|
|
431
|
+
constraints=constraints, # Include constraints
|
|
432
|
+
loss_function="sse",
|
|
433
|
+
optimization_config=pso_config,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
result = calibrator.run()
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Probabilistic Calibration:**
|
|
440
|
+
|
|
441
|
+
For uncertainty quantification, use probabilistic calibration to get an ensemble of parameter sets:
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from commol import ProbabilisticCalibrationConfig
|
|
445
|
+
|
|
446
|
+
# Configure probabilistic calibration
|
|
447
|
+
prob_config = ProbabilisticCalibrationConfig(
|
|
448
|
+
n_runs=20, # Number of calibration runs
|
|
449
|
+
confidence_level=0.95
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
problem = CalibrationProblem(
|
|
453
|
+
observed_data=observed_data,
|
|
454
|
+
parameters=parameters,
|
|
455
|
+
loss_function="sse",
|
|
456
|
+
optimization_config=pso_config,
|
|
457
|
+
probabilistic_config=prob_config, # Enable probabilistic mode
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
# Run probabilistic calibration
|
|
461
|
+
calibrator = Calibrator(simulation, problem)
|
|
462
|
+
prob_result = calibrator.run_probabilistic()
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Documentation
|
|
466
|
+
|
|
467
|
+
**[Full Documentation](https://munqu.github.io/commol)**
|
|
468
|
+
|
|
469
|
+
- [Installation Guide](https://munqu.github.io/commol/getting-started/installation/) - Setup and installation
|
|
470
|
+
- [Quick Start](https://munqu.github.io/commol/getting-started/quickstart/) - Build your first model
|
|
471
|
+
- [User Guide](https://munqu.github.io/commol/guide/core-concepts/) - Core concepts and tutorials
|
|
472
|
+
- [Model Calibration](https://munqu.github.io/commol/guide/calibration/) - Parameter fitting and optimization
|
|
473
|
+
- [API Reference](https://munqu.github.io/commol/api/model-builder/) - Complete API documentation
|
|
474
|
+
- [Examples](https://munqu.github.io/commol/guide/examples/) - SIR, SEIR, and advanced models
|
|
475
|
+
|
|
476
|
+
## Development
|
|
477
|
+
|
|
478
|
+
For contributors and developers:
|
|
479
|
+
|
|
480
|
+
- [Development Workflow](https://munqu.github.io/commol/development/workflow/) - Setup, branching, CI/CD
|
|
481
|
+
- [Contributing Guidelines](https://munqu.github.io/commol/development/contributing/) - How to contribute
|
|
482
|
+
- [Release Process](https://munqu.github.io/commol/development/release/) - Version management
|
|
483
|
+
|
|
484
|
+
### Local Development
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
# Clone repository
|
|
488
|
+
git clone https://github.com/MUNQU/commol.git
|
|
489
|
+
cd commol
|
|
490
|
+
|
|
491
|
+
# Create and activate virtual environment
|
|
492
|
+
python -m venv venv
|
|
493
|
+
|
|
494
|
+
source venv/bin/activate # On Linux/macOS
|
|
495
|
+
venv\Scripts\activate # On Windows
|
|
496
|
+
|
|
497
|
+
# Install Python dependencies
|
|
498
|
+
cd py-commol
|
|
499
|
+
pip install -e ".[dev,docs]"
|
|
500
|
+
|
|
501
|
+
# Build Rust workspace
|
|
502
|
+
cd ..
|
|
503
|
+
cargo build --workspace
|
|
504
|
+
|
|
505
|
+
# Build Python extension (with virtual environment activated)
|
|
506
|
+
cd py-commol
|
|
507
|
+
maturin develop --release
|
|
508
|
+
|
|
509
|
+
# Run tests
|
|
510
|
+
pytest
|
|
511
|
+
cd ..
|
|
512
|
+
cargo test --workspace
|
|
513
|
+
|
|
514
|
+
# Build documentation locally
|
|
515
|
+
cd py-commol
|
|
516
|
+
mkdocs serve
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
> **⚠️ Path Requirements**: Ensure the project path contains no tildes (`~`) or spaces. Maturin may fail otherwise.
|
|
520
|
+
>
|
|
521
|
+
> **💡 Tip**: Make sure your virtual environment is activated before running `maturin develop`.
|
|
522
|
+
|
|
523
|
+
## License
|
|
524
|
+
|
|
525
|
+
Commol is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
526
|
+
|
|
527
|
+
## Authors
|
|
528
|
+
|
|
529
|
+
- Rafael J. Villanueva Micó - [rjvillan@imm.upv.es](mailto:rjvillan@imm.upv.es)
|
|
530
|
+
- Carlos Andreu Vilarroig - [caranvi1@upv.es](mailto:caranvi1@upv.es)
|
|
531
|
+
- David Martínez Rodríguez - [damarro3@upv.es](mailto:damarro3@upv.es)
|
|
532
|
+
|
|
533
|
+
## Citation
|
|
534
|
+
|
|
535
|
+
If you use Commol in your research, please cite:
|
|
536
|
+
|
|
537
|
+
```bibtex
|
|
538
|
+
@software{commol2025,
|
|
539
|
+
title = {Commol: A High-Performance Compartment Modelling Library},
|
|
540
|
+
author = {
|
|
541
|
+
Villanueva Micó, Rafael J.
|
|
542
|
+
and Andreu Vilarroig, Carlos
|
|
543
|
+
and Martínez Rodríguez, David
|
|
544
|
+
},
|
|
545
|
+
year = {2025},
|
|
546
|
+
url = {https://github.com/MUNQU/commol}
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## Support
|
|
551
|
+
|
|
552
|
+
- Documentation: https://munqu.github.io/commol
|
|
553
|
+
- Issue Tracker: https://github.com/MUNQU/commol/issues
|
|
554
|
+
- Discussions: https://github.com/MUNQU/commol/discussions
|
|
555
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
commol-0.1.0b2.dist-info/METADATA,sha256=tb56qeRXaC0T7g_tsUP2laNgXwyZemkJJi2Cqg3z6K4,16708
|
|
2
|
+
commol-0.1.0b2.dist-info/WHEEL,sha256=1PvyiPvcJ94VD-5qzLXvCxiTKltkB9r5dXMQ1otw8Pg,104
|
|
3
|
+
commol_rs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
commol_rs/commol_rs.cpython-314-darwin.so,sha256=4sGndTCZ39VI-9eql0_WoHaFqvysi1fCGgrmvOajAsQ,5338656
|
|
5
|
+
commol_rs/commol_rs.pyi,sha256=CGw8HFA3sajCc8fzjGnfJez3lFWuLdqGKpVVSh_O7ik,15103
|
|
6
|
+
commol-0.1.0b2.dist-info/RECORD,,
|
commol_rs/__init__.py
ADDED
|
File without changes
|
|
Binary file
|
commol_rs/commol_rs.pyi
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
from typing import Protocol
|
|
2
|
+
|
|
3
|
+
from commol.constants import LogicOperators, ModelTypes, VariablePrefixes
|
|
4
|
+
|
|
5
|
+
class RuleProtocol(Protocol):
|
|
6
|
+
variable: str
|
|
7
|
+
operator: LogicOperators
|
|
8
|
+
value: str | int | float | bool
|
|
9
|
+
|
|
10
|
+
class ConditionProtocol(Protocol):
|
|
11
|
+
logic: LogicOperators
|
|
12
|
+
rules: list[RuleProtocol]
|
|
13
|
+
|
|
14
|
+
class DiseaseStateProtocol(Protocol):
|
|
15
|
+
id: str
|
|
16
|
+
name: str
|
|
17
|
+
|
|
18
|
+
class StratificationProtocol(Protocol):
|
|
19
|
+
id: str
|
|
20
|
+
categories: list[str]
|
|
21
|
+
|
|
22
|
+
class StratificationConditionProtocol(Protocol):
|
|
23
|
+
stratification: str
|
|
24
|
+
category: str
|
|
25
|
+
|
|
26
|
+
class StratifiedRateProtocol(Protocol):
|
|
27
|
+
conditions: list[StratificationConditionProtocol]
|
|
28
|
+
rate: str
|
|
29
|
+
|
|
30
|
+
class TransitionProtocol(Protocol):
|
|
31
|
+
id: str
|
|
32
|
+
source: list[str]
|
|
33
|
+
target: list[str]
|
|
34
|
+
rate: RateMathExpressionProtocol | None
|
|
35
|
+
stratified_rates: list[StratifiedRateProtocol] | None
|
|
36
|
+
condition: ConditionProtocol | None
|
|
37
|
+
|
|
38
|
+
class ParameterProtocol(Protocol):
|
|
39
|
+
id: str
|
|
40
|
+
value: float
|
|
41
|
+
description: str | None
|
|
42
|
+
|
|
43
|
+
class StratificationFractionProtocol(Protocol):
|
|
44
|
+
category: str
|
|
45
|
+
fraction: float
|
|
46
|
+
|
|
47
|
+
class StratificationFractionsProtocol(Protocol):
|
|
48
|
+
stratification: str
|
|
49
|
+
fractions: list[StratificationFractionProtocol]
|
|
50
|
+
|
|
51
|
+
class InitialConditionsProtocol(Protocol):
|
|
52
|
+
population_size: int
|
|
53
|
+
disease_state_fraction: dict[str, float]
|
|
54
|
+
stratification_fractions: list[StratificationFractionsProtocol]
|
|
55
|
+
|
|
56
|
+
class PopulationProtocol(Protocol):
|
|
57
|
+
disease_states: list[DiseaseStateProtocol]
|
|
58
|
+
stratifications: list[StratificationProtocol]
|
|
59
|
+
transitions: list[TransitionProtocol]
|
|
60
|
+
initial_conditions: InitialConditionsProtocol
|
|
61
|
+
|
|
62
|
+
class DynamicsProtocol(Protocol):
|
|
63
|
+
typology: ModelTypes
|
|
64
|
+
transitions: list[TransitionProtocol]
|
|
65
|
+
|
|
66
|
+
class RustModelProtocol(Protocol):
|
|
67
|
+
name: str
|
|
68
|
+
description: str | None
|
|
69
|
+
version: str | None
|
|
70
|
+
population: PopulationProtocol
|
|
71
|
+
parameters: list[ParameterProtocol]
|
|
72
|
+
dynamics: DynamicsProtocol
|
|
73
|
+
@staticmethod
|
|
74
|
+
def from_json(json_string: str) -> RustModelProtocol: ...
|
|
75
|
+
|
|
76
|
+
class DifferenceEquationsProtocol(Protocol):
|
|
77
|
+
def __init__(self, model: RustModelProtocol) -> None: ...
|
|
78
|
+
def run(self, num_steps: int) -> list[list[float]]: ...
|
|
79
|
+
def step(self) -> None: ...
|
|
80
|
+
@property
|
|
81
|
+
def population(self) -> list[float]: ...
|
|
82
|
+
@property
|
|
83
|
+
def compartments(self) -> list[str]: ...
|
|
84
|
+
|
|
85
|
+
class DifferenceModule(Protocol):
|
|
86
|
+
DifferenceEquations: type[DifferenceEquationsProtocol]
|
|
87
|
+
|
|
88
|
+
class ObservedDataPointProtocol(Protocol):
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
step: int,
|
|
92
|
+
compartment: str,
|
|
93
|
+
value: float,
|
|
94
|
+
weight: float | None = None,
|
|
95
|
+
scale_id: str | None = None,
|
|
96
|
+
) -> None: ...
|
|
97
|
+
@property
|
|
98
|
+
def time_step(self) -> int: ...
|
|
99
|
+
@property
|
|
100
|
+
def compartment(self) -> str: ...
|
|
101
|
+
@property
|
|
102
|
+
def value(self) -> float: ...
|
|
103
|
+
@property
|
|
104
|
+
def scale_id(self) -> str | None: ...
|
|
105
|
+
|
|
106
|
+
class CalibrationParameterTypeProtocol(Protocol):
|
|
107
|
+
Parameter: "CalibrationParameterTypeProtocol"
|
|
108
|
+
InitialCondition: "CalibrationParameterTypeProtocol"
|
|
109
|
+
Scale: "CalibrationParameterTypeProtocol"
|
|
110
|
+
|
|
111
|
+
class CalibrationParameterProtocol(Protocol):
|
|
112
|
+
def __init__(
|
|
113
|
+
self,
|
|
114
|
+
id: str,
|
|
115
|
+
parameter_type: CalibrationParameterTypeProtocol,
|
|
116
|
+
min_bound: float,
|
|
117
|
+
max_bound: float,
|
|
118
|
+
initial_guess: float | None = None,
|
|
119
|
+
) -> None: ...
|
|
120
|
+
@property
|
|
121
|
+
def id(self) -> str: ...
|
|
122
|
+
@property
|
|
123
|
+
def parameter_type(self) -> CalibrationParameterTypeProtocol: ...
|
|
124
|
+
@property
|
|
125
|
+
def min_bound(self) -> float: ...
|
|
126
|
+
@property
|
|
127
|
+
def max_bound(self) -> float: ...
|
|
128
|
+
|
|
129
|
+
class CalibrationConstraintProtocol(Protocol):
|
|
130
|
+
def __init__(
|
|
131
|
+
self,
|
|
132
|
+
id: str,
|
|
133
|
+
expression: str,
|
|
134
|
+
description: str | None = None,
|
|
135
|
+
weight: float = 1.0,
|
|
136
|
+
time_steps: list[int] | None = None,
|
|
137
|
+
) -> None: ...
|
|
138
|
+
@property
|
|
139
|
+
def id(self) -> str: ...
|
|
140
|
+
@property
|
|
141
|
+
def expression(self) -> str: ...
|
|
142
|
+
@property
|
|
143
|
+
def description(self) -> str | None: ...
|
|
144
|
+
@property
|
|
145
|
+
def weight(self) -> float: ...
|
|
146
|
+
@property
|
|
147
|
+
def time_steps(self) -> list[int] | None: ...
|
|
148
|
+
|
|
149
|
+
class LossConfigProtocol(Protocol):
|
|
150
|
+
@staticmethod
|
|
151
|
+
def sse() -> LossConfigProtocol: ...
|
|
152
|
+
@staticmethod
|
|
153
|
+
def rmse() -> LossConfigProtocol: ...
|
|
154
|
+
@staticmethod
|
|
155
|
+
def mae() -> LossConfigProtocol: ...
|
|
156
|
+
@staticmethod
|
|
157
|
+
def weighted_sse() -> LossConfigProtocol: ...
|
|
158
|
+
|
|
159
|
+
class NelderMeadConfigProtocol(Protocol):
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
max_iterations: int = 1000,
|
|
163
|
+
sd_tolerance: float = 1e-6,
|
|
164
|
+
simplex_perturbation: float = 1.1,
|
|
165
|
+
alpha: float | None = None,
|
|
166
|
+
gamma: float | None = None,
|
|
167
|
+
rho: float | None = None,
|
|
168
|
+
sigma: float | None = None,
|
|
169
|
+
verbose: bool = False,
|
|
170
|
+
header_interval: int = 100,
|
|
171
|
+
) -> None: ...
|
|
172
|
+
|
|
173
|
+
class PSOInertiaConstantProtocol(Protocol):
|
|
174
|
+
def __init__(self, factor: float) -> None: ...
|
|
175
|
+
@property
|
|
176
|
+
def factor(self) -> float: ...
|
|
177
|
+
|
|
178
|
+
class PSOInertiaChaoticProtocol(Protocol):
|
|
179
|
+
def __init__(self, w_min: float, w_max: float) -> None: ...
|
|
180
|
+
@property
|
|
181
|
+
def w_min(self) -> float: ...
|
|
182
|
+
@property
|
|
183
|
+
def w_max(self) -> float: ...
|
|
184
|
+
|
|
185
|
+
class PSOAccelerationConstantProtocol(Protocol):
|
|
186
|
+
def __init__(self, cognitive: float, social: float) -> None: ...
|
|
187
|
+
@property
|
|
188
|
+
def cognitive(self) -> float: ...
|
|
189
|
+
@property
|
|
190
|
+
def social(self) -> float: ...
|
|
191
|
+
|
|
192
|
+
class PSOAccelerationTimeVaryingProtocol(Protocol):
|
|
193
|
+
def __init__(
|
|
194
|
+
self, c1_initial: float, c1_final: float, c2_initial: float, c2_final: float
|
|
195
|
+
) -> None: ...
|
|
196
|
+
@property
|
|
197
|
+
def c1_initial(self) -> float: ...
|
|
198
|
+
@property
|
|
199
|
+
def c1_final(self) -> float: ...
|
|
200
|
+
@property
|
|
201
|
+
def c2_initial(self) -> float: ...
|
|
202
|
+
@property
|
|
203
|
+
def c2_final(self) -> float: ...
|
|
204
|
+
|
|
205
|
+
class PSOMutationProtocol(Protocol):
|
|
206
|
+
def __init__(
|
|
207
|
+
self, strategy: str, scale: float, probability: float, application: str
|
|
208
|
+
) -> None: ...
|
|
209
|
+
@property
|
|
210
|
+
def strategy(self) -> str: ...
|
|
211
|
+
@property
|
|
212
|
+
def scale(self) -> float: ...
|
|
213
|
+
@property
|
|
214
|
+
def probability(self) -> float: ...
|
|
215
|
+
@property
|
|
216
|
+
def application(self) -> str: ...
|
|
217
|
+
|
|
218
|
+
class PSOVelocityProtocol(Protocol):
|
|
219
|
+
def __init__(
|
|
220
|
+
self, clamp_factor: float | None = None, mutation_threshold: float | None = None
|
|
221
|
+
) -> None: ...
|
|
222
|
+
@property
|
|
223
|
+
def clamp_factor(self) -> float | None: ...
|
|
224
|
+
@property
|
|
225
|
+
def mutation_threshold(self) -> float | None: ...
|
|
226
|
+
|
|
227
|
+
class ParticleSwarmConfigProtocol(Protocol):
|
|
228
|
+
def __init__(
|
|
229
|
+
self,
|
|
230
|
+
num_particles: int = 20,
|
|
231
|
+
max_iterations: int = 1000,
|
|
232
|
+
verbose: bool = False,
|
|
233
|
+
inertia: PSOInertiaConstantProtocol | PSOInertiaChaoticProtocol | None = None,
|
|
234
|
+
acceleration: PSOAccelerationConstantProtocol
|
|
235
|
+
| PSOAccelerationTimeVaryingProtocol
|
|
236
|
+
| None = None,
|
|
237
|
+
mutation: PSOMutationProtocol | None = None,
|
|
238
|
+
velocity: PSOVelocityProtocol | None = None,
|
|
239
|
+
initialization: str = "uniform",
|
|
240
|
+
seed: int | None = None,
|
|
241
|
+
) -> None: ...
|
|
242
|
+
|
|
243
|
+
class OptimizationConfigProtocol(Protocol):
|
|
244
|
+
@staticmethod
|
|
245
|
+
def nelder_mead(
|
|
246
|
+
config: NelderMeadConfigProtocol | None = None,
|
|
247
|
+
) -> OptimizationConfigProtocol: ...
|
|
248
|
+
@staticmethod
|
|
249
|
+
def particle_swarm(
|
|
250
|
+
config: ParticleSwarmConfigProtocol | None = None,
|
|
251
|
+
) -> OptimizationConfigProtocol: ...
|
|
252
|
+
|
|
253
|
+
class CalibrationResultProtocol(Protocol):
|
|
254
|
+
@property
|
|
255
|
+
def best_parameters(self) -> dict[str, float]: ...
|
|
256
|
+
@property
|
|
257
|
+
def best_parameters_list(self) -> list[float]: ...
|
|
258
|
+
@property
|
|
259
|
+
def parameter_names(self) -> list[str]: ...
|
|
260
|
+
@property
|
|
261
|
+
def final_loss(self) -> float: ...
|
|
262
|
+
@property
|
|
263
|
+
def iterations(self) -> int: ...
|
|
264
|
+
@property
|
|
265
|
+
def converged(self) -> bool: ...
|
|
266
|
+
@property
|
|
267
|
+
def termination_reason(self) -> str: ...
|
|
268
|
+
def to_dict(self) -> dict[str, object]: ...
|
|
269
|
+
|
|
270
|
+
class CalibrationEvaluationProtocol(Protocol):
|
|
271
|
+
def __init__(
|
|
272
|
+
self,
|
|
273
|
+
parameters: list[float],
|
|
274
|
+
loss: float,
|
|
275
|
+
predictions: list[list[float]],
|
|
276
|
+
) -> None: ...
|
|
277
|
+
@property
|
|
278
|
+
def parameters(self) -> list[float]: ...
|
|
279
|
+
@property
|
|
280
|
+
def loss(self) -> float: ...
|
|
281
|
+
@property
|
|
282
|
+
def predictions(self) -> list[list[float]]: ...
|
|
283
|
+
|
|
284
|
+
class CalibrationResultWithHistoryProtocol(Protocol):
|
|
285
|
+
@property
|
|
286
|
+
def best_parameters(self) -> dict[str, float]: ...
|
|
287
|
+
@property
|
|
288
|
+
def best_parameters_list(self) -> list[float]: ...
|
|
289
|
+
@property
|
|
290
|
+
def parameter_names(self) -> list[str]: ...
|
|
291
|
+
@property
|
|
292
|
+
def final_loss(self) -> float: ...
|
|
293
|
+
@property
|
|
294
|
+
def iterations(self) -> int: ...
|
|
295
|
+
@property
|
|
296
|
+
def converged(self) -> bool: ...
|
|
297
|
+
@property
|
|
298
|
+
def termination_reason(self) -> str: ...
|
|
299
|
+
@property
|
|
300
|
+
def evaluations(self) -> list[CalibrationEvaluationProtocol]: ...
|
|
301
|
+
|
|
302
|
+
class ParetoSolutionProtocol(Protocol):
|
|
303
|
+
@property
|
|
304
|
+
def ensemble_size(self) -> int: ...
|
|
305
|
+
@property
|
|
306
|
+
def ci_width(self) -> float: ...
|
|
307
|
+
@property
|
|
308
|
+
def coverage(self) -> float: ...
|
|
309
|
+
@property
|
|
310
|
+
def size_penalty(self) -> float: ...
|
|
311
|
+
@property
|
|
312
|
+
def selected_indices(self) -> list[int]: ...
|
|
313
|
+
|
|
314
|
+
class EnsembleSelectionResultProtocol(Protocol):
|
|
315
|
+
@property
|
|
316
|
+
def selected_ensemble(self) -> list[int]: ...
|
|
317
|
+
@property
|
|
318
|
+
def pareto_front(self) -> list[ParetoSolutionProtocol]: ...
|
|
319
|
+
@property
|
|
320
|
+
def selected_pareto_index(self) -> int: ...
|
|
321
|
+
|
|
322
|
+
class CalibrationModule(Protocol):
|
|
323
|
+
ObservedDataPoint: type[ObservedDataPointProtocol]
|
|
324
|
+
CalibrationParameterType: type[CalibrationParameterTypeProtocol]
|
|
325
|
+
CalibrationParameter: type[CalibrationParameterProtocol]
|
|
326
|
+
CalibrationConstraint: type[CalibrationConstraintProtocol]
|
|
327
|
+
LossConfig: type[LossConfigProtocol]
|
|
328
|
+
NelderMeadConfig: type[NelderMeadConfigProtocol]
|
|
329
|
+
PSOInertiaConstant: type[PSOInertiaConstantProtocol]
|
|
330
|
+
PSOInertiaChaotic: type[PSOInertiaChaoticProtocol]
|
|
331
|
+
PSOAccelerationConstant: type[PSOAccelerationConstantProtocol]
|
|
332
|
+
PSOAccelerationTimeVarying: type[PSOAccelerationTimeVaryingProtocol]
|
|
333
|
+
PSOMutation: type[PSOMutationProtocol]
|
|
334
|
+
PSOVelocity: type[PSOVelocityProtocol]
|
|
335
|
+
ParticleSwarmConfig: type[ParticleSwarmConfigProtocol]
|
|
336
|
+
OptimizationConfig: type[OptimizationConfigProtocol]
|
|
337
|
+
CalibrationResult: type[CalibrationResultProtocol]
|
|
338
|
+
CalibrationEvaluation: type[CalibrationEvaluationProtocol]
|
|
339
|
+
CalibrationResultWithHistory: type[CalibrationResultWithHistoryProtocol]
|
|
340
|
+
ParetoSolution: type[ParetoSolutionProtocol]
|
|
341
|
+
EnsembleSelectionResult: type[EnsembleSelectionResultProtocol]
|
|
342
|
+
|
|
343
|
+
def calibrate(
|
|
344
|
+
self,
|
|
345
|
+
engine: DifferenceEquationsProtocol,
|
|
346
|
+
observed_data: list[ObservedDataPointProtocol],
|
|
347
|
+
parameters: list[CalibrationParameterProtocol],
|
|
348
|
+
constraints: list[CalibrationConstraintProtocol],
|
|
349
|
+
loss_config: LossConfigProtocol,
|
|
350
|
+
optimization_config: OptimizationConfigProtocol,
|
|
351
|
+
initial_population_size: int,
|
|
352
|
+
) -> CalibrationResultProtocol: ...
|
|
353
|
+
def calibrate_with_history(
|
|
354
|
+
self,
|
|
355
|
+
engine: DifferenceEquationsProtocol,
|
|
356
|
+
observed_data: list[ObservedDataPointProtocol],
|
|
357
|
+
parameters: list[CalibrationParameterProtocol],
|
|
358
|
+
constraints: list[CalibrationConstraintProtocol],
|
|
359
|
+
loss_config: LossConfigProtocol,
|
|
360
|
+
optimization_config: OptimizationConfigProtocol,
|
|
361
|
+
initial_population_size: int,
|
|
362
|
+
) -> CalibrationResultWithHistoryProtocol: ...
|
|
363
|
+
def run_multiple_calibrations(
|
|
364
|
+
self,
|
|
365
|
+
engine: DifferenceEquationsProtocol,
|
|
366
|
+
observed_data: list[ObservedDataPointProtocol],
|
|
367
|
+
parameters: list[CalibrationParameterProtocol],
|
|
368
|
+
constraints: list[CalibrationConstraintProtocol],
|
|
369
|
+
loss_config: LossConfigProtocol,
|
|
370
|
+
optimization_config: OptimizationConfigProtocol,
|
|
371
|
+
initial_population_size: int,
|
|
372
|
+
n_runs: int,
|
|
373
|
+
seed: int,
|
|
374
|
+
) -> list[CalibrationResultWithHistoryProtocol]: ...
|
|
375
|
+
def select_optimal_ensemble(
|
|
376
|
+
self,
|
|
377
|
+
candidates: list[CalibrationEvaluationProtocol],
|
|
378
|
+
observed_data_tuples: list[tuple[int, int, float]],
|
|
379
|
+
population_size: int,
|
|
380
|
+
generations: int,
|
|
381
|
+
confidence_level: float,
|
|
382
|
+
seed: int,
|
|
383
|
+
pareto_preference: float,
|
|
384
|
+
ensemble_size_mode: str,
|
|
385
|
+
ensemble_size: int | None = None,
|
|
386
|
+
ensemble_size_min: int | None = None,
|
|
387
|
+
ensemble_size_max: int | None = None,
|
|
388
|
+
ci_margin_factor: float = 0.1,
|
|
389
|
+
ci_sample_sizes: list[int] | None = None,
|
|
390
|
+
nsga_crossover_probability: float = 0.9,
|
|
391
|
+
) -> EnsembleSelectionResultProtocol: ...
|
|
392
|
+
def deduplicate_evaluations(
|
|
393
|
+
self,
|
|
394
|
+
evaluations: list[CalibrationEvaluationProtocol],
|
|
395
|
+
tolerance: float,
|
|
396
|
+
) -> list[CalibrationEvaluationProtocol]: ...
|
|
397
|
+
def generate_predictions_parallel(
|
|
398
|
+
self,
|
|
399
|
+
engine: DifferenceEquationsProtocol,
|
|
400
|
+
parameter_sets: list[list[float]],
|
|
401
|
+
parameter_names: list[str],
|
|
402
|
+
time_steps: int,
|
|
403
|
+
) -> list[list[list[float]]]: ...
|
|
404
|
+
def select_cluster_representatives(
|
|
405
|
+
self,
|
|
406
|
+
evaluations: list[CalibrationEvaluationProtocol],
|
|
407
|
+
cluster_labels: list[int],
|
|
408
|
+
max_representatives: int,
|
|
409
|
+
elite_fraction: float,
|
|
410
|
+
strategy: str,
|
|
411
|
+
selection_method: str = "crowding_distance",
|
|
412
|
+
quality_temperature: float = 1.0,
|
|
413
|
+
seed: int = 42,
|
|
414
|
+
k_neighbors_min: int = 5,
|
|
415
|
+
k_neighbors_max: int = 10,
|
|
416
|
+
sparsity_weight: float = 2.0,
|
|
417
|
+
stratum_fit_weight: float = 10.0,
|
|
418
|
+
) -> list[int]: ...
|
|
419
|
+
|
|
420
|
+
class MathExpressionProtocol(Protocol):
|
|
421
|
+
def __init__(self, expression: str) -> None: ...
|
|
422
|
+
def validate(self) -> None: ...
|
|
423
|
+
|
|
424
|
+
class RateMathExpressionProtocol(Protocol):
|
|
425
|
+
@staticmethod
|
|
426
|
+
def from_string_py(s: str) -> RateMathExpressionProtocol: ...
|
|
427
|
+
@staticmethod
|
|
428
|
+
def parameter(name: str) -> RateMathExpressionProtocol: ...
|
|
429
|
+
@staticmethod
|
|
430
|
+
def formula(formula: str) -> RateMathExpressionProtocol: ...
|
|
431
|
+
@staticmethod
|
|
432
|
+
def constant(value: float) -> RateMathExpressionProtocol: ...
|
|
433
|
+
def py_get_variables(self) -> list[str]: ...
|
|
434
|
+
|
|
435
|
+
class CoreModule(Protocol):
|
|
436
|
+
Model: type[RustModelProtocol]
|
|
437
|
+
Population: type[PopulationProtocol]
|
|
438
|
+
DiseaseState: type[DiseaseStateProtocol]
|
|
439
|
+
Stratification: type[StratificationProtocol]
|
|
440
|
+
StratificationCondition: type[StratificationConditionProtocol]
|
|
441
|
+
StratifiedRate: type[StratifiedRateProtocol]
|
|
442
|
+
Transition: type[TransitionProtocol]
|
|
443
|
+
Parameter: type[ParameterProtocol]
|
|
444
|
+
InitialConditions: type[InitialConditionsProtocol]
|
|
445
|
+
StratificationFraction: type[StratificationFractionProtocol]
|
|
446
|
+
StratificationFractions: type[StratificationFractionsProtocol]
|
|
447
|
+
Condition: type[ConditionProtocol]
|
|
448
|
+
Rule: type[RuleProtocol]
|
|
449
|
+
LogicOperator: type[LogicOperators]
|
|
450
|
+
ModelTypes: type[ModelTypes]
|
|
451
|
+
VariablePrefixes: type[VariablePrefixes]
|
|
452
|
+
Dynamics: type[DynamicsProtocol]
|
|
453
|
+
MathExpression: type[MathExpressionProtocol]
|
|
454
|
+
RateMathExpression: type[RateMathExpressionProtocol]
|
|
455
|
+
|
|
456
|
+
class RustEpiModelModule(Protocol):
|
|
457
|
+
core: CoreModule
|
|
458
|
+
difference: DifferenceModule
|
|
459
|
+
calibration: CalibrationModule
|
|
460
|
+
|
|
461
|
+
core: CoreModule
|
|
462
|
+
difference: DifferenceModule
|
|
463
|
+
calibration: CalibrationModule
|
|
464
|
+
rust_epimodel: RustEpiModelModule
|