A modern, type-safe wrapper for optimization solvers with automatic data-driven modeling
LumiX makes mathematical programming accessible, maintainable, and enjoyable by providing a unified, type-safe interface to multiple optimization solvers.
- π― Type-Safe & IDE-Friendly β Full type hints and autocomplete support for a superior development experience
- π Multi-Solver Support β Seamlessly switch between OR-Tools, Gurobi, CPLEX, GLPK, and CP-SAT
- π Data-Driven Modeling β Build models directly from your data with automatic indexing and mapping
- π Automatic Linearization β Automatically linearize non-linear constraints (bilinear, absolute value, piecewise)
- π Advanced Analysis β Built-in sensitivity analysis, scenario analysis, and what-if analysis tools
- π Interactive Visualization β Plotly-based charts for solutions, sensitivity, scenarios, and Gantt schedules
- π― Goal Programming β Native support for multi-objective optimization with priorities and weights
- β‘ ORM Integration β Map solutions directly to your ORM models for seamless data flow
# Install core library
pip install lumix-opt
# Install with a solver (e.g., OR-Tools - free and open-source)
pip install "lumix-opt[ortools]"
# Or install with multiple solvers
pip install "lumix-opt[ortools,gurobi,cplex]"from dataclasses import dataclass
from lumix import (
LXModel,
LXVariable,
LXConstraint,
LXLinearExpression,
LXOptimizer,
)
# Define your data
@dataclass
class Product:
id: str
name: str
profit: float
resource_usage: float
products = [
Product("A", "Product A", profit=30, resource_usage=2),
Product("B", "Product B", profit=40, resource_usage=3),
]
# Define decision variables
production = (
LXVariable[Product, float]("production")
.continuous()
.bounds(lower=0)
.indexed_by(lambda p: p.id)
.from_data(products)
)
# Build the model
model = (
LXModel("production_plan")
.add_variable(production)
.maximize(
LXLinearExpression()
.add_term(production, lambda p: p.profit)
)
)
# Add constraints
model.add_constraint(
LXConstraint("resource_limit")
.expression(
LXLinearExpression()
.add_term(production, lambda p: p.resource_usage)
)
.le()
.rhs(100) # Resource capacity
)
# Solve
optimizer = LXOptimizer().use_solver("ortools")
solution = optimizer.solve(model)
# Access results
if solution.is_optimal():
print(f"Optimal profit: ${solution.objective_value:,.2f}")
for product in products:
qty = solution.variables["production"][product.id]
print(f"Produce {qty:.2f} units of {product.name}")LumiX provides a unified interface to multiple solvers:
| Solver | Linear | Integer | Quadratic | Advanced Features | License | Best For |
|---|---|---|---|---|---|---|
| OR-Tools | β | β | β | SOS, Indicator | Apache 2.0 (Free) | General LP/MIP, Learning |
| Gurobi | β | β | β | SOCP, PWL, Callbacks | Commercial/Academic | Large-scale, Production |
| CPLEX | β | β | β | SOCP, PWL, Callbacks | Commercial/Academic | Large-scale, Production |
| GLPK | β | β | β | Basic | GPL (Free) | Small problems, Teaching |
| CP-SAT | β | β | β | Constraint Programming | Apache 2.0 (Free) | Scheduling, Assignment |
# Just change one line to switch solvers
optimizer = LXOptimizer().use_solver("ortools") # Free
optimizer = LXOptimizer().use_solver("gurobi") # Requires license
optimizer = LXOptimizer().use_solver("cplex") # Requires license
optimizer = LXOptimizer().use_solver("glpk") # Free
optimizer = LXOptimizer().use_solver("cpsat") # Free# Single-dimension indexing
production = (
LXVariable[Product, float]("production")
.continuous()
.indexed_by(lambda p: p.id)
.from_data(products)
)
# Multi-dimension indexing
from lumix import LXIndexDimension
assignment = (
LXVariable[Tuple[Driver, Date, Shift], int]("assignment")
.binary()
.indexed_by_product(
LXIndexDimension(Driver, lambda d: d.id).from_data(drivers),
LXIndexDimension(Date, lambda dt: dt.id).from_data(dates),
LXIndexDimension(Shift, lambda s: s.id).from_data(shifts),
)
)# Linear expressions with automatic coefficient extraction
profit_expr = (
LXLinearExpression()
.add_term(production, lambda p: p.profit)
)
# Quadratic expressions
quadratic_expr = (
LXQuadraticExpression()
.add_quadratic_term(x, y, coefficient=0.5)
)LumiX can automatically linearize non-linear terms:
from lumix import LXBilinearTerm, LXAbsoluteTerm, LXPiecewiseLinearTerm
# Bilinear products (x * y)
bilinear = LXBilinearTerm(x, y, bounds_x=(0, 10), bounds_y=(0, 5))
# Absolute values |x|
absolute = LXAbsoluteTerm(x)
# Piecewise-linear functions
piecewise = LXPiecewiseLinearTerm(
variable=x,
breakpoints=[0, 10, 20, 30],
slopes=[1.0, 0.5, 0.2]
)from lumix import (
LXSensitivityAnalyzer,
LXScenarioAnalyzer,
LXWhatIfAnalyzer,
)
# Sensitivity analysis
sens = LXSensitivityAnalyzer(model, solution)
report = sens.generate_report()
print(report)
# Scenario analysis
scenario_analyzer = LXScenarioAnalyzer(model, optimizer)
scenario_analyzer.add_scenario("base", {})
scenario_analyzer.add_scenario("high_demand", {"demand": 150})
results = scenario_analyzer.solve_all()
# What-if analysis
whatif = LXWhatIfAnalyzer(model, optimizer)
result = whatif.increase_constraint_rhs("capacity", by=10)
print(f"Impact: ${result.delta_objective:,.2f}")from lumix import LXConstraint, LXLinearExpression
# Mark constraints as goals with priorities
model.add_constraint(
LXConstraint("profit_goal")
.expression(profit_expr)
.ge()
.rhs(1000)
.as_goal(priority=1, weight=1.0) # Highest priority
)
model.add_constraint(
LXConstraint("quality_goal")
.expression(quality_expr)
.ge()
.rhs(95)
.as_goal(priority=2, weight=0.8) # Lower priority
)
# Set goal programming mode and prepare
model.set_goal_mode("weighted")
model.prepare_goal_programming()
# Solve with standard optimizer
optimizer = LXOptimizer().use_solver("gurobi")
solution = optimizer.solve(model)LumiX includes Plotly-based visualization tools for analyzing optimization results:
# Install visualization dependencies
pip install "lumix-opt[viz]"from lumix.visualization import (
LXSolutionVisualizer, # Variable values, constraint utilization
LXSensitivityPlot, # Tornado charts, shadow prices
LXScenarioCompare, # Multi-scenario comparison
LXGoalProgressChart, # Goal achievement gauges
LXScheduleGantt, # Gantt charts for scheduling
LXAssignmentMatrix, # Assignment problem heatmaps
LXSpatialMap, # Facility location maps
LXModelGraph, # Variable-constraint network
LXDashboard, # Combined overview dashboards
)
# Visualize solution
viz = LXSolutionVisualizer(solution, model)
viz.show() # Opens in browser/Jupyter
# Sensitivity tornado chart
sens_plot = LXSensitivityPlot(sensitivity_analyzer)
sens_plot.plot_tornado(top_n=10).show()
# Export to HTML
viz.to_html("solution.html")- Installation Guide β Install LumiX and solvers
- Quick Start β Build your first model
- Solver Guide β Choose the right solver
- Examples β 11 comprehensive examples
- Notebooks β 15 interactive Jupyter tutorials
The repository includes 11 examples demonstrating various features:
- Production Planning β Single-model indexing, data-driven modeling
- Driver Scheduling β Multi-dimensional indexing, scheduling
- Facility Location β Binary variables, fixed costs
- Basic LP β Simple linear programming
- CP-SAT Assignment β Constraint programming solver
- McCormick Bilinear β Bilinear term linearization
- Piecewise Functions β Piecewise-linear approximations
- Scenario Analysis β Multiple scenario comparison
- Sensitivity Analysis β Parameter sensitivity
- What-If Analysis β Decision support
- Goal Programming β Multi-objective optimization
Interactive tutorials are available in the notebooks/ directory:
| Notebook | Topic |
|---|---|
| 01-11 | Tutorial notebooks covering all example topics above |
| 12-15 | High School Timetabling β Comprehensive case study |
The High School Timetabling series (notebooks 12-15) demonstrates:
- 3D multi-model indexing (Lecture Γ TimeSlot Γ Classroom)
- SQLAlchemy ORM integration with
from_model(session) - Goal programming for teacher preferences
- Production-ready configuration patterns
# Manual indexing, no type safety
x = {}
for i in range(len(products)):
x[i] = model.addVar(name=f"x_{i}")
# String-based error-prone expressions
model.addConstr(
sum(x[i] * data[i] for i in range(len(products))) <= capacity
)# Type-safe, data-driven, IDE-friendly
production = (
LXVariable[Product, float]("production")
.continuous()
.indexed_by(lambda p: p.id)
.from_data(products)
)
model.add_constraint(
LXConstraint("capacity")
.expression(
LXLinearExpression()
.add_term(production, lambda p: p.usage)
)
.le()
.rhs(capacity)
)Benefits:
- β Full IDE autocomplete
- β Type checking catches errors early
- β No manual indexing
- β Data-driven coefficients
- β Readable, maintainable code
- β Easy to refactor
git clone https://github.com/tdelphi1981/LumiX.git
cd LumiX
pip install -e .[dev]pytestmypy src/lumixblack src/lumix
ruff check src/lumixlumix/
βββ src/lumix/
β βββ core/ # Core model building (variables, constraints, expressions)
β βββ solvers/ # Solver interfaces (OR-Tools, Gurobi, CPLEX, GLPK, CP-SAT)
β βββ analysis/ # Analysis tools (sensitivity, scenario, what-if)
β βββ linearization/ # Automatic linearization engine
β βββ goal_programming/ # Goal programming support
β βββ indexing/ # Multi-dimensional indexing
β βββ nonlinear/ # Non-linear terms
β βββ solution/ # Solution handling and mapping
β βββ visualization/ # Plotly-based interactive charts
β βββ utils/ # Utilities (logger, ORM, rational converter)
βββ examples/ # 11 comprehensive examples
βββ notebooks/ # 15 Jupyter tutorial notebooks
βββ tests/ # Test suite
βββ docs/ # Sphinx documentation
Contributions are welcome! Please:
- Open an issue to discuss your idea
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
LumiX is licensed under the Academic Free License v3.0.
This is a permissive open-source license that:
- β Allows commercial use
- β Allows modification and distribution
- β Provides patent protection
- β Is OSI-approved
LumiX builds upon the excellent work of:
- Documentation: https://lumix.readthedocs.io
- Issues: https://github.com/tdelphi1981/LumiX/issues
- Discussions: https://github.com/tdelphi1981/LumiX/discussions
- Additional solver support (HiGHS, SCIP)
- Jupyter notebook integration
- Interactive visualization tools
- Cloud solver integration
- SQLAlchemy ORM support
- Django ORM support
- Advanced constraint programming features
- Parallel scenario evaluation
- Model versioning and serialization
This project is maintained by:
- Tolga BERBER - tolga.berber@fen.ktu.edu.tr
- Beyzanur SΔ°YAH - beyzanursiyah@ktu.edu.tr
For a complete list of contributors, see AUTHORS.
Made with β€οΈ by the LumiX Contributors
