Core Module API¶
The core module provides the fundamental building blocks for creating optimization models in LumiX.
Overview¶
The core module implements a type-safe, data-driven approach to optimization modeling through five main components:
graph TD
A[LXModel] --> B[LXVariable]
A --> C[LXConstraint]
A --> D[LXExpression]
B --> D
C --> D
E[LXEnums] --> B
E --> C
E --> A
style A fill:#e1f5ff
style B fill:#fff4e1
style C fill:#ffe1e1
style D fill:#e1ffe1
style E fill:#f0e1ff
Components¶
Model Builder¶
Main model builder with full type safety and IDE support. |
The LXModel class is the central component for building optimization models.
It uses the Builder pattern with a fluent API.
Variables¶
Variable Family - represents multiple solver variables indexed by data models. |
The LXVariable class represents variable families that automatically
expand to multiple solver variables based on data.
Constraints¶
Constraint Family - represents multiple constraints indexed by data models. |
The LXConstraint class represents constraint families that automatically
expand to multiple solver constraints based on data.
Expressions¶
Type-safe linear expression builder with multi-model support. |
|
Quadratic expression: linear_terms + quadratic_terms + constant |
|
Non-linear expression containing arbitrary non-linear terms. |
|
Quadratic term: coeff * var1 * var2 |
Expression classes for building objective functions and constraint left-hand sides.
Enumerations¶
Variable type enumeration for optimization variables. |
|
Constraint sense enumeration for inequality and equality constraints. |
|
Objective sense enumeration for optimization direction. |
Type-safe enumerations for variable types, constraint senses, and objective directions.
Detailed API Reference¶
Model¶
Model builder class for LumiX optimization models.
This module provides the LXModel class, which is the central component for building optimization models in LumiX. It implements the Builder pattern with fluent API for creating type-safe, data-driven optimization models.
- The model serves as a container for:
Variable families (decision variables indexed by data)
Constraint families (constraints indexed by data)
Objective function (linear or quadratic expression)
Goal programming metadata (for multi-objective optimization)
- Key Features:
Fluent API: Method chaining for concise model building
Type Safety: Generic type parameter for compile-time type checking
Goal Programming: Native support for multi-objective optimization
Auto-expansion: Variable and constraint families expand automatically
- Architecture:
LXModel uses the Builder pattern where each method returns self to enable method chaining. The model doesn’t create solver variables directly - instead, it stores variable and constraint families that are expanded during solving.
Examples
Simple production planning model:
from lumix import LXModel, LXVariable, LXConstraint, LXLinearExpression
# Create model
model = LXModel("production_plan")
# Add variables
production = LXVariable[Product, float]("production")\
.continuous()\
.bounds(lower=0)\
.from_data(products)
model.add_variable(production)
# Add constraints
capacity = LXConstraint("capacity")\
.expression(
LXLinearExpression().add_term(production, lambda p: p.usage)
)\
.le()\
.rhs(max_capacity)
model.add_constraint(capacity)
# Set objective
model.maximize(
LXLinearExpression().add_term(production, lambda p: p.profit)
)
Fluent API with method chaining:
model = (
LXModel[Product]("production")
.add_variable(production)
.add_constraint(capacity)
.maximize(profit_expr)
)
Goal programming for multi-objective optimization:
model = LXModel("multi_objective")\
.set_goal_mode("weighted")
# Mark constraints as goals with priorities
model.add_constraint(
profit_constraint.as_goal(priority=1, weight=1.0)
)
model.add_constraint(
quality_constraint.as_goal(priority=2, weight=0.8)
)
# Solve with goal programming solver
solution = optimizer.solve(model)
Note
The model is solver-agnostic. The same model can be solved with different solvers (OR-Tools, Gurobi, CPLEX, GLPK) by simply changing the optimizer configuration.
See also
LXVariable: Variable family builderLXConstraint: Constraint family builderLXLinearExpression: Linear expression builderLXOptimizer: Solver interface
- class lumix.core.model.LXModel(name)[source]
Bases:
Generic[TModel]Main model builder with full type safety and IDE support.
Creates and manages optimization models with:
Variables (single or multi-indexed)
Constraints (linear, indexed, multi-model)
Objective function (linear or quadratic)
Examples:
# Simple model model = LXModel("production_plan") model.add_variable(production) model.add_constraint(capacity_constraint) model.maximize( LXLinearExpression().add_term(production, lambda p: p.selling_price) ) # Type-safe model model = LXModel[Product]("production_plan") .add_variable(production) .add_constraint(capacity_constraint) .maximize( LXLinearExpression() .add_term(production, lambda p: p.selling_price - p.cost) )
- Parameters:
name (str)
- __deepcopy__(memo)[source]
Custom deepcopy that enables what-if analysis with ORM data sources.
This method orchestrates deep copying of the entire model including: 1. All variable families (with ORM data materialization) 2. All constraint families (with ORM data materialization) 3. Objective expression 4. Goal programming metadata
This is the central method that makes what-if analysis possible by creating independent copies of models that can be modified without affecting the original.
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this model with all ORM dependencies resolved
Note
After copying, all variables and constraints will have their ORM sessions detached and data materialized. The copy is completely independent and safe for serialization/pickling.
Example
>>> original_model = build_model_with_orm(session) >>> modified_model = deepcopy(original_model) >>> # modified_model can now be changed without affecting original_model
- __getstate__()[source]
Support for pickle protocol - detach ORM sessions before pickling.
- Returns:
Dictionary of instance state safe for pickling
- __setstate__(state)[source]
Support for pickle protocol - restore from pickled state.
- Parameters:
state – Dictionary of instance state from pickling
- add_variable(var)[source]
Add variable with full type checking.
- Parameters:
var (
LXVariable) – Variable to add- Return type:
Self- Returns:
Self for chaining
- add_variables(*variables)[source]
Add multiple variable families.
- Parameters:
*variables (
LXVariable) – Variables to add- Return type:
Self- Returns:
Self for chaining
- add_constraint(constraint)[source]
Add constraint with full type checking.
- Parameters:
constraint (
LXConstraint) – Constraint to add- Return type:
Self- Returns:
Self for chaining
- add_constraints(*constraints)[source]
Add multiple constraints.
- Parameters:
*constraints (
LXConstraint) – Constraints to add- Return type:
Self- Returns:
Self for chaining
- minimize(expr)[source]
Set objective to minimize.
- Parameters:
expr (
LXLinearExpression|LXQuadraticExpression) – Objective expression (linear or quadratic)- Return type:
Self- Returns:
Self for chaining
- maximize(expr)[source]
Set objective to maximize.
- Parameters:
expr (
LXLinearExpression|LXQuadraticExpression) – Objective expression (linear or quadratic)- Return type:
Self- Returns:
Self for chaining
- get_variable(name)[source]
Get variable family by name.
- Parameters:
name (
str) – Variable name- Return type:
- Returns:
LXVariable if found, None otherwise
- get_constraint(name)[source]
Get constraint by name.
- Parameters:
name (
str) – Constraint name- Return type:
- Returns:
LXConstraint if found, None otherwise
- set_goal_mode(mode)[source]
Set goal programming mode.
- Parameters:
mode (
str) – Goal programming mode (“weighted” or “sequential”)- Return type:
Self- Returns:
Self for chaining
- Raises:
ValueError – If mode is not “weighted” or “sequential”
Example
>>> model.set_goal_mode("weighted") >>> # Solve with weighted objectives (single solve)
>>> model.set_goal_mode("sequential") >>> # Solve lexicographically (multiple solves)
- prepare_goal_programming()[source]
Prepare model for goal programming by relaxing goal constraints.
This method: 1. Identifies constraints marked as goals (via .as_goal()) 2. Relaxes them by adding deviation variables 3. Builds the appropriate objective function based on mode 4. Adds deviation variables to the model 5. Replaces goal constraints with relaxed versions
This is automatically called by the solver, but can be called manually for inspection or debugging.
- Return type:
Self- Returns:
Self for chaining
Example
>>> model.set_goal_mode("weighted") >>> model.prepare_goal_programming() >>> # Model now has deviation variables and goal objective
- has_goals()[source]
Check if model has any goal constraints.
- Return type:
- Returns:
True if at least one constraint is marked as a goal
- populate_goal_deviations(solution)[source]
Populate goal deviation values in the solution.
Extracts deviation variable values from the solution and organizes them by goal name for easy access via solution.get_goal_deviations().
This method is automatically called after solving if the model has goals.
- Parameters:
solution (
LXSolution) – Solution object to populate- Return type:
- Returns:
The solution object with goal_deviations populated
Variables¶
Variable class with multi-indexing support for LumiX.
- class lumix.core.variables.LXVariable(name, var_type=LXVarType.CONTINUOUS, lower_bound=None, upper_bound=None, model_type=None, index_func=None, cost_func=None, _filter=None, _data=None, _session=None, _cartesian=None, _multi_cost_func=None, _join_config=None)[source]
Bases:
Generic[TModel,TValue]Variable Family - represents multiple solver variables indexed by data models.
IMPORTANT: LXVariable is NOT a single variable, but a FAMILY/TEMPLATE that automatically expands to multiple solver variables based on data.
When you write:
production = LXVariable[Product, float]("production").from_data(products)
This creates ONE LXVariable object that represents MANY solver variables:
production[product1], production[product2], production[product3], ...
The expansion happens automatically during model building - you don’t loop manually.
Supports:
Single-model indexing: LXVariable[Product, float]
Multi-model indexing: LXVariable[Tuple[Driver, Date], int]
Join-based sparse indexing
Cartesian product indexing
Examples:
# Single model - data-driven production = ( LXVariable[Product, float]("production") .continuous() .indexed_by(lambda p: p.id) .bounds(lower=0) .cost(lambda p: p.unit_cost) .from_data(products) # Provide the data directly ) # Or with ORM production = ( LXVariable[Product, float]("production") .continuous() .from_model(Product, session=session) # Query from ORM ) # Multi-model (cartesian product) duty = ( LXVariable[Tuple[Driver, Date], int]("duty") .binary() .indexed_by_product( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ) .where_multi(lambda driver, date: driver.is_active) )
- Parameters:
-
name:
str
-
var_type:
LXVarType= 'continuous'
- __deepcopy__(memo)[source]
Custom deepcopy that detaches ORM sessions and handles lambda closures.
This method enables what-if analysis on variables using ORM data sources by: 1. Materializing lazy-loaded ORM data before copying 2. Detaching ORM objects from database sessions 3. Safely copying lambda functions (index_func, cost_func, filters, etc.) 4. Deep copying cartesian products and join configurations
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this variable with all ORM dependencies resolved
Note
After copying, the new variable will have _session=None and all data stored in _data as detached objects safe for pickling.
- __getstate__()[source]
Support for pickle protocol - detach ORM sessions before pickling.
- Returns:
Dictionary of instance state safe for pickling
- __setstate__(state)[source]
Support for pickle protocol - restore from pickled state.
- Parameters:
state – Dictionary of instance state from pickling
- continuous()[source]
Set as continuous variable. Returns self for chaining.
- Return type:
Self
- integer()[source]
Set as integer variable. Returns self for chaining.
- Return type:
Self
- binary()[source]
Set as binary variable. Returns self for chaining.
- Return type:
Self
- bounds(lower=None, upper=None)[source]
Set variable bounds with full type checking.
- from_data(data)[source]
Provide data instances directly (for non-ORM usage).
- Parameters:
- Return type:
Self- Returns:
Self for chaining
Example
production = Variable[Product, float](“production”).from_data(products)
- from_model(model, session=None)[source]
Bind to ORM model type for automatic querying.
- Parameters:
- Return type:
Self- Returns:
Self for chaining
Example
production = Variable[Product, float](“production”).from_model(Product, session)
- get_instances()[source]
Get the data instances for this variable family.
- Return type:
- Returns:
List of model instances
- Raises:
ValueError – If no data source configured
- indexed_by(func)[source]
Define indexing function with full type inference.
- Parameters:
func (
Callable[[TypeVar(TModel)],TypeVar(TIndex)]) – Function to extract index from model instance- Return type:
Self- Returns:
Self for chaining
Examples
.indexed_by(lambda product: product.id) .indexed_by(lambda route: (route.origin, route.destination))
- indexed_by_product(dim1, dim2, *extra_dims)[source]
Index by cartesian product of multiple models. Creates variables for every valid combination.
- Parameters:
dim1 (
LXIndexDimension[TypeVar(TModel1)]) – First dimensiondim2 (
LXIndexDimension[TypeVar(TModel2)]) – Second dimension*extra_dims (
LXIndexDimension) – Additional dimensions for 3D+ indexing
- Return type:
Self- Returns:
Self for chaining
Example:
duty = LXVariable[Tuple[Driver, Date], int]("duty") .indexed_by_product( LXIndexDimension(Driver, lambda d: d.id) .where(lambda d: d.is_active), LXIndexDimension(Date, lambda dt: dt.date) .where(lambda dt: dt >= today) )
- indexed_by_join(primary, related, join_func, key_func=None)[source]
Index by a relationship/join between models. Only creates variables where relationship exists (sparse).
- Parameters:
- Return type:
Self- Returns:
Self for chaining
Example:
# Only create variables for valid driver-route assignments assignment = LXVariable[Tuple[Driver, Route], int]("assign") .indexed_by_join( Driver, Route, join_func=lambda d: d.qualified_routes, # ORM relationship key_func=lambda d, r: (d.id, r.id) )
- cost(func)[source]
Define objective coefficient from model.
- Parameters:
func (
Callable[[TypeVar(TModel)],float]) – Function to calculate cost from model- Return type:
Self- Returns:
Self for chaining
Example
.cost(lambda product: product.unit_cost)
- cost_multi(func)[source]
Define cost function for multi-indexed variables. Function receives all index models as arguments.
- Parameters:
func (
Callable[...,float]) – Function receiving all dimension models- Return type:
Self- Returns:
Self for chaining
Example
.cost_multi(lambda driver, date: driver.daily_rate * date.overtime_multiplier)
- where(predicate)[source]
Filter which model instances to include.
- Parameters:
predicate (
Callable[[TypeVar(TModel)],bool]) – Filter function- Return type:
Self- Returns:
Self for chaining
Example
.where(lambda p: p.is_active and p.stock > 0)
- where_multi(predicate)[source]
Filter multi-indexed variable combinations.
- Parameters:
predicate (
Callable[...,bool]) – Filter function receiving all dimension models- Return type:
Self- Returns:
Self for chaining
Example:
.where_multi(lambda driver, date, shift: driver.can_work_shift(shift) and date.weekday() not in driver.days_off )
- __init__(name, var_type=LXVarType.CONTINUOUS, lower_bound=None, upper_bound=None, model_type=None, index_func=None, cost_func=None, _filter=None, _data=None, _session=None, _cartesian=None, _multi_cost_func=None, _join_config=None)
- Parameters:
- Return type:
None
Constraints¶
Constraint class for LumiX optimization models.
- class lumix.core.constraints.LXConstraint(name, lhs=None, sense=LXConstraintSense.LE, rhs_value=None, rhs_func=None, model_type=None, index_func=None, _data=None, _session=None, goal_metadata=None)[source]
Bases:
Generic[TModel]Constraint Family - represents multiple constraints indexed by data models.
Like LXVariable, an LXConstraint represents a FAMILY of constraints that automatically expands to multiple solver constraints based on data.
Represents: LHS {<=, >=, ==} RHS
Examples:
# Simple single constraint LXConstraint("total_capacity") .expression(LXLinearExpression().add_term(production, 1.0)) .le() .rhs(100) # Constraint family - one per resource # Note: In multi-model constraints, the coefficient lambda receives instances from: # - p: Product (from the production variable's indexing) # - r: Resource (from this constraint's indexing) # This allows expressing relationships between different data models. LXConstraint[Resource]("capacity") .expression(LXLinearExpression().add_term(production, lambda p, r: p.usage[r.id])) .le() .rhs(lambda r: r.capacity) .from_data(resources) .indexed_by(lambda r: r.id)
- Parameters:
name (str)
lhs (LXLinearExpression[TModel] | None)
sense (LXConstraintSense)
rhs_value (float | None)
model_type (Type[TModel] | None)
index_func (Callable[[TModel], TIndex] | None)
_data (List[TModel] | None)
_session (Any | None)
goal_metadata (LXGoalMetadata | None)
-
name:
str
-
lhs:
Optional[LXLinearExpression[TypeVar(TModel)]] = None
-
sense:
LXConstraintSense= '<='
-
goal_metadata:
Optional[LXGoalMetadata] = None
- __deepcopy__(memo)[source]
Custom deepcopy that detaches ORM sessions and handles lambda closures.
This method enables what-if analysis on constraints using ORM data sources by: 1. Materializing lazy-loaded ORM data before copying 2. Detaching ORM objects from database sessions 3. Safely copying lambda functions (index_func, rhs_func, etc.) 4. Deep copying constraint expressions and goal metadata
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this constraint with all ORM dependencies resolved
Note
After copying, the new constraint will have _session=None and all data stored in _data as detached objects safe for pickling.
- __getstate__()[source]
Support for pickle protocol - detach ORM sessions before pickling.
- Returns:
Dictionary of instance state safe for pickling
- __setstate__(state)[source]
Support for pickle protocol - restore from pickled state.
- Parameters:
state – Dictionary of instance state from pickling
- expression(expr)[source]
Set LHS expression.
- Parameters:
expr (
LXLinearExpression[TypeVar(TModel)]) – Linear expression for left-hand side- Return type:
Self- Returns:
Self for chaining
- le()[source]
Set as <= constraint.
- Return type:
Self- Returns:
Self for chaining
- ge()[source]
Set as >= constraint.
- Return type:
Self- Returns:
Self for chaining
- eq()[source]
Set as == constraint.
- Return type:
Self- Returns:
Self for chaining
- rhs(value)[source]
Set RHS (constant or function).
- Parameters:
value (
Union[float,Callable[[TypeVar(TModel)],float]]) – Right-hand side value (constant or function)- Return type:
Self- Returns:
Self for chaining
Examples
.rhs(100) # constant .rhs(lambda resource: resource.capacity) # from model
- from_data(data)[source]
Provide data instances directly.
- from_model(model, session=None)[source]
Bind to model for indexed constraints.
- indexed_by(func)[source]
Create constraint for each model instance.
- Parameters:
func (
Callable[[TypeVar(TModel)],TypeVar(TIndex)]) – Function to extract index from model- Return type:
Self- Returns:
Self for chaining
Example
.indexed_by(lambda r: r.id)
- as_goal(priority, weight=1.0)[source]
Mark this constraint as a goal for goal programming.
Automatically relaxes the constraint by adding deviation variables and includes it in the goal programming objective function.
Constraint types are handled as follows:
LE (expr <= rhs): expr + neg_dev - pos_dev == rhs
Positive deviation (exceeding target) is undesired
GE (expr >= rhs): expr + neg_dev - pos_dev == rhs
Negative deviation (falling short) is undesired
EQ (expr == rhs): expr + neg_dev - pos_dev == rhs
Both deviations are undesired
- Parameters:
- Return type:
Self- Returns:
Self for chaining
Example:
# High priority production goal .as_goal(priority=1, weight=1.0) # Lower priority overtime limit .as_goal(priority=2, weight=0.5) # Custom objective term (maximize profit) .as_goal(priority=0, weight=1.0)
- is_goal()[source]
Check if this constraint is marked as a goal.
- Return type:
- Returns:
True if this is a goal constraint, False otherwise
- get_instances()[source]
Get the data instances for this constraint family.
- Return type:
- Returns:
List of model instances, or empty list if single constraint
- Raises:
ValueError – If indexed but no data source configured
- __init__(name, lhs=None, sense=LXConstraintSense.LE, rhs_value=None, rhs_func=None, model_type=None, index_func=None, _data=None, _session=None, goal_metadata=None)
- Parameters:
name (str)
lhs (LXLinearExpression[TModel] | None)
sense (LXConstraintSense)
rhs_value (float | None)
model_type (Type[TModel] | None)
index_func (Callable[[TModel], TIndex] | None)
_data (List[TModel] | None)
_session (Any | None)
goal_metadata (LXGoalMetadata | None)
- Return type:
None
Expressions¶
Expression classes for LumiX optimization models.
- class lumix.core.expressions.LXLinearExpression(terms=<factory>, constant=0.0, _multi_terms=<factory>)[source]
Bases:
Generic[TModel]Type-safe linear expression builder with multi-model support.
Represents: sum(coeff[i] * var[i]) + constant
Examples:
expr = LXLinearExpression() expr.add_term(production, 1.0) expr.add_term(inventory, -1.0) expr.constant(100) # Multi-model expr = LXLinearExpression() expr.sum_over(duty, where=lambda driver, date: date.is_weekend)
- terms: Dict[str, Tuple[LXVariable, Callable[[TModel], float]], Tuple[Callable[[TModel], bool]]]
- constant: float = 0.0
- __deepcopy__(memo)[source]
Custom deepcopy that handles variables and lambda functions.
This method enables what-if analysis on expressions by: 1. Deep copying all variables in the expression 2. Safely copying coefficient and filter lambda functions 3. Preserving the expression structure
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this expression with all dependencies resolved
- add_term(var, coeff=1.0, where=None)[source]
Add term with coefficient (constant or function).
- add_multi_term(var, coeff=<function LXLinearExpression.<lambda>>, where=None)[source]
Add multi-indexed variable to expression.
- Parameters:
- Return type:
Self- Returns:
Self for chaining
Example:
expr.add_multi_term( duty, coeff=lambda driver, date: driver.cost * date.multiplier, where=lambda driver, date: date.is_weekend )
- sum_over(var, where=None)[source]
Syntactic sugar for summing over all dimensions of a variable.
- Parameters:
var (
LXVariable) – Variable to sum over all its dimensionswhere (
Optional[Callable[...,bool]]) – Optional filter function to selectively include terms
- Return type:
Self- Returns:
Self for chaining
Example:
# Sum all driver duties (over all drivers and dates) expr.sum_over(duty) # Sum duties for all drivers on a specific date expr.sum_over(duty, where=lambda d, dt: dt == specific_date)
Note
Currently sums over all dimensions. Future enhancement could add selective dimension summing (e.g., sum only over drivers, not dates).
- add_constant(value)[source]
Add constant to expression.
- Parameters:
value (
float) – Constant value- Return type:
Self- Returns:
Self for chaining
- __add__(other)[source]
Enable expr1 + expr2 or expr + constant.
- Parameters:
other (
Union[float,Self]) – Expression or constant to add- Return type:
Self- Returns:
Self for chaining
- __mul__(scalar)[source]
Enable scalar * expression.
- Parameters:
scalar (
float) – Scalar multiplier- Return type:
Self- Returns:
Self for chaining
- copy()[source]
Create a deep copy of this expression.
- Return type:
Self- Returns:
New expression with same terms and constant
- __init__(terms=<factory>, constant=0.0, _multi_terms=<factory>)
- class lumix.core.expressions.LXQuadraticTerm(var1, var2, coefficient=1.0)[source]
Bases:
objectQuadratic term: coeff * var1 * var2
Used in portfolio optimization, risk modeling, etc.
- Parameters:
var1 (LXVariable)
var2 (LXVariable)
coefficient (float)
-
var1:
LXVariable
-
var2:
LXVariable
-
coefficient:
float= 1.0
- __deepcopy__(memo)[source]
Custom deepcopy that handles variables.
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this quadratic term
- __init__(var1, var2, coefficient=1.0)
- Parameters:
var1 (LXVariable)
var2 (LXVariable)
coefficient (float)
- Return type:
None
- class lumix.core.expressions.LXQuadraticExpression(linear_terms=<factory>, quadratic_terms=<factory>, constant=0.0)[source]
Bases:
objectQuadratic expression: linear_terms + quadratic_terms + constant
Represents: 0.5 * x^T Q x + c^T x + constant
Example
# Portfolio variance: sum(w[i] * w[j] * cov[i,j]) # Plus linear returns: sum(return[i] * w[i]) quad_expr = LXQuadraticExpression() quad_expr.add_quadratic(w[0], w[1], cov[0,1]) quad_expr.linear_terms.add_term(w[0], returns[0])
- Parameters:
linear_terms (LXLinearExpression)
quadratic_terms (List[LXQuadraticTerm])
constant (float)
-
linear_terms:
LXLinearExpression
-
quadratic_terms:
List[LXQuadraticTerm]
-
constant:
float= 0.0
- __deepcopy__(memo)[source]
Custom deepcopy that handles linear and quadratic terms.
This method enables what-if analysis on quadratic expressions by: 1. Deep copying the linear expression component 2. Deep copying all quadratic terms 3. Preserving the expression structure
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this quadratic expression with all dependencies resolved
- add_quadratic(var1, var2, coeff=1.0)[source]
Add quadratic term.
- Parameters:
var1 (
LXVariable) – First variablevar2 (
LXVariable) – Second variablecoeff (
float) – Coefficient
- Return type:
Self- Returns:
Self for chaining
- add_squared(var, coeff=1.0)[source]
Add x^2 term.
- Parameters:
var (
LXVariable) – Variable to squarecoeff (
float) – Coefficient
- Return type:
Self- Returns:
Self for chaining
- __add__(other)[source]
Enable: quad_expr + linear_expr or quad_expr + constant.
- Parameters:
other (
LXLinearExpression|float) – Linear expression or constant- Return type:
Self- Returns:
Self for chaining
- __init__(linear_terms=<factory>, quadratic_terms=<factory>, constant=0.0)
- Parameters:
linear_terms (LXLinearExpression)
quadratic_terms (List[LXQuadraticTerm])
constant (float)
- Return type:
None
- class lumix.core.expressions.LXNonLinearExpression(linear_terms=<factory>, nonlinear_terms=<factory>, constant=0.0)[source]
Bases:
objectNon-linear expression containing arbitrary non-linear terms.
Supports: - Bilinear terms (x * y) - Absolute value (x) - Min/max functions - Piecewise-linear approximations - Conditional expressions - Custom non-linear functions
These will be automatically linearized by the Linearizer engine.
Example
# Create nonlinear expression expr = LXNonLinearExpression()
# Add bilinear product expr.add_product(length, width)
# Add absolute value expr.add_abs(deviation)
# Add piecewise function expr.add_piecewise(time, lambda t: math.exp(t), num_segments=30)
- Parameters:
linear_terms (LXLinearExpression)
constant (float)
-
linear_terms:
LXLinearExpression
-
constant:
float= 0.0
- add_linear(expr)[source]
Add linear terms.
- Parameters:
expr (
LXLinearExpression) – Linear expression to add- Return type:
Self- Returns:
Self for chaining
- add_abs(var, coeff=1.0)[source]
Add absolute value term: coeff * var
- Parameters:
var (
LXVariable) – Variable to take absolute value ofcoeff (
float) – Coefficient (default: 1.0)
- Return type:
Self- Returns:
Self for chaining
Example
# Minimize absolute deviation expr.add_abs(actual - target)
- add_min(*vars, coefficients=None)[source]
Add minimum function: min(vars)
- Parameters:
*vars (
LXVariable) – Variables to take minimum ofcoefficients (
Optional[List[float]]) – Optional coefficients for each variable
- Return type:
Self- Returns:
Self for chaining
Example
# Minimum of three costs expr.add_min(cost_a, cost_b, cost_c)
- add_max(*vars, coefficients=None)[source]
Add maximum function: max(vars)
- Parameters:
*vars (
LXVariable) – Variables to take maximum ofcoefficients (
Optional[List[float]]) – Optional coefficients for each variable
- Return type:
Self- Returns:
Self for chaining
Example
# Maximum capacity expr.add_max(capacity_1, capacity_2, capacity_3)
- add_product(var1, var2, coeff=1.0)[source]
Add bilinear product: coeff * var1 * var2
Automatically linearized based on variable types: - Binary × Binary: AND logic - Binary × Continuous: Big-M method - Continuous × Continuous: McCormick envelopes
- Parameters:
var1 (
LXVariable) – First variablevar2 (
LXVariable) – Second variablecoeff (
float) – Coefficient (default: 1.0)
- Return type:
Self- Returns:
Self for chaining
Example
# Rectangle area expr.add_product(length, width)
# Facility open × flow amount expr.add_product(is_open, flow_amount)
- add_indicator(binary_var, condition, linear_expr)[source]
Add conditional constraint: if binary_var == condition then linear_expr
- Parameters:
binary_var (
LXVariable) – Binary variablecondition (
bool) – Condition value (True or False)linear_expr (
LXLinearExpression) – Expression to apply when condition is met
- Return type:
Self- Returns:
Self for chaining
Example:
# If warehouse is open, then demand must be met expr.add_indicator( is_open, True, LXLinearExpression().add_term(supply, 1.0) )
- add_piecewise(var, func, num_segments=20, x_min=None, x_max=None, adaptive=True, method='sos2')[source]
Add piecewise-linear approximation of arbitrary function.
- Parameters:
var (
LXVariable) – Input variablefunc (
Callable[[float],float]) – Function to approximate (e.g., lambda x: math.exp(x))num_segments (
int) – Number of linear segmentsx_min (
Optional[float]) – Minimum domain value (default: var.lower_bound)x_max (
Optional[float]) – Maximum domain value (default: var.upper_bound)adaptive (
bool) – Use adaptive breakpoint generationmethod (
Literal['sos2','incremental','logarithmic']) – Linearization method (“sos2”, “incremental”, “logarithmic”)
- Return type:
Self- Returns:
Self for chaining
Example:
# Exponential growth expr.add_piecewise(time, lambda t: math.exp(t), num_segments=30) # Custom discount curve expr.add_piecewise( quantity, lambda q: 1.0 if q < 100 else 0.9 if q < 1000 else 0.8, num_segments=50 )
- add_nonlinear_term(term)[source]
Add pre-constructed non-linear term.
- Parameters:
term (
Any) – Non-linear term object- Return type:
Self- Returns:
Self for chaining
- add_nonlinear_terms(terms)[source]
Add multiple non-linear terms.
- __init__(linear_terms=<factory>, nonlinear_terms=<factory>, constant=0.0)
- Parameters:
linear_terms (LXLinearExpression)
constant (float)
- Return type:
None
Enumerations¶
Core enumerations for LumiX optimization library.
This module defines type-safe enumerations for optimization modeling:
Variable Types: Continuous, integer, and binary variables
Constraint Senses: Less-than-or-equal, greater-than-or-equal, and equality
Objective Directions: Minimize and maximize
These enumerations provide IDE autocomplete and type checking throughout the library.
Examples
Creating variables with different types:
from lumix import LXVariable, LXVarType
# Continuous variable (default)
production = LXVariable[Product, float]("production").continuous()
# Integer variable
trucks = LXVariable[Route, int]("trucks").integer()
# Binary variable (0 or 1)
is_open = LXVariable[Facility, int]("is_open").binary()
Using constraint senses:
from lumix import LXConstraint, LXConstraintSense
# Less-than-or-equal constraint
constraint1 = LXConstraint("capacity").le().rhs(100)
# Greater-than-or-equal constraint
constraint2 = LXConstraint("minimum").ge().rhs(50)
# Equality constraint
constraint3 = LXConstraint("balance").eq().rhs(0)
Setting objective direction:
from lumix import LXModel, LXObjectiveSense
# Maximize profit
model.maximize(profit_expr)
# Minimize cost
model.minimize(cost_expr)
- class lumix.core.enums.LXVarType(value)[source]
Bases:
EnumVariable type enumeration for optimization variables.
Defines the domain of decision variables in the optimization model. Each type has different solver representations and computational characteristics.
- CONTINUOUS
Real-valued variables (floating-point) Range: [-inf, inf] or bounded Use for: Production quantities, weights, percentages Example: production[product] = 123.45
- INTEGER
Integer-valued variables Range: Whole numbers only Use for: Counts, discrete quantities Example: num_trucks[route] = 5
- BINARY
Binary variables (0 or 1) Range: {0, 1} Use for: Yes/no decisions, selection, activation Example: is_facility_open[location] = 1
Note
CONTINUOUS variables generally solve faster than integer variables
BINARY is a special case of INTEGER with automatic bounds [0, 1]
Mixed-integer problems combine CONTINUOUS with INTEGER/BINARY variables
Examples
Variable type affects solver choice and performance:
# Fast: Linear program with continuous variables production = LXVariable[Product, float]("prod").continuous() # Slower: Mixed-integer program trucks = LXVariable[Route, int]("trucks").integer() # Classic: Binary decision variables select = LXVariable[Item, int]("select").binary()
- CONTINUOUS = 'continuous'
- INTEGER = 'integer'
- BINARY = 'binary'
- class lumix.core.enums.LXConstraintSense(value)[source]
Bases:
EnumConstraint sense enumeration for inequality and equality constraints.
Defines the relationship between left-hand side (LHS) and right-hand side (RHS) of constraints in the optimization model.
- LE
Less-than-or-equal constraint (<=) Meaning: LHS <= RHS Use for: Capacity limits, maximum bounds, upper limits Example: total_production <= factory_capacity
- GE
Greater-than-or-equal constraint (>=) Meaning: LHS >= RHS Use for: Minimum requirements, lower bounds, demand satisfaction Example: production >= minimum_quota
- EQ
Equality constraint (==) Meaning: LHS == RHS Use for: Balance equations, exact requirements, flow conservation Example: inflow - outflow == 0
Note
LE and GE constraints define feasible regions (inequalities)
EQ constraints are more restrictive and may reduce feasibility
All constraints must be satisfied for a solution to be feasible
Examples
Different constraint types:
# Capacity constraint (upper limit) LXConstraint("capacity") .expression(resource_usage_expr) .le() .rhs(max_capacity) # Demand constraint (lower limit) LXConstraint("demand") .expression(production_expr) .ge() .rhs(min_demand) # Balance constraint (exact equality) LXConstraint("flow_balance") .expression(inflow - outflow) .eq() .rhs(0)
- LE = '<='
- GE = '>='
- EQ = '=='
- class lumix.core.enums.LXObjectiveSense(value)[source]
Bases:
EnumObjective sense enumeration for optimization direction.
Defines whether the objective function should be minimized or maximized.
- MINIMIZE
Minimize the objective function Use for: Costs, distances, time, waste, deviations, risk Example: Minimize total transportation cost
- MAXIMIZE
Maximize the objective function Use for: Profit, revenue, efficiency, throughput, utility Example: Maximize total profit
Note
Every optimization model must have exactly one objective
Minimizing f(x) is equivalent to maximizing -f(x)
For multi-objective problems, use goal programming module
Examples
Setting objective direction:
# Maximize profit model = LXModel("production_plan") model.maximize( LXLinearExpression() .add_term(production, lambda p: p.profit) ) # Minimize cost model = LXModel("logistics") model.minimize( LXLinearExpression() .add_term(shipment, lambda s: s.cost) ) # Multi-objective (using goal programming) model.set_goal_mode("weighted") # Objectives defined via goal constraints
- MINIMIZE = 'min'
- MAXIMIZE = 'max'