What’s New in v1.3.0
1 Optyx v1.3.0
Theme: Scalable Expressions, Vectorized Gradients, Sparse Computation, Basic MIP, Modeling Convenience
This release addresses critical scalability limitations discovered in v1.2.x benchmarks and adds major new capabilities.
1.1 Mixed-Integer Linear Programming (MILP)
Optyx now supports integer and binary decision variables, automatically routing problems with discrete variables to the MILP solver (SciPy’s HiGHS backend via scipy.optimize.milp()).
BinaryVariable()andIntegerVariable()constructor aliasesVectorVariable(domain="binary")andVectorVariable(domain="integer")for vectorized discrete variablesSolution.mip_gapandSolution.best_boundfor optimality reporting- Domain validation enforces correct bounds for binary variables
- Clear error when attempting unsupported MIQP (quadratic + integer)
See the Integer Programming tutorial and the Mine Equipment MILP example.
1.2 Vectorized Gradients & Scalability
Cold-start performance for quadratic programs has been dramatically improved through automatic vectorized gradient detection.
| Problem | Cold Overhead vs SciPy | Warm Overhead vs SciPy |
|---|---|---|
| CQP n=500 | 2.2x | 1.2x |
| CQP n=1,000 | 1.8x | 1.2x |
| CQP n=5,000 | 1.1x | 1.0x |
VectorGradientPatterndetects expressions with vectorizable gradient structure (∇f = Ax + b)NarySum/NaryProductflatten deep loop-built trees to O(1) depthVectorBinaryOppreserves vector structure for element-wise operations
See the Benchmarks and the Performance & Scaling guide.
1.3 Sparse Computation
Large-scale LPs with 100,000+ variables are now practical.
Problem.subject_to(A @ x <= b)supports matrix blocks directly, withas_matrix(...)for sparse coefficient matricesas_matrix(storage="auto" | "dense" | "sparse")gives explicit control over matrix-block storage, with automatic CSR conversion for large low-density dense arrays- Sparse Jacobian compilation reduces memory from O(m×n) to O(nnz)
- Sparse constrained NLPs now bias toward
trust-constrsooner, lazily compiling the batched sparse Jacobian only when that solver path is actually used - n=100,000 LP with 1% density constraint matrix solves end-to-end
1.4 Modeling Convenience
VariableDict— dict-indexed variables keyed by strings, with.prod()and.sum(subset)aggregation. See the VariableDict tutorial.Expression.between(lb, ub)— range constraints in one callsubject_to()accepts generators —prob.subject_to(x[i] >= 0 for i in range(n))Problemcontext manager —with Problem() as p: ...Problem.reset()— clear solver cache and warm-start stateProblem.remove_constraint()— incremental model modification- Warm starts — re-solves automatically use the previous solution
- Bounds correctness fix — variable bounds are never cached, enabling fix-and-dive patterns
1.5 Solver Callbacks & Termination
SolverProgressdataclass with iteration, objective, violation, elapsed time, and current xcallback=parameter onsolve()— returnTrueto stop earlytime_limit=parameter onsolve()— wall-clock budgetSolverStatus.TERMINATEDfor callback-initiated stops
See the Solver Callbacks example.
1.6 Serialization & I/O
Problem.write("model.lp")— export to LP format (linear and quadratic objectives, constraints, bounds, integer/binary sections)Solution.to_dict()andSolution.to_json()— solution serialization for logging and auditing
See the LP Export example.
1.7 Per-Element Array Bounds & Fancy Indexing
- Array bounds on
VectorVariable:VectorVariable("x", 3, lb=np.array([0, 0.5, 0.2])) - Fancy indexing:
x[[0, 2, 5]]returns a subset vector expression
See the Vector Variables tutorial.