discopt#
A hybrid Mixed-Integer Nonlinear Programming (MINLP) solver combining a Rust backend, JAX automatic differentiation, and Python orchestration. Solves MINLP problems via NLP-based spatial Branch & Bound [Belotti et al., 2013, Land and Doig, 1960] with JIT-compiled objective/gradient/Hessian evaluation.
Architecture#
Model.solve() --> Python orchestrator --> Rust TreeManager (B&B engine)
| |
JAX NLPEvaluator Node pool / branching / pruning
NLP backends: Zero-copy numpy arrays (PyO3)
pounce (pure-Rust Ipopt port)
ipm (pure-JAX, vmap batch) [default]
cyipopt (Ipopt)
Rust backend (crates/discopt-core): Expression IR, Branch & Bound tree (node pool, branching, pruning), .nl file parser, FBBT/presolve (interval arithmetic, probing, Big-M simplification).
JAX layer (python/discopt/_jax): DAG compiler mapping modeling expressions to JAX primitives, JIT-compiled NLP evaluator (objective, gradient, Hessian, constraint Jacobian), McCormick convex/concave relaxations [McCormick, 1976] (21 functions including sigmoid, softplus, tanh), and a relaxation compiler with vmap support.
Solver wrappers (python/discopt/solvers): POUNCE (pure-Rust Ipopt port), cyipopt NLP wrapper for Ipopt [Wächter and Biegler, 2006], HiGHS LP and MILP wrappers with warm-start support (MILP used by the LOA decomposition solver).
Neural network embedding (python/discopt/nn): embeds trained feedforward networks as algebraic MINLP constraints [Ceccon et al., 2022] via full-space (smooth activations), ReLU big-M MILP [Anderson et al., 2020], and reduced-space strategies; interval arithmetic bound propagation; ONNX model import.
Generalized disjunctive programming (python/discopt/_jax/gdp_reformulate.py): reformulates GDP models — BooleanVar, propositional logic operators, either_or(), if_then() — into standard MINLP via big-M, multiple big-M (LP-tightened), convex hull, or Logic-based Outer Approximation.
Orchestrator (python/discopt/solver.py): End-to-end Model.solve() connecting all components. At each B&B node: solve continuous NLP relaxation with the interior-point method [Nocedal and Wright, 2006], prune infeasible nodes, fathom integer-feasible solutions, branch on most fractional variable.
Certified-global MINLP via AMP (python/discopt/solvers/amp.py): Adaptive Multivariate Partitioning [Nagarajan et al., 2019] for nonconvex MINLPs (bilinear, signomial, concave). Iterates a piecewise-McCormick / convex-hull MILP relaxation against an NLP subproblem (Ipopt), refining the partition where the relaxation gap is largest. At every iteration LB_k <= global_opt <= UB_k, so termination yields a certified suboptimality bound. Invoked with Model.solve(solver="amp"); see Certified-global MINLP with AMP.
Parameter estimation & MBDoE (python/discopt/estimate.py, python/discopt/doe/): Model-based parameter estimation via weighted least-squares NLP, and optimal design of experiments using Fisher Information Matrix analysis [Franceschini and Macchietto, 2008, Wang and Dowling, 2022]. Key advantage: exact sensitivity Jacobians via JAX autodiff (no finite differences). Includes sequential DoE loop, identifiability analysis, and design space exploration with D/A/E/ME-optimality criteria [Atkinson et al., 2007].
Quick Start#
from discopt import Model
m = Model("example")
x = m.continuous("x", lb=0, ub=5)
y = m.continuous("y", lb=0, ub=5)
z = m.binary("z")
m.minimize(x**2 + y**2 + z)
m.subject_to(x + y >= 1)
m.subject_to(x**2 + y <= 3)
result = m.solve()
print(result.status) # "optimal"
print(result.objective) # 0.5
print(result.x) # {"x": 0.5, "y": 0.5, "z": 0.0}
Parameter Estimation & Design of Experiments#
discopt includes model-based parameter estimation and optimal experimental design, using exact JAX autodiff for Fisher Information Matrix computation.
from discopt.estimate import Experiment, ExperimentModel, estimate_parameters
from discopt.doe import compute_fim, optimal_experiment, DesignCriterion
import discopt.modeling as dm
import numpy as np
# Define an experiment: y = k * x
class MyExperiment(Experiment):
def create_model(self, **kwargs):
m = dm.Model("exp")
k = m.continuous("k", lb=0.01, ub=20)
x = m.continuous("x", lb=0.1, ub=10)
return ExperimentModel(
model=m,
unknown_parameters={"k": k},
design_inputs={"x": x},
responses={"y": k * x},
measurement_error={"y": 0.1},
)
# Estimate k from data
exp = MyExperiment()
data = {"y": 6.0} # observed at some x
result = estimate_parameters(exp, data)
print(result.parameters) # {"k": ...}
print(result.confidence_intervals)
# Find optimal measurement location (D-optimal)
design = optimal_experiment(
exp, param_values={"k": 2.0},
design_bounds={"x": (0.5, 10.0)},
criterion=DesignCriterion.D_OPTIMAL,
)
print(design.summary())
NLP Backend Comparison#
discopt supports three NLP solver backends, each with different strengths:
Backend |
Implementation |
Use Case |
|---|---|---|
|
Pure-JAX IPM |
B&B inner loop; GPU-batched via |
|
Pure-Rust Ipopt port |
Single-problem NLP; fastest wall-clock |
|
Ipopt via cyipopt |
Single-problem NLP; most robust |
For single continuous solves the ipm default is promoted to a KKT-valid
backend, resolving to POUNCE when installed and falling back to cyipopt.
result = model.solve(nlp_solver="pounce") # POUNCE (pure-Rust Ipopt port)
result = model.solve(nlp_solver="ipm") # Pure-JAX (default)
result = model.solve(nlp_solver="cyipopt") # Ipopt
Contents#
Tutorials — Problem Classes
- Linear Programming
- Quadratic Programming
- Mixed-Integer Linear Programming (MILP)
- 0-1 Knapsack: Packing a Backpack
- Mixed-Integer Quadratic Programming (MIQP)
- Mixed-Integer Nonlinear Programming (MINLP)
- Generalized Disjunctive Programming (GDP)
- Dynamic Optimization with DAE Collocation
- Robust Optimization
- Adjustable Robust Optimization
- Multi-Objective Optimization
Tutorials — Solver Backends
Tutorials
Advanced Features
- discopt Advanced Features
- Solver Internals: BARON-Parity Features
- Presolve
- Parametric Sensitivity Analysis (sIPOPT-style)
- LLM Integration
- LLM Integration
- Warm-Starting with Initial Solutions
- Convex NLP Fast Path
- Convexity detection
- Nonlinear Branch & Bound (NLP-BB)
- Exporting Models to MPS and LP Formats
- Callbacks and User-Defined Cuts
Solver Backends
Applications
- Neural Network Embedding
- Decision-Focused Learning with discopt
- Parameter Estimation & Design of Experiments
- Parameter Estimation
- Model-Based Design of Experiments
- Design of Experiments from the Command Line
- Batch / Parallel Design of Experiments
- Mixture Designs
- Latin-Square Designs and ANOVA
- Factor Screening with 2-Level Factorial Designs
- Active-Learning Optimization with a Surrogate
- Model-Based Active Learning for Response Optimization
- Identifiability and Estimability Analysis
- Model Discrimination Workflow
API Reference
- API Reference
- discopt
- discopt.benchmarks
- discopt.callbacks
- discopt.cli
- discopt.constants
- discopt.course
- discopt.dae
- discopt.dev
- discopt.doe
- discopt.doe.acquisition
- discopt.doe.anova
- discopt.doe.cli
- discopt.doe.design
- discopt.doe.discrimination
- discopt.doe.discrimination_sequential
- discopt.doe.estimability
- discopt.doe.exploration
- discopt.doe.fim
- discopt.doe.fractional
- discopt.doe.gui
- discopt.doe.latin
- discopt.doe.model_based
- discopt.doe.optimize
- discopt.doe.profile
- discopt.doe.screening
- discopt.doe.selection
- discopt.doe.sequential
- discopt.doe.surrogate
- discopt.doe.templates
- discopt.doe.workbook
- discopt.estimate
- discopt.export
- discopt.gp
- discopt.interfaces
- discopt.llm
- discopt.mo
- discopt.modeling
- discopt.nn
- discopt.ro
- discopt.skills
- discopt.solver
- discopt.solvers
- discopt.tutor
- discopt.validation
- discopt.warm_start
- discopt