Conversation
* Implement NarySum, NaryProduct and flatten_expression optimizer - Add NarySum and NaryProduct expression nodes for flat n-ary trees - Add iterative flatten_expression() to coalesce nested BinaryOp chains - Eliminates recursion depth limit for loop-summed expressions - ~7x evaluation speedup for loop-constructed sums * Add gradient rules for NarySum/NaryProduct and additional tests - Handle NarySum/NaryProduct in _gradient_cached and _gradient_iterative - Add 6 new test cases (gradients, get_variables, edge cases) - 15 total nary expression tests passing * wire flatten_expression into solve pipeline, add NarySum/NaryProduct to compiler - Call flatten_expression() on objective and constraint expressions in scipy_solver._build_solver_cache() before compilation - Add NarySum/NaryProduct handlers to _build_evaluator() (recursive path) - Add NarySum/NaryProduct handlers to _build_evaluator_iterative() (iterative path) - All 819 tests pass
…lation (#111) * feat: add VectorBinaryOp for efficient vector arithmetic Introduce VectorBinaryOp as a subclass of VectorExpression that stores a single (left, right, op) triple instead of N individual BinaryOp nodes. This reduces expression tree size from O(n) nodes to O(1) for element-wise vector operations like x + y, x - target, x * weights. - Add VectorBinaryOp class with numpy-vectorized evaluate() - Update _vector_binary_op() to return VectorBinaryOp - Add compiler fast path using numpy ufuncs for VectorBinaryOp - Add fast paths in VectorExpressionSum and LinearCombination compilation - Fix __rsub__, __rtruediv__, __neg__ on VectorVariable and VectorExpression - Add 37 tests covering construction, evaluation, compilation, gradients, constraints, and end-to-end solves Closes #87 * feat: complete Task 0.1 & 0.2 — lazy VectorBinaryOp, vectorized gradients, flat NarySum output Task 0.2 (VectorBinaryOp): - Make _expressions lazy via @Property (O(1) construction) - VectorExpressionSum.evaluate() bypasses materialization - Add @register_gradient(VectorBinaryOp) for O(1) symbolic gradients - Add compile_gradient fast path for sum(VectorBinaryOp) patterns - Add compile_gradient fast path for NarySum with VectorBinaryOp terms Task 0.1 (NarySum — carried from closed branch): - NarySum gradient produces flat NarySum instead of nested BinaryOp chain - Both recursive and iterative gradient paths updated Tests: 26 new tests (882 total, 0 failures)
Implements efficient O(1) Hessian computation for sums of quadratic forms (e.g. 2*x'Q1x + 3*x'Q2x) by pre-calculating the summed matrix at compile time. Changes: - Added recursive constant detection in compute_hessian (BinaryOp handling) - Added global optimization in compile_hessian: returns cached constant matrix function if all entries are constant - Fixed LinearCombination detecting zero Hessian for non-linear vectors - Added _hash initialization to VectorPowerSum/VectorUnarySum to fix caching bugs - Added regression tests for linear combinations of quadratic forms
…, #93) (#115) * feat(autodiff): implement VectorGradientPattern enum for expression classification (#91) Renamed existing VectorGradientPattern dataclass to AffineGradientPattern to avoid conflict and better reflect purpose. Implemented new VectorGradientPattern Enum and detector for general structural classification. * perf: optimize AffineGradientPattern with structured metadata (#91, #92, #93) - Add linear_type/linear_scale/linear_diag metadata to AffineGradientPattern to avoid O(n²) matrix materialization during pattern detection - Rewrite compile_vector_gradient to use metadata-first fast paths, reducing compilation from O(n²) to O(1) for common patterns - Optimize _combine_patterns to check structured types before materializing - Use scipy.optimize.Bounds instead of list-of-tuples in solver - Update benchmark results reflecting performance improvements
Detect which variables an expression depends on to skip zero-gradient columns during Jacobian compilation. Uses extract_all_linear_coefficients for O(n) constant detection on linear expressions. Extends NLP benchmarks to n=10000, fixes SciPy baseline to use L-BFGS-B.
Add compile_sparse_gradient(), compile_gradient_with_sparsity() to compiler.py and compile_sparse_jacobian() to autodiff.py. Returns scipy.sparse.csr_matrix with O(nnz) memory for sparse constraint systems, falls back to dense when density > 0.5. Integrate batched sparse constraint Jacobian in scipy_solver.py. 27 new tests, 939 total passing.
Add subject_to_matrix(A, x, sense, b) to Problem, accepting dense or scipy.sparse constraint matrices. Bypasses expression tree entirely and passes sparse A directly through to HiGHS via linprog. - _MatrixConstraint dataclass stores raw matrix constraints - _merge_matrix_constraints() in analysis.py handles column mapping, sense conversion, and merging with expression-tree constraints - 22 new tests covering dense/sparse, all senses, mixed constraints - Zero overhead vs raw scipy at n=100K (1.0x cold/warm)
- Wire Variable.obj into LP objective extraction (analysis.py) - Wire Variable.obj into NLP objective building (scipy_solver.py) - Fix pyright warning: guard sub_expr None check in autodiff.py - Fix pyright warning: type-ignore scipy Bounds stub mismatch - Add 34 tests for between(), generator subject_to, context manager, obj=
- Solution.to_dict(): 4 tests (basic fields, None fields, multipliers, all statuses) - Solution.to_json(): 3 tests (string output, file write, roundtrip) - Solution.from_json(): 5 tests (string, file, missing fields, all statuses, solve roundtrip) - Problem.reset(): 6 tests (clears caches, preserves definition, cold re-solve, NLP) - SolverStatus.TERMINATED: 4 tests (exists, is_feasible, serialization, enum members) - Solution.print_vars(): 3 tests (output format, no objective, sorted order) All 1021 tests passing.
- MatrixVariable.diagonal(offset): 13 tests (main/super/sub diagonals, rectangular, bounds, symmetric) - Per-element bounds arrays: 10 tests (numpy/list/scalar/None, size validation, LP/NLP solves) - Fancy indexing x[[0,2]]: 13 tests (list/ndarray/tuple/boolean, negative, error cases, solves) - Combined features: 2 integration tests All 3 features were already implemented. Updated benchmark results. 1059 tests passing.
Route linear problems with integer/binary variables to HiGHS MILP solver. - Add milp_solver.py wrapping scipy.optimize.milp() - Add BinaryVariable/IntegerVariable aliases, VectorVariable domain support - Route integer vars from lp_solver to solve_milp automatically - Guard against MIQP/MINLP (raises ValueError) - Add Solution.mip_gap and Solution.best_bound fields - Domain validation in Variable.__init__ - 28 new MILP tests, 7 updated solver tests - MILP scaling benchmarks (loop n<=500, vector n<=5000)
- VariableDict: dict-indexed variable collection with string keys, per-key bounds, sum/prod/subset operations, and Solution extraction - 43 tests covering creation, access, expressions, solving, edge cases - Mine production planning example and quarto doc (VariableDict showcase) - Mine equipment MILP example and quarto doc (BinaryVariable, IntegerVariable, VectorVariable with binary/integer domains, Big-M constraints) - Sparse benchmark: added comparison plots for compile/eval speedup and memory reduction
- Add Problem.remove_constraint(index_or_name) for removal by int index or str name - Selective cache invalidation: preserve objective/gradient cache when only constraints change - Warm start: store previous solution, use as x0 on re-solve (warm_start=True default) - Problem.reset() now clears warm start state - Fix LP bounds caching bug: always re-read v.lb/v.ub instead of stale LPData.bounds - Add _rebuild_constraint_cache() for partial NLP cache rebuild - 33 new tests covering add/remove, warm start, bounds freshness, fix/unfix, staleness - Add modify_and_resolve.py example and quarto doc
- Add SolverProgress dataclass with iteration, objective_value, constraint_violation, elapsed_time, x fields - Add callback= and time_limit= parameters to Problem.solve() - Implement _EarlyTermination exception and composite callback builder in scipy_solver.py, supporting SLSQP, trust-constr, and L-BFGS-B - Export SolverProgress from optyx.__init__ - Fix ElementwisePower support in compiler, autodiff, and vector helpers to enable vectorized VectorVariable slicing expressions - Add 26 callback/time-limit tests and 5 vector slicing tests - Add examples/solver_callbacks.py demo - Add docs/examples/solver-callbacks.qmd quarto documentation Closes #105
- Add src/optyx/io.py with write_lp(), format_lp(), and _format_lp() supporting LP, QP, and MIP problems in CPLEX LP format - Add Problem.write(filename) and Problem.to_lp() methods - Add extract_quadratic_coefficients() to analysis.py - Handle quadratic objectives (QuadraticForm, DotProduct, var*var, expr**2) with correct [ Q ] / 2 notation - Support Generals/Binaries sections for integer/binary variables - Support matrix constraints (dense and sparse) - Add 59 tests in test_lp_export.py - Add examples/lp_export.py demo - Add docs/examples/lp-export.qmd documentation - Update docs/_quarto.yml navigation Closes #106
* docs: implement v1.3.0 documentation plan * Restructure docs nav and add What's New page - Group tutorials by topic (Modeling, Variables, Advanced) - Group examples by category (Industry, Techniques, Large-Scale) - Rename API section to Topic Guides - Add What's New page covering v1.3.0 features * Fix tutorial code cells for integer-programming and variable-dict - Use complete dicts for VariableDict bounds (all keys required) - Replace non-existent .to_dict() with manual dict comprehension * Update benchmarks with latest run data and add MILP section - Refresh all LP, NLP, CQP tables from benchmark_output.txt - Add MILP scaling section with knapsack benchmark - Add milp, sparse PNGs to assets - Update overhead summary to include MILP - Fix NLP narrative to reflect actual benchmark characteristics * Update docs and benchmarks for v1.3.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v1.3.0
Merges the full v1.3.0 release into main. This PR now reflects the current release branch, including the final docs, benchmark, org-migration, and release-polish updates added after the PR was opened.
Highlights
BinaryVariable,IntegerVariable, andVectorVariable(domain="binary"|"integer")route linear discrete models to SciPy HiGHS viascipy.optimize.milp()VectorGradientPattern,NarySum/NaryProduct,VectorBinaryOp, andDotProductfast paths reduce compile overhead and keep large models scalableProblem.subject_to(A @ x <= b)andas_matrix(...), plus sparse Jacobian/objective paths and improved sparse NLP routingsubject_to(),between(), fancy indexing, per-element array bounds, andProblemcontext managerremove_constraint(),reset(), warm starts, solver callbacks,time_limit=, andSolverStatus.TERMINATEDProblem.write("model.lp"), plusSolution.to_dict(),to_json(), andfrom_json()optyx-dev, version and dependency bumps, lint/format cleanup, typing fixes, and sparse-solver documentation polishNotes
optyx-devorganization.CHANGELOG.mdfor the complete v1.3.0 entry.