Solution Module API¶
The solution module provides classes for working with optimization solutions, including variable value access, sensitivity analysis, and solution mapping.
Overview¶
The solution module implements type-safe solution handling with automatic mapping from solver indices to user data:
graph LR
A[Solver] --> B[LXSolution]
B --> C[Variable Values]
B --> D[Mapped Values]
B --> E[Sensitivity Data]
B --> F[Goal Deviations]
G[LXSolutionMapper] --> D
H[Data Models] --> G
style B fill:#e1f5ff
style C fill:#fff4e1
style D fill:#ffe1e1
style E fill:#e1ffe1
style F fill:#f0e1ff
Components¶
Solution Container¶
Type-safe solution with automatic mapping. |
The LXSolution class provides comprehensive access to:
Variable values (direct and mapped)
Solution metadata (status, objective, solve time)
Sensitivity analysis data (shadow prices, reduced costs)
Goal programming information (deviations, satisfaction)
Solution Mapper¶
Maps solution values back to ORM model instances. |
The LXSolutionMapper class provides utilities for:
Mapping solution values to model instances
Handling single-indexed variables
Processing multi-indexed variables
Working with cartesian product results
Detailed API Reference¶
LXSolution¶
Solution classes for LumiX.
- class lumix.solution.solution.LXSolution(objective_value, status, solve_time, variables=<factory>, mapped=<factory>, shadow_prices=<factory>, reduced_costs=<factory>, gap=None, iterations=None, nodes=None, goal_deviations=<factory>)[source]
Bases:
Generic[TModel]Type-safe solution with automatic mapping.
Provides access to:
Variable values (by name or LXVariable object)
Mapped values (variables mapped by index keys)
Shadow prices (dual values for constraints)
Reduced costs (for sensitivity analysis)
Examples
Basic usage:
solution = optimizer.solve(model) # Access by variable name prod_value = solution.variables["production"] # Access by LXVariable object prod_value = solution.get_variable(production) # Access multi-indexed variables duty_value = solution.variables["duty"][(driver_id, date)] # Access mapped values (indexed by keys) for key, value in solution.get_mapped(duty).items(): if value > 0.5: print(f"Variable {key} = {value}")
- Parameters:
-
objective_value:
float
-
status:
str
-
solve_time:
float
- get_variable(var)[source]
Get variable value with full type inference.
- get_mapped(var)[source]
Get values mapped by index keys.
Returns the same structure as variables, indexed by the keys extracted via the variable’s index_func (e.g., product.id).
Note
This returns index keys, not model instances, to avoid hashability issues with non-frozen dataclasses.
- Parameters:
var (
LXVariable[TypeVar(TModel),TypeVar(TValue,int,float)]) – LXVariable to get mapped values for- Return type:
- Returns:
Dictionary mapping index keys to values
Examples
For production indexed by product.id:
for product_id, qty in solution.get_mapped(production).items(): print(f"Product {product_id}: {qty} units")
- get_shadow_price(constraint_name)[source]
Get shadow price (dual value) for constraint.
- get_reduced_cost(var_name)[source]
Get reduced cost for variable.
- get_goal_deviations(goal_name)[source]
Get deviation values for a goal constraint.
Returns both positive and negative deviations for the specified goal.
- Parameters:
goal_name (
str) – Name of the goal constraint- Return type:
- Returns:
Dictionary with keys ‘pos’ and ‘neg’ containing deviation values, or None if goal not found
Example
>>> deviations = solution.get_goal_deviations("production_target") >>> pos_dev = deviations["pos"] # Over-production >>> neg_dev = deviations["neg"] # Under-production
- is_goal_satisfied(goal_name, tolerance=1e-06)[source]
Check if a goal is satisfied within tolerance.
A goal is satisfied if both positive and negative deviations are within the specified tolerance.
- Parameters:
- Return type:
- Returns:
True if goal is satisfied, False if not, None if goal not found
Example
>>> if solution.is_goal_satisfied("demand_goal", tolerance=0.01): ... print("Demand goal achieved!")
- get_total_deviation(goal_name)[source]
Get total absolute deviation for a goal.
Sum of absolute values of all positive and negative deviations.
- Parameters:
goal_name (
str) – Name of the goal constraint- Return type:
- Returns:
Total deviation, or None if goal not found
Example
>>> total_dev = solution.get_total_deviation("production_target") >>> print(f"Total deviation: {total_dev}")
- visualize(model=None)[source]
Create interactive visualization for this solution.
Requires the visualization extra: pip install lumix-opt[viz]
- Parameters:
model (
Optional[LXModel[TypeVar(TModel)]]) – Optional optimization model (for constraint info)- Return type:
LXSolutionVisualizer[TypeVar(TModel)]- Returns:
LXSolutionVisualizer instance
Examples
Basic usage:
solution.visualize().show()
With model for constraint details:
solution.visualize(model).show()
Export to HTML:
solution.visualize(model).to_html("solution.html")
- __init__(objective_value, status, solve_time, variables=<factory>, mapped=<factory>, shadow_prices=<factory>, reduced_costs=<factory>, gap=None, iterations=None, nodes=None, goal_deviations=<factory>)
Key Attributes:
objective_value: Final objective function valuestatus: Solution status string (optimal, feasible, infeasible, etc.)solve_time: Time taken to solve in secondsvariables: Dictionary mapping variable names to values (solver indices)mapped: Dictionary mapping variable names to values (data keys)shadow_prices: Shadow prices (dual values) for constraintsreduced_costs: Reduced costs for variablesgap: Optimality gap (for MIP)iterations: Number of solver iterationsnodes: Number of branch-and-bound nodesgoal_deviations: Deviation values for goal programming
Key Methods:
get_variable(var): Get variable value with type inferenceget_mapped(var): Get values mapped by index keysget_shadow_price(constraint_name): Get shadow price for constraintget_reduced_cost(var_name): Get reduced cost for variableget_goal_deviations(goal_name): Get goal deviation valuesis_goal_satisfied(goal_name, tolerance): Check if goal is achievedget_total_deviation(goal_name): Get total absolute deviationis_optimal(): Check if solution is optimalis_feasible(): Check if solution is feasiblesummary(): Get formatted solution summary
LXSolutionMapper¶
Solution mapping utilities for LumiX.
- class lumix.solution.mapping.LXSolutionMapper[source]
Bases:
Generic[TModel]Maps solution values back to ORM model instances.
Handles: - Single-indexed variables - Multi-indexed variables - Join-based variables
- map_variable_to_models(var, solution_values, model_instances)[source]
Map variable values to model instances.
- Parameters:
- Return type:
- Returns:
Dictionary mapping model instances to values
- map_multi_indexed_variable(var, solution_values)[source]
Map multi-indexed variable values to model instance tuples.
Key Methods:
map_variable_to_models(var, solution_values, model_instances): Map solution values to model instances for single-indexed variablesmap_multi_indexed_variable(var, solution_values): Map solution values to model instance tuples for multi-indexed variables
Usage Examples¶
Basic Solution Access¶
from lumix import LXOptimizer, LXModel, LXVariable
# Solve model
optimizer = LXOptimizer().use_solver("gurobi")
solution = optimizer.solve(model)
# Check status
if solution.is_optimal():
print(f"Optimal objective: {solution.objective_value:.2f}")
# Access variable values
for key, value in solution.get_mapped(production).items():
print(f"Product {key}: {value} units")
Sensitivity Analysis¶
# Get shadow price
shadow_price = solution.get_shadow_price("capacity_constraint")
if shadow_price:
print(f"Value of additional capacity: ${shadow_price:.2f}")
# Get reduced cost
reduced_cost = solution.get_reduced_cost("production[product_A]")
if reduced_cost:
print(f"Cost reduction needed: ${reduced_cost:.2f}")
Goal Programming¶
# Check goal satisfaction
if solution.is_goal_satisfied("demand_target"):
print("Demand goal achieved!")
else:
deviations = solution.get_goal_deviations("demand_target")
print(f"Positive deviation: {deviations['pos']}")
print(f"Negative deviation: {deviations['neg']}")
# Get total deviation
total_dev = solution.get_total_deviation("demand_target")
print(f"Total deviation: {total_dev:.2f}")
Solution Mapping¶
from lumix.solution import LXSolutionMapper
# Create mapper
mapper = LXSolutionMapper[Product]()
# Map to model instances
instance_values = mapper.map_variable_to_models(
var=production,
solution_values=solution.mapped["production"],
model_instances=products
)
# Process by instance
for product, quantity in instance_values.items():
print(f"{product.name}: {quantity} units")
Multi-Indexed Variables¶
# Map multi-indexed solution
instance_map = mapper.map_multi_indexed_variable(
var=assignment,
solution_values=solution.mapped["assignment"]
)
# Result: {(Driver(id=1), Date(date="2024-01-01")): 1, ...}
for (driver, date), assigned in instance_map.items():
if assigned > 0.5:
print(f"{driver.name} assigned on {date.date}")
Solution Summary¶
# Get formatted summary
print(solution.summary())
Output:
Status: optimal
Objective: 12345.678900
Solve time: 0.123s
Non-zero variables: 42/100
Gap: 0.00%
Iterations: 125
Goal Constraints: 3
Goals Satisfied: 2/3
Type Hints¶
The solution module is fully type-annotated:
from typing import Dict, Any, Union, Optional, Tuple
from lumix.solution import LXSolution, LXSolutionMapper
from lumix.core import LXVariable
# Type-safe solution access
solution: LXSolution[Product]
value: Union[float, Dict[Any, float]] = solution.get_variable(production)
# Type-safe mapping
mapper: LXSolutionMapper[Product]
instance_map: Dict[Product, float] = mapper.map_variable_to_models(...)
See Also¶
Core Module API - Core module (variables, constraints, models)
Nonlinear Module API - Nonlinear terms
Linearization Module API - Automatic linearization
Utils Module API - Utility components