7.8 KiB
| storyId | title | epic | status | created | priority |
|---|---|---|---|---|---|
| 6-6 | Python Solver Configuration Parity | 6 | done | 2026-02-22 | P0 |
Story 6.6: Python Solver Configuration Parity
Overview
Expose all Rust solver configuration options in Python bindings to enable full control over convergence optimization from Python scripts.
Problem Statement
The current Python bindings expose only a subset of the Rust solver configuration options. This prevents Python users from:
- Setting initial states for cold-start solving (critical for convergence)
- Configuring Jacobian freezing for performance optimization
- Using advanced convergence criteria for multi-circuit systems
- Accessing timeout behavior configuration (ZOH fallback for HIL)
- Using SolverStrategy for uniform solver abstraction
Gap Analysis
| Rust Field | Python Exposed | Impact | Priority |
|---|---|---|---|
initial_state |
❌ | Cannot warm-start solver | P0 |
use_numerical_jacobian |
❌ | Cannot debug Jacobian issues | P1 |
jacobian_freezing |
❌ | Missing 80% performance optimization | P1 |
convergence_criteria |
❌ | Cannot configure multi-circuit convergence | P1 |
timeout_config |
❌ | Cannot configure ZOH fallback | P2 |
previous_state |
❌ | Cannot use HIL zero-order hold | P2 |
line_search_armijo_c |
❌ | Cannot tune line search | P2 |
divergence_threshold |
❌ | Cannot adjust divergence detection | P2 |
SolverStrategy enum |
❌ | No uniform solver abstraction | P0 |
Acceptance Criteria
AC1: NewtonConfig Full Exposure
Given Python script using entropyk
When creating NewtonConfig
Then all Rust configuration fields are accessible:
config = entropyk.NewtonConfig(
max_iterations=200,
tolerance=1e-6,
line_search=True,
timeout_ms=5000,
# NEW FIELDS:
initial_state=[101325.0, 420000.0, ...], # Warm-start
use_numerical_jacobian=False,
jacobian_freezing=entropyk.JacobianFreezingConfig(
max_frozen_iters=3,
threshold=0.1
),
convergence_criteria=entropyk.ConvergenceCriteria(
pressure_tolerance_pa=1.0,
mass_balance_tolerance_kgs=1e-9
),
timeout_config=entropyk.TimeoutConfig(
return_best_state_on_timeout=True,
zoh_fallback=False
),
line_search_armijo_c=1e-4,
line_search_max_backtracks=20,
divergence_threshold=1e10
)
AC2: PicardConfig Full Exposure
Given Python script using entropyk
When creating PicardConfig
Then all Rust configuration fields are accessible:
config = entropyk.PicardConfig(
max_iterations=500,
tolerance=1e-4,
relaxation=0.5,
# NEW FIELDS:
initial_state=[...],
timeout_ms=10000,
convergence_criteria=entropyk.ConvergenceCriteria(...)
)
AC3: SolverStrategy Exposure
Given Python script using entropyk
When needing uniform solver interface
Then SolverStrategy enum is available:
# Create strategy directly
strategy = entropyk.SolverStrategy.newton(tolerance=1e-6)
strategy = entropyk.SolverStrategy.picard(relaxation=0.5)
# Use default
strategy = entropyk.SolverStrategy.default()
# Solve uniformly
result = strategy.solve(system)
AC4: Supporting Types
Given Python script using entropyk When configuring advanced options Then supporting types are available:
# JacobianFreezingConfig
jf_config = entropyk.JacobianFreezingConfig(
max_frozen_iters=3,
threshold=0.1
)
# TimeoutConfig
to_config = entropyk.TimeoutConfig(
return_best_state_on_timeout=True,
zoh_fallback=False
)
# ConvergenceCriteria
cc = entropyk.ConvergenceCriteria(
pressure_tolerance_pa=1.0,
mass_balance_tolerance_kgs=1e-9,
energy_balance_tolerance_w=1e-6
)
AC5: Backward Compatibility
Given existing Python code When upgrading to new version Then all existing code continues to work:
# OLD CODE - still works
config = entropyk.NewtonConfig(max_iterations=100, tolerance=1e-6)
result = config.solve(system)
# NEW CODE - with advanced options
config = entropyk.NewtonConfig(
max_iterations=100,
tolerance=1e-6,
initial_state=previous_result.state_vector
)
Implementation Tasks
Task 1: Extend PyNewtonConfig
- Add
initial_state: Option<Vec<f64>>field - Add
use_numerical_jacobian: boolfield - Add
jacobian_freezing: Option<PyJacobianFreezingConfig>field - Add
convergence_criteria: Option<PyConvergenceCriteria>field - Add
timeout_config: PyTimeoutConfigfield - Add
previous_state: Option<Vec<f64>>field - Add
line_search_armijo_c: f64field - Add
line_search_max_backtracks: usizefield - Add
divergence_threshold: f64field - Update
solve()to pass all fields to RustNewtonConfig
Task 2: Extend PyPicardConfig
- Add
initial_state: Option<Vec<f64>>field - Add
timeout_ms: Option<u64>field - Add
convergence_criteria: Option<PyConvergenceCriteria>field - Update
solve()to pass all fields to RustPicardConfig
Task 3: Create PySolverStrategy
- Create
PySolverStrategystruct wrappingSolverStrategy - Implement
#[staticmethod] newton()constructor - Implement
#[staticmethod] picard()constructor - Implement
#[staticmethod] default()constructor - Implement
solve(&mut self, system: &mut PySystem)method - Register in
lib.rs
Task 4: Create Supporting Types
- Create
PyJacobianFreezingConfigstruct - Create
PyTimeoutConfigstruct - Create
PyConvergenceCriteriastruct - Register all in
lib.rs
Task 5: Update Documentation
- Update
bindings/python/README.mdwith new API - Add examples for warm-start solving
- Add examples for Jacobian freezing
- Update
solver_control_examples.ipynb
Task 6: Add Tests
- Test
initial_statewarm-start - Test
jacobian_freezingconfiguration - Test
convergence_criteriaconfiguration - Test
SolverStrategyusage - Test backward compatibility
File List
| File | Action | Description |
|---|---|---|
bindings/python/src/solver.rs |
Modify | Extend config structs |
bindings/python/src/lib.rs |
Modify | Register new classes |
bindings/python/README.md |
Modify | Document new API |
bindings/python/tests/test_solver.py |
Modify | Add tests |
bindings/python/solver_control_examples.ipynb |
Modify | Add examples |
Technical Notes
Priority Implementation Order
- P0:
initial_state- Most critical for convergence - P0:
SolverStrategy- Architectural consistency - P1:
jacobian_freezing- Performance optimization - P1:
convergence_criteria- Multi-circuit support - P2: Other fields - Advanced tuning
Memory Safety
initial_stateandprevious_stateare cloned when passed to Rust- No lifetime issues as all data is owned
unsendableonPySystemremains for now (future: thread safety)
Performance Considerations
- Jacobian freezing can reduce per-iteration time by ~80%
- Warm-start can reduce iterations by 50-90% for similar conditions
References
- FR52: Python Solver Configuration Parity [Source: prd.md]
- Story 6.2: Python Bindings (PyO3) - foundation [Source: epics.md]
- Epic 4: Intelligent Solver Engine - Rust solver implementation [Source: epics.md]
- NewtonConfig:
crates/solver/src/solver.rs:398-490 - PicardConfig:
crates/solver/src/solver.rs(Picard section) - SolverStrategy:
crates/solver/src/solver.rs:2030-2073
Dependencies
- Story 6.2 (Python Bindings) - ✅ Complete
- Epic 4 (Solver Engine) - ✅ Complete
Definition of Done
- All acceptance criteria met
- All tests pass (
pytest tests/ -v) - Documentation updated
- Backward compatibility verified
- Code reviewed
- Merged to main