Loss functions (evopt.loss)
Warning
This module is part of the internal implementation of evopt and is not intended for direct use by end users. Its API may change without notice.
Multi-objective loss calculation for evolutionary optimization.
This module provides functionality for calculating loss values in optimization scenarios with multiple objectives and constraints. It supports both hard and soft constraints, with configurable weighting between them.
The module implements normalized error calculations to handle objectives with different scales and provides mechanisms to distinguish between hard constraints (must be satisfied) and soft objectives (should be optimized).
Example
Basic usage with target values and observed results:
>>> from evopt.loss import calc_loss
>>>
>>> # Define target values with constraints
>>> targets = {
... 'weight': 10.0, # Target weight (default: hard constraint)
... 'stress': (0, 50), # Stress must be between 0 and 50
... 'deflection': {'value': 0.5, 'hard': False} # Soft objective
... }
>>>
>>> # Observed values from evaluation
>>> observed = {
... 'weight': 12.5,
... 'stress': 30.2,
... 'deflection': 0.8
... }
>>>
>>> # Calculate loss
>>> loss = calc_loss(targets, observed, method="mae")
>>> print(f"Combined loss: {loss.combined_loss}")
>>> print(f"Observed values: {loss.observed_dict}")
- class evopt.loss.CLoss(target_dict: dict, method='mae', verbose: bool = False, hard_to_soft_weight: float = 0.95)[source]
Bases:
objectLoss calculator for multi-objective optimization with constraints.
This class handles the calculation of loss values when optimizing against multiple objectives with both hard and soft constraints. It normalizes errors across different scales and can weight hard constraints more heavily than soft objectives.
Hard constraints are treated as requirements that must be satisfied, while soft objectives are goals that should be optimized but can be compromised. The final loss combines both types with configurable weighting.
- target_dict
Dictionary of target values with optional constraint settings.
- method
Error calculation method (‘mse’ or ‘mae’).
- verbose
Whether to print detailed information during calculation.
- w
Weight factor for hard constraints (between 0 and 1).
- observed_dict
Dictionary of mean observed values after calculation.
- combined_loss
The final weighted loss value after calculation.
Examples
Creating a loss calculator and computing loss:
>>> targets = {'stress': (0, 100), 'weight': 50.0} >>> observed = {'stress': 80.0, 'weight': 55.2} >>> loss_calc = CLoss(targets, method='mae', verbose=True) >>> loss_calc.calc_loss(observed) >>> print(f"Loss: {loss_calc.combined_loss}")
- calc_loss(observed_dict: dict) float[source]
Calculate the combined loss across all constraints and objectives.
Processes the observed values for each key in target_dict, computing individual errors and determining if constraints are satisfied. Hard constraints and soft objectives are weighted according to the hard_to_soft_weight parameter.
- Parameters:
observed_dict – Dictionary of observed values with the same keys as target_dict. Values can be single numbers, lists, or arrays.
- Returns:
The combined loss value is stored in self.combined_loss but not returned.
- Return type:
float
- Raises:
KeyError – If a key in target_dict is not found in observed_dict.
Note
After calling this method, access the results via self.combined_loss and self.observed_dict properties.
Example
>>> targets = { ... 'weight': 10.0, ... 'stress': {'value': 50.0, 'hard': True}, ... 'deflection': {'value': 0.5, 'hard': False} ... } >>> observed = { ... 'weight': 12.5, ... 'stress': 80.0, ... 'deflection': 0.8 ... } >>> loss_calc = CLoss(targets) >>> loss_calc.calc_loss(observed) >>> print(f"Combined loss: {loss_calc.combined_loss}")
- calculate_error(target_values, observed_values) float[source]
Calculate normalized error between target and observed values.
Computes a normalized error measure that handles different scales automatically. The normalization divides the difference by the sum of absolute values plus 1, making the error scale-independent. NaN values in observed data are ignored.
- Parameters:
target_values – List or array of target values.
observed_values – List or array of observed values.
- Returns:
Normalized error value (MAE or MSE based on the configured method).
- Return type:
float
Note
Returns NaN if all observed values are NaN.
Example
>>> loss_calc = CLoss({"dummy": 0}) >>> error = loss_calc.calculate_error([10, 20, 30], [12, 18, 35]) >>> print(f"Error: {error:.4f}") # Output depends on method
- constraint_satisfied(key: str, observed_values: list) bool[source]
Check if observed values satisfy the constraint for a given key.
Determines whether observed values meet the constraint defined in target_dict. For single values, a 5% tolerance is applied unless the constraint is defined as a range using a tuple.
- Parameters:
key – The key in target_dict to check.
observed_values – List of observed values to check against the constraint.
- Returns:
- True if the constraint is satisfied (at least 50% of values within bounds),
False otherwise.
- Return type:
bool
Note
Returns False if observed_values is empty or contains only None/NaN.
Example
>>> targets = {'stress': (0, 100)} # Stress must be between 0 and 100 >>> loss_calc = CLoss(targets) >>> satisfied = loss_calc.constraint_satisfied('stress', [50, 80, 120]) >>> print(f"Constraint satisfied: {satisfied}") # True (2/3 within bounds)
- evopt.loss.calc_loss(target_dict: dict, observed_dict: dict, method: str = 'mse', hard_to_soft_weight: float = 0.95, verbose: bool = False) CLoss[source]
Convenience function to calculate loss for multi-objective optimization.
Creates a CLoss object with the specified parameters, calculates the loss, and returns the configured loss calculator for further access to results.
- Parameters:
target_dict – Dictionary of target values and constraint specifications. See CLoss class documentation for format details.
observed_dict – Dictionary of observed values to evaluate.
method – Error calculation method (‘mse’ or ‘mae’). Default is ‘mse’.
hard_to_soft_weight – Weight for balancing hard vs. soft constraints (0.0-1.0). Default is 0.9 (90% weight to hard constraints).
verbose – Whether to print detailed calculation information. Default is False.
- Returns:
- Configured loss calculator object with results accessible via
the combined_loss and observed_dict properties.
- Return type:
CLoss
- Raises:
KeyError – If a key in target_dict is not found in observed_dict.
Example
>>> targets = {'weight': 10.0, 'stress': (0, 100)} >>> observed = {'weight': 12.5, 'stress': 80.0} >>> loss = calc_loss(targets, observed, method='mae', verbose=True) >>> print(f"Combined loss: {loss.combined_loss}") >>> print(f"Observed values: {loss.observed_dict}")