Skip to content

tdelphi1981/LumiX

LumiX Logo

LumiX

Python Version License Documentation

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.

✨ Key Features

  • 🎯 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

πŸš€ Quick Start

Installation

# 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]"

Simple Example

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}")

πŸ”§ Supported Solvers

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

Switching Solvers

# 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

πŸ“š Core Capabilities

Variables with Automatic Indexing

# 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),
    )
)

Type-Safe Expressions

# 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)
)

Automatic Linearization

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]
)

Advanced Analysis

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}")

Goal Programming

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)

Interactive Visualization

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")

πŸ“– Documentation

Examples

The repository includes 11 examples demonstrating various features:

  1. Production Planning β€” Single-model indexing, data-driven modeling
  2. Driver Scheduling β€” Multi-dimensional indexing, scheduling
  3. Facility Location β€” Binary variables, fixed costs
  4. Basic LP β€” Simple linear programming
  5. CP-SAT Assignment β€” Constraint programming solver
  6. McCormick Bilinear β€” Bilinear term linearization
  7. Piecewise Functions β€” Piecewise-linear approximations
  8. Scenario Analysis β€” Multiple scenario comparison
  9. Sensitivity Analysis β€” Parameter sensitivity
  10. What-If Analysis β€” Decision support
  11. Goal Programming β€” Multi-objective optimization

Jupyter Notebooks

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

🎯 Why LumiX?

Before (Traditional Approach)

# 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
)

After (LumiX)

# 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

πŸ› οΈ Development

Setup Development Environment

git clone https://github.com/tdelphi1981/LumiX.git
cd LumiX
pip install -e .[dev]

Run Tests

pytest

Type Checking

mypy src/lumix

Code Formatting

black src/lumix
ruff check src/lumix

πŸ“¦ Project Structure

lumix/
β”œβ”€β”€ 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

🀝 Contributing

Contributions are welcome! Please:

  1. Open an issue to discuss your idea
  2. Fork the repository
  3. Create a feature branch
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

πŸ“„ License

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

πŸ™ Acknowledgments

LumiX builds upon the excellent work of:

πŸ“ž Support

πŸ—ΊοΈ Roadmap

  • 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

Authors

This project is maintained by:

For a complete list of contributors, see AUTHORS.


Made with ❀️ by the LumiX Contributors

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published