What’s New

Recent Optyx releases and changes
Published

August 24, 2026

1 Optyx v1.3.2

Theme: Correctness, reliability, and maintenance

This patch release strengthens the existing v1.3 API without introducing a new solver abstraction.

  • Solver caches and warm starts are guarded by the current variable layout.
  • SLSQP candidates are checked for finite values, bounds, constraints, and stationarity before they can be reported as optimal; invalid candidates can be retried with trust-constr.
  • Solution.is_feasible now requires measured feasibility evidence, exposed as constraint_violation, feasibility_tolerance, and feasibility_checked.
  • Polynomial degree analysis consistently handles parameters, products, NarySum, and NaryProduct.
  • Scalar, vector, and matrix variable bounds and domains are validated early.
  • Conflicting variables that share a name are rejected with an actionable error.
  • Changes to Variable.obj are reflected in the next LP or MILP solve.
  • Solves no longer mutate the process-wide warning handler.
  • Problem.summary() includes matrix constraint rows in equality and inequality totals.
  • Obsolete SciPy compatibility code and stale source helpers were removed, and the source tree passes Pyright without warnings.

2 Optyx v1.3.1

This release reduced construction and solve overhead for large vector-backed models while preserving the public API.

  • Lazy VectorVariable metadata avoids unnecessary scalar materialization.
  • Single-vector NLP objectives compile through a contiguous vector layout.
  • Solution value dictionaries are materialized only when accessed.

See the project changelog for the complete release record.


3 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.


3.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() and IntegerVariable() constructor aliases
  • VectorVariable(domain="binary") and VectorVariable(domain="integer") for vectorized discrete variables
  • Solution.mip_gap and Solution.best_bound for 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.


3.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
  • VectorGradientPattern detects expressions with vectorizable gradient structure (∇f = Ax + b)
  • NarySum / NaryProduct flatten deep loop-built trees to O(1) depth
  • VectorBinaryOp preserves vector structure for element-wise operations

See the Benchmarks and the Performance & Scaling guide.


3.3 Sparse Computation

Large-scale LPs with 100,000+ variables are now practical.

  • Problem.subject_to(A @ x <= b) supports matrix blocks directly, with as_matrix(...) for sparse coefficient matrices
  • as_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-constr sooner, 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

3.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 call
  • subject_to() accepts generatorsprob.subject_to(x[i] >= 0 for i in range(n))
  • Problem context managerwith Problem() as p: ...
  • Problem.reset() — clear solver cache and warm-start state
  • Problem.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

3.5 Solver Callbacks & Termination

  • SolverProgress dataclass with iteration, objective, violation, elapsed time, and current x
  • callback= parameter on solve() — return True to stop early
  • time_limit= parameter on solve() — wall-clock budget
  • SolverStatus.TERMINATED for callback-initiated stops

See the Solver Callbacks example.


3.6 Serialization & I/O

  • Problem.write("model.lp") — export to LP format (linear and quadratic objectives, constraints, bounds, integer/binary sections)
  • Solution.to_dict() and Solution.to_json() — solution serialization for logging and auditing

See the LP Export example.


3.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.