commol 0.1.0b1__cp313-cp313-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.

Potentially problematic release.


This version of commol might be problematic. Click here for more details.

@@ -0,0 +1,555 @@
1
+ Metadata-Version: 2.4
2
+ Name: commol
3
+ Version: 0.1.0b1
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.0b1.dist-info/METADATA,sha256=UsM1BHfm2iLUic_e1-4kXcSCNtJk8cwP4ALGNbaUqIg,16708
2
+ commol-0.1.0b1.dist-info/WHEEL,sha256=7EyPuU1vQDftlqyV8jHPuI-hSsV6D32-W3PQHFWI9CA,104
3
+ commol_rs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ commol_rs/commol_rs.cpython-313-darwin.so,sha256=9A5EkYzmi62ePKGFYdmk2BxCrPW9tvyKhXWsUrC7EsQ,5360352
5
+ commol_rs/commol_rs.pyi,sha256=CGw8HFA3sajCc8fzjGnfJez3lFWuLdqGKpVVSh_O7ik,15103
6
+ commol-0.1.0b1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.9.6)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-macosx_11_0_arm64
commol_rs/__init__.py ADDED
File without changes
@@ -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