Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
30f1725
Add weight_of_last_period to flowsystem
FBumann Nov 17, 2025
a537be5
Add weights per effect and move normalization
FBumann Nov 17, 2025
cc7e2ac
Weighted Sum Constraints Over All Periods have been fully implement…
FBumann Nov 17, 2025
3f932af
Fixed a critical bug in /Users/felix/PycharmProjects/flixopt_719231/…
FBumann Nov 17, 2025
a690060
Successfully refactored 11 parameter names across the codebase using…
FBumann Nov 17, 2025
9945a7c
Cahneglog
FBumann Nov 17, 2025
ac03159
Fix CHANGELOG.md
FBumann Nov 17, 2025
7f351ec
1. Critical Bug Fix - structure.py:219-229
FBumann Nov 18, 2025
f18343b
Merge remote-tracking branch 'origin/main' into feature/sums-over-all…
FBumann Nov 18, 2025
4675da6
1. Critical Bug Fix - structure.py:219-229
FBumann Nov 18, 2025
8d048d9
Added single-period validation in _create_periods_with_extra():
FBumann Nov 18, 2025
f6c160a
Added dimension validation for flow_hours constraints
FBumann Nov 18, 2025
3066234
Fixed the DataArray boolean context
FBumann Nov 18, 2025
debef08
Remove intermediate parameters that need no deprecation
FBumann Nov 18, 2025
97821b8
Remove intermediate parameters that need no deprecation
FBumann Nov 18, 2025
fec2f75
Update CHANGELOG.md
FBumann Nov 18, 2025
e077330
Fix weighting per period in Flows
FBumann Nov 18, 2025
8e7ac77
Add type hints and fallback for weights = None
FBumann Nov 18, 2025
b16c7e3
Imrove weight computation in Effects
FBumann Nov 18, 2025
915b6f1
Improve objectove weight handling
FBumann Nov 18, 2025
8e47551
Add tests
FBumann Nov 18, 2025
3177ca2
Typos
FBumann Nov 18, 2025
f306ff2
Add zero-sum guard to objective_weights property to prevent silent Na…
FBumann Nov 18, 2025
e0c29e2
Guard over‑periods constraint when no period dimension is present.
FBumann Nov 18, 2025
705503d
Fit fallback weight to dims
FBumann Nov 18, 2025
f818b23
Improve weight handling.
FBumann Nov 19, 2025
1b0c1ed
Typos and updates
FBumann Nov 19, 2025
43ccdd4
Update CHANGELOG.md
FBumann Nov 19, 2025
bd3f60d
Update tests
FBumann Nov 19, 2025
6d3e58d
Improve handling of scenario weights
FBumann Nov 19, 2025
523365f
Improve docs
FBumann Nov 19, 2025
d767fd4
Typos
FBumann Nov 19, 2025
a8be0ab
Rename in tests
FBumann Nov 19, 2025
613a323
Fix tests
FBumann Nov 19, 2025
7df6334
Use setter for scenario_weights
FBumann Nov 19, 2025
b6abb9d
Revert test changes
FBumann Nov 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 89 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,67 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp

## [Unreleased] - ????-??-??

**Summary**: Renaming parameters in Linear Transformers for readability & Internal architecture improvements to simplify FlowSystem-Element coupling and eliminate circular dependencies. Old parameters till work but emmit warnings.
**Summary**: Renaming parameters in Linear Transformers for readability (old parameters still work but emit warnings), new bounds for weighted sums over all periods for effects and flow hours, and refactored weights handling to fix `.sel()` issues with periods.

If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOpt/flixOpt/releases/tag/v3.0.0) and [Migration Guide](https://flixopt.github.io/flixopt/latest/user-guide/migration-guide-v3/).

### ✨ Added
- **Internal period weight computation**: `FlowSystem` now automatically computes `period_weights` from the period index (similar to `hours_per_timestep` for time dimension), ensuring weights are always consistent with the actual periods

- **New constraint parameters for sum across all periods**:
- `Effect`: Added `minimum_over_periods` and `maximum_over_periods` for weighted sum constraints across all periods (complements existing per-period `minimum_total`/`maximum_total`)
- `Flow`: Added `flow_hours_max_over_periods` and `flow_hours_min_over_periods` for weighted sum constraints across all periods

**Important**:
- Constraints with the `_over_periods` suffix compute weighted sums across all periods using the **raw** weights from period durations (or user-specified weights). These constraints always use unnormalized weights.
- The `normalize_weights` parameter (in `Calculation` or `FlowSystem.create_model()`) only affects the objective function, not the `_over_periods` constraints.
- Per-period constraints (without the suffix) apply separately to each individual period.

**Example**:
```python
# Per-period constraint: limits apply to EACH period individually
# With periods=[2020, 2030, 2040], this creates 3 separate constraints
effect = fx.Effect('costs', maximum_total=1000) # ≤1000 in 2020 AND ≤1000 in 2030 AND ≤1000 in 2040

# Over-periods constraint: limits apply to WEIGHTED SUM across ALL periods
# With periods=[2020, 2030, 2040] (auto-derived weights: [10, 10, 10] from 10-year intervals)
effect = fx.Effect('costs', maximum_over_periods=1000) # 10×costs₂₀₂₀ + 10×costs₂₀₃₀ + 10×costs₂₀₄₀ ≤ 1000

# Note: If normalize_weights=True, the objective uses normalized weights [0.33, 0.33, 0.33],
# but the constraint above still uses raw weights [10, 10, 10]
```

- **Auto-modeling**: `Calculation.solve()` now automatically calls `do_modeling()` if not already done, making the explicit `do_modeling()` call optional for simpler workflows
- **System validation**: Added `_validate_system_integrity()` to validate cross-element references (e.g., Flow.bus) immediately after transformation, providing clearer error messages
- **Element registration validation**: Added checks to prevent elements from being assigned to multiple FlowSystems simultaneously
- **Helper methods in Interface base class**: Added `_fit_coords()` and `_fit_effect_coords()` convenience wrappers for cleaner data transformation code
- **FlowSystem property in Interface**: Added `flow_system` property to access the linked FlowSystem with clear error messages if not yet linked

### 💥 Breaking Changes
- **FlowSystem weights parameter renamed**: The `weights` parameter in `FlowSystem.__init__()` has been renamed to `scenario_weights` to clarify that it only accepts scenario dimension weights (not period × scenario)
- Period weights are now **always computed internally** from the period index (similar to `hours_per_timestep` for time)
- The combined `weights` (period × scenario) are computed automatically by multiplying `period_weights × scenario_weights`
- only scenario_weights are normalized in the objective function

**Migration**: Update your code from:
```python
# Old (v3.6 and earlier)
fs = FlowSystem(..., weights=np.array([0.3, 0.5, 0.2])) # scenario weights
```

To:
```python
# New (v3.7+)
fs = FlowSystem(..., scenario_weights=np.array([0.3, 0.5, 0.2]))
```

**Note**: If you were previously passing period × scenario weights to `weights`, you now need to:
1. Pass only scenario weights to `scenario_weights`
2. Period weights will be computed automatically from your `periods` index

### ♻️ Changed
- **Period weights now computed from period index**: FlowSystem now computes `period_weights` automatically from the period index (using period intervals/differences), making weight handling consistent with `hours_per_timestep` for time dimension
- Added `_update_period_metadata()` method (analogous to `_update_time_metadata()`) to recalculate weights when periods are selected
- Period weights are stored separately in `FlowSystem.period_weights` (1D array with 'period' dimension)
- Scenario weights are stored in `FlowSystem.scenario_weights` (1D array with 'scenario' dimension)
- Combined weights `FlowSystem.weights` (2D array with 'period' and 'scenario' dimensions) are computed via `_compute_weights()` method

- **Refactored FlowSystem-Element coupling**:
- Introduced `_set_flow_system()` method in Interface base class to propagate FlowSystem reference to nested Interface objects
- Each Interface subclass now explicitly propagates the reference to its nested interfaces (e.g., Component → OnOffParameters, Flow → InvestParameters)
Expand All @@ -83,19 +132,48 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
- `Boiler`: `eta` → `thermal_efficiency`
- `Power2Heat`: `eta` → `thermal_efficiency`
- `CHP`: `eta_th` → `thermal_efficiency`, `eta_el` → `electrical_efficiency`
- `HetaPump`: `COP` → `cop`
- `HetaPumpWithSource`: `COP` → `cop`
- `HeatPump`: `COP` → `cop`
- `HeatPumpWithSource`: `COP` → `cop`
- **Storage Parameters**:
- `Storage`: `initial_charge_state="lastValueOfSim"` → `initial_charge_state="equals_last"`

- **Parameter naming consistency**: Established consistent naming pattern for constraint parameters across `Effect`, `Flow`, and `OnOffParameters`:
- Per-period constraints use no suffix or clarified names (e.g., `minimum_total`, `flow_hours_max`, `on_hours_min`)
- Sum-over-all-periods constraints use `_over_periods` suffix (e.g., `minimum_over_periods`, `flow_hours_max_over_periods`)

- **Flow parameters** (renamed for consistency):
- Renamed `flow_hours_total_max` → `flow_hours_max` (per-period constraint)
- Renamed `flow_hours_total_min` → `flow_hours_min` (per-period constraint)

- **OnOffParameters** (renamed for consistency):
- Renamed `on_hours_total_max` → `on_hours_max` (per-period constraint)
- Renamed `on_hours_total_min` → `on_hours_min` (per-period constraint)
- Renamed `switch_on_total_max` → `switch_on_max` (per-period constraint)

### 🗑️ Deprecated
- **Old parameter names in `linear_converters.py`**: The following parameter names are now deprecated and accessible as properties/kwargs that emit `DeprecationWarning`. They will be removed in v4.0.0:
- **Flow parameters**: `Q_fu`, `Q_th`, `P_el`, `Q_ab` (use `fuel_flow`, `thermal_flow`, `electrical_flow`, `heat_source_flow` instead)
- **Efficiency parameters**: `eta`, `eta_th`, `eta_el` (use `thermal_efficiency`, `electrical_efficiency` instead)
- **COP parameter**: `COP` (use lowercase `cop` instead)
- **Storage Parameter**: `Storage`: `initial_charge_state="lastValueOfSim"` (use `initial_charge_state="equals_last"`)


- **Flow parameters**: `flow_hours_total_max`, `flow_hours_total_min` (use `flow_hours_max`, `flow_hours_min`)
- **OnOffParameters**: `on_hours_total_max`, `on_hours_total_min`, `switch_on_total_max` (use `on_hours_max`, `on_hours_min`, `switch_on_max`)

**Migration**: Simply rename parameters by removing `_total` from the middle:
- `flow_hours_total_max` → `flow_hours_max`
- `on_hours_total_min` → `on_hours_min`
- `switch_on_total_max` → `switch_on_max`

All deprecated parameter names continue to work with deprecation warnings for backward compatibility. **Deprecated names will be removed in version 4.0.0.** Please update your code to use the new parameter names. Additional property aliases have been added internally to handle various naming variations that may have been used.


### 🐛 Fixed
- **Fixed weights not recalculating when using `.sel()` on periods**: `FlowSystem.sel()` and `FlowSystem.isel()` now correctly recalculate `period_weights` and `weights` when selecting a subset of periods (previously weights would be incorrectly sliced instead of recomputed from the new period index)
- Added `_update_period_metadata()` call in `_dataset_sel()` and `_dataset_isel()` to ensure weights stay consistent with selected periods
- This matches the existing behavior for time dimension where `hours_per_timestep` is recalculated on selection

- Fixed inconsistent argument passing in `_fit_effect_coords()` - standardized all calls to use named arguments (`prefix=`, `effect_values=`, `suffix=`) instead of mix of positional and named arguments
- Fixed `check_bounds` function in `linear_converters.py` to normalize array inputs before comparisons, ensuring correct boundary checks with DataFrames, Series, and other array-like types

Expand All @@ -104,6 +182,10 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
- Added comprehensive docstrings to `_do_modeling()` methods explaining the pattern: "Create variables, constraints, and nested submodels"
- Added missing type hints throughout the codebase
- Improved code organization by making FlowSystem reference propagation explicit and traceable
- **System validation**: Added `_validate_system_integrity()` to validate cross-element references (e.g., Flow.bus) immediately after transformation, providing clearer error messages
- **Element registration validation**: Added checks to prevent elements from being assigned to multiple FlowSystems simultaneously
- **Helper methods in Interface base class**: Added `_fit_coords()` and `_fit_effect_coords()` convenience wrappers for cleaner data transformation code
- **FlowSystem property in Interface**: Added `flow_system` property to access the linked FlowSystem with clear error messages if not yet linked

---

Expand Down
71 changes: 59 additions & 12 deletions docs/user-guide/mathematical-notation/dimensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ flow_system = fx.FlowSystem(
timesteps=timesteps,
periods=periods,
scenarios=scenarios,
weights=np.array([0.5, 0.5]) # Scenario weights
scenario_weights=np.array([0.5, 0.5]) # Scenario weights
)
```

Expand Down Expand Up @@ -220,28 +220,75 @@ Where:

Weights determine the relative importance of scenarios and periods in the objective function.

**Specification:**
### Scenario Weights

You provide scenario weights explicitly via the `scenario_weights` parameter:

```python
flow_system = fx.FlowSystem(
timesteps=timesteps,
periods=periods,
scenarios=scenarios,
weights=weights # Shape depends on dimensions
scenario_weights=np.array([0.3, 0.7]) # Scenario probabilities
)
```

**Weight Dimensions:**
**Default:** If not specified, all scenarios have equal weight (normalized to sum to 1).

### Period Weights

Period weights are **automatically computed** from the period index (similar to how `hours_per_timestep` is computed from the time index):

| Dimensions Present | Weight Shape | Example | Meaning |
|-------------------|--------------|---------|---------|
| Time + Scenario | 1D array of length `n_scenarios` | `[0.3, 0.7]` | Scenario probabilities |
| Time + Period | 1D array of length `n_periods` | `[0.5, 0.3, 0.2]` | Period importance |
| Time + Period + Scenario | 2D array `(n_periods, n_scenarios)` | `[[0.25, 0.25], [0.25, 0.25]]` | Combined weights |
```python
# Period weights are computed from the differences between period values
periods = pd.Index([2020, 2025, 2030, 2035])
# → period_weights = [5, 5, 5, 5] (representing 5-year intervals)

**Default:** If not specified, all scenarios/periods have equal weight (normalized to sum to 1).
flow_system = fx.FlowSystem(
timesteps=timesteps,
periods=periods,
# No need to specify period weights - they're computed automatically
)
```

**How period weights are computed:**
- For periods `[2020, 2025, 2030, 2035]`, the weights are `[5, 5, 5, 5]` (the interval sizes)
- This ensures that when you use `.sel()` to select a subset of periods, the weights are correctly recalculated
- You can specify `weight_of_last_period` if the last period weight cannot be inferred from the index

### Combined Weights

When both periods and scenarios are present, the combined `weights` array (accessible via `flow_system.model.objective_weights`) is computed as:

$$
w_{y,s} = w_y \times \frac{w_s}{\sum_{s \in \mathcal{S}} w_s}
$$

Where:
- $w_y$ are the period weights (computed from period index)
- $w_s$ are the scenario weights (user-specified)
- $\mathcal{S}$ is the set of all scenarios
- The scenario weights are normalized to sum to 1 before multiplication

**Example:**
```python
periods = pd.Index([2020, 2030, 2040]) # → period_weights = [10, 10, 10]
scenarios = pd.Index(['Base', 'High'])
scenario_weights = np.array([0.6, 0.4])

flow_system = fx.FlowSystem(
timesteps=timesteps,
periods=periods,
scenarios=scenarios,
scenario_weights=scenario_weights
)

# Combined weights shape: (3 periods, 2 scenarios)
# [[6.0, 4.0], # 2020: 10 × [0.6, 0.4]
# [6.0, 4.0], # 2030: 10 × [0.6, 0.4]
# [6.0, 4.0]] # 2040: 10 × [0.6, 0.4]
```

**Normalization:** Set `normalize_weights=True` in `Calculation` to automatically normalize weights to sum to 1.
**Normalization:** Set `normalize_weights=False` in `Calculation` to turn of the normalization.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ For equipment with OnOffParameters, the complete constraint system includes:
**Key Parameters:**
- `effects_per_switch_on`: Costs per startup event
- `effects_per_running_hour`: Costs per hour of operation
- `on_hours_total_min`, `on_hours_total_max`: Total runtime bounds
- `on_hours_min`, `on_hours_max`: Total runtime bounds
- `consecutive_on_hours_min`, `consecutive_on_hours_max`: Consecutive runtime bounds
- `consecutive_off_hours_min`, `consecutive_off_hours_max`: Consecutive shutdown bounds
- `switch_on_total_max`: Maximum number of startups
- `switch_on_max`: Maximum number of startups
- `force_switch_on`: Create switch variables even without limits (for tracking)

See the [`OnOffParameters`][flixopt.interface.OnOffParameters] API documentation for complete parameter list and usage examples.
Expand All @@ -265,7 +265,7 @@ power_plant = OnOffParameters(
effects_per_running_hour={'fixed_om': 125}, # €125/hour while running
consecutive_on_hours_min=8, # Minimum 8-hour run
consecutive_off_hours_min=4, # 4-hour cooling period
on_hours_total_max=6000, # Annual limit
on_hours_max=6000, # Annual limit
)
```

Expand All @@ -276,7 +276,7 @@ batch_reactor = OnOffParameters(
consecutive_on_hours_min=12, # 12-hour minimum batch
consecutive_on_hours_max=24, # 24-hour maximum batch
consecutive_off_hours_min=6, # Cleaning time
switch_on_total_max=200, # Max 200 batches
switch_on_max=200, # Max 200 batches
)
```

Expand All @@ -286,7 +286,7 @@ hvac = OnOffParameters(
effects_per_switch_on={'compressor_wear': 0.5},
consecutive_on_hours_min=1, # Prevent short cycling
consecutive_off_hours_min=0.5, # 30-min minimum off
switch_on_total_max=2000, # Limit compressor starts
switch_on_max=2000, # Limit compressor starts
)
```

Expand All @@ -296,7 +296,7 @@ backup_gen = OnOffParameters(
effects_per_switch_on={'fuel_priming': 50}, # L diesel
consecutive_on_hours_min=0.5, # 30-min test duration
consecutive_off_hours_max=720, # Test every 30 days
on_hours_total_min=26, # Weekly testing requirement
on_hours_min=26, # Weekly testing requirement
)
```

Expand Down
8 changes: 4 additions & 4 deletions examples/02_Complex/complex_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@
relative_minimum=5 / 50, # Minimum part load
relative_maximum=1, # Maximum part load
previous_flow_rate=50, # Previous flow rate
flow_hours_total_max=1e6, # Total energy flow limit
flow_hours_max=1e6, # Total energy flow limit
on_off_parameters=fx.OnOffParameters(
on_hours_total_min=0, # Minimum operating hours
on_hours_total_max=1000, # Maximum operating hours
on_hours_min=0, # Minimum operating hours
on_hours_max=1000, # Maximum operating hours
consecutive_on_hours_max=10, # Max consecutive operating hours
consecutive_on_hours_min=np.array([1, 1, 1, 1, 1, 2, 2, 2, 2]), # min consecutive operation hours
consecutive_off_hours_max=10, # Max consecutive off hours
effects_per_switch_on=0.01, # Cost per switch-on
switch_on_total_max=1000, # Max number of starts
switch_on_max=1000, # Max number of starts
),
),
fuel_flow=fx.Flow(label='Q_fu', bus='Gas', size=200),
Expand Down
4 changes: 3 additions & 1 deletion examples/04_Scenarios/scenario_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@
# Base Case: 60% probability, High Demand: 40% probability
scenario_weights = np.array([0.6, 0.4])

flow_system = fx.FlowSystem(timesteps=timesteps, periods=periods, scenarios=scenarios, weights=scenario_weights)
flow_system = fx.FlowSystem(
timesteps=timesteps, periods=periods, scenarios=scenarios, scenario_weights=scenario_weights
)

# --- Define Energy Buses ---
# These represent nodes, where the used medias are balanced (electricity, heat, and gas)
Expand Down
4 changes: 2 additions & 2 deletions flixopt/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class for defined way of solving a flow_system optimization
name: name of calculation
flow_system: flow_system which should be calculated
folder: folder where results should be saved. If None, then the current working directory is used.
normalize_weights: Whether to automatically normalize the weights (periods and scenarios) to sum up to 1 when solving.
normalize_weights: Whether to automatically normalize the weights of scenarios to sum up to 1 when solving.
active_timesteps: Deprecated. Use FlowSystem.sel(time=...) or FlowSystem.isel(time=...) instead.
"""

Expand Down Expand Up @@ -182,7 +182,7 @@ class FullCalculation(Calculation):
name: name of calculation
flow_system: flow_system which should be calculated
folder: folder where results should be saved. If None, then the current working directory is used.
normalize_weights: Whether to automatically normalize the weights (periods and scenarios) to sum up to 1 when solving.
normalize_weights: Whether to automatically normalize the weights of scenarios to sum up to 1 when solving.
active_timesteps: Deprecated. Use FlowSystem.sel(time=...) or FlowSystem.isel(time=...) instead.
"""

Expand Down
2 changes: 1 addition & 1 deletion flixopt/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ class Transmission(Component):
on_off_parameters=OnOffParameters(
effects_per_switch_on={'maintenance': 0.1},
consecutive_on_hours_min=2, # Minimum 2-hour operation
switch_on_total_max=10, # Maximum 10 starts per day
switch_on_max=10, # Maximum 10 starts per day
),
Comment on lines +650 to 651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Docs: rename looks consistent with API (switch_on_max).

Good alignment with the new OnOffParameters naming.

Quick sweep for lingering old names:


🏁 Script executed:

#!/bin/bash
rg -nP --glob '!**/site/**' '(on_hours_total_(min|max)|switch_on_total_max|flow_hours_total_(min|max))'

Length of output: 6321


Update parameter names across tests, documentation, and examples for API consistency.

The verification found lingering old parameter names in multiple locations beyond the file in scope:

  • Test files (tests/test_*.py, tests/conftest.py): Still using on_hours_total_min/max, switch_on_total_max, flow_hours_total_min/max
  • Documentation examples (docs/user-guide/mathematical-notation/features/OnOffParameters.md): Example code uses old names
  • Reference examples (examples/02_Complex/complex_example.py): All parameter names need updating
  • Docstring (flixopt/calculation.py:428): Mentions old names in constraint documentation

While the backward compatibility layer in flixopt/elements.py and flixopt/interface.py keeps these working, the tests and examples should migrate to the new names (on_hours_min/max, switch_on_max, flow_hours_min/max) to serve as proper reference material and ensure consistent migration across the codebase.

🤖 Prompt for AI Agents
In flixopt/components.py around lines 636 to 637, the code and surrounding
project materials still reference old parameter names (on_hours_total_min/max,
switch_on_total_max, flow_hours_total_min/max); update all usages to the new API
names (on_hours_min/on_hours_max, switch_on_max, flow_hours_min/flow_hours_max).
Search and replace these names across tests (tests/test_*.py,
tests/conftest.py), documentation examples
(docs/user-guide/mathematical-notation/features/OnOffParameters.md), reference
examples (examples/02_Complex/complex_example.py), and the docstring in
flixopt/calculation.py (around line 428), ensuring signatures, examples, and
constraint text use the new names; keep the backward-compatibility layer
untouched. After changes, run the test suite and update any failing assertions
or example outputs that reference the old names.

)
```
Expand Down
Loading