|
Gecode 6.4.0
|
Status: research/design only, 2026-09-05. No QP source implementation or shared Model, native, solve, workflow or binding change is authorized by this document.
Implement an isolated QuadraticModel / QuadraticSnapshot wrapper, an explicit solve_quadratic backend, and an independent original-objective/KKT/bound checker. The first supported class is finite-box continuous variables, ordinary linear constraints, and positive weighted squared affine objective terms. Minimize a convex objective or maximize a concave objective. Preserve singular curvature, fixed variables and empty/constant terms correctly; do not require positive definiteness. Return Unsupported for unbounded original variable domains, integer/binary/semi variables, indicators, CP globals, arbitrary Hessians, quadratic constraints, nonconvex objectives, starts, sessions and Exact/Certified solve requests in this first slice. This is a useful bounded least-squares and penalty-objective feature, not MIQP, QCP, nonlinear or full QP parity.
Lower each square to a private residual variable and a diagonal Hessian. This establishes convexity structurally, preserves the user's original factored objective, and avoids forming a rounded Gram matrix. Keep the existing linear model API and binary layout unchanged. A distinct snapshot type without an implicit conversion makes accidental use by an older linear workflow a compile error. Build registration/umbrella inclusion is the only shared change needed for the first C++ vertical slice.
Finite original boxes are a deliberate initial restriction: they make a residual-corrected global lower bound available without inverting a possibly singular Hessian or treating small stationarity residuals as exactly zero. Removing that restriction requires additional bound/curvature verification; it must not be simulated by inventing large artificial bounds.
The local dependency is HiGHS v1.15.1, commit 04024d701f79feb8e2f18bc3df0dffc04ef05088. The installed integration build has HIPO=OFF. The following findings come from that source, not an assumption about current development documentation.
| Contract | Pinned evidence and implication |
|---|---|
| Objective convention | c0 + c'x + 0.5*x'Q*x. Lower triangular column-compressed entries represent one symmetric Hessian. Diagonal contribution is 0.5*Qjj*xj^2; one off-diagonal entry contributes Qij*xi*xj. QP README, Hessian evaluation. |
| Hessian upload | HighsHessian uses dim_, format_, start_, index_, value_; prefer canonical lower CSC with start.size()==dim+1, sorted unique row indices, and finite values. Type, assessment/normalization. |
| Upload may change data | Assessment sums duplicates, normalizes the triangle, filters small values and completes missing diagonals. Square asymmetry is rejected; upper triangular entries in triangular input can be moved/summed. Avoid relying on correction/warnings; preflight and inspect the uploaded representation. Normalization. |
| Convexity is not established | okHessianDiagonal only rejects a diagonal sign inconsistent with the sense. Passing it is not a PSD proof. For example, [[1,2],[2,1]] has positive diagonal and eigenvalues 3,-1. Later negative-curvature detection is not a complete acceptance test. Diagonal test, solve gate. |
| No MIQP | A QP with integrality is rejected unless solve_relaxation was requested. That latter path drops integrality; it is not MIQP support. The adapter must never enable it as a fallback. Dispatch. |
| Actual initial algorithm | The active-set solver is the default; HiPO is used only when selected and compiled/available. It maintains a reduced Hessian and has a nullspace limit, default 4000. Explicitly select qpasm for reproducible first-slice behavior; do not infer HiPO availability from recent docs. QP dispatcher, options. |
| Regularization changes the working objective | solveqp adds qp_regularization_value to each stored diagonal; the default is 1e-7. The source explicitly describes perturbed solutions. Final HiGHS checks use the original model. Our acceptance checks must also use the unregularized original squares. Regularization, settings. |
| Dual values are available, not automatic proof | Original-sense column and row duals are returned; multiply by the objective sense sign to normalize. getDualObjectiveValue is available, but its computation assumes meaningful dual data and selects bound contributions from primal location. Preserve it as a vendor diagnostic, not an independently verified bound. mip_dual_bound is a MIP field and is not the QP bound. Dual mapping, dual objective. |
| Final numerical checks | HiGHS computes original objective/KKT failures and calls checkOptimality for a QP reported optimal. Recheck independently rather than assuming that report establishes convexity or exact optimality. Final checks. |
| Cancellation limits | The active-set call receives time/iteration limits, but the inspected path does not pass the general HiGHS callback object to QUASS. Check cancellation before/after backend work and exclude late candidates; do not advertise an in-loop interrupt callback. Propagation, factorization and phase-I work are cooperative. QP call, time checks. |
The current official solver documentation likewise cautions that the diagonal convexity check can miss nonconvexity. It is supporting context, not the version pin or an authorization to enable new solvers.
Let s=+1 for minimization and s=-1 for maximization. Define the original objective explicitly as
The maximization entry point is named maximize_concave_squares so its negative penalties are explicit. Its normalized minimized objective is
For each square, introduce private continuous z_k and linear equality z_k - a_k'x = b_k. Minimize s*c0 + (s*c)'x + sum w_k*z_k^2, with diagonal Q[z_k,z_k]=2*w_k and zero curvature on original x columns. Residual variables may be free; only original variables require finite boxes. The backend Hessian is PSD by construction, including when some original directions are flat. Auxiliary values and rows stay private; result slots use original wrapper variables, including tombstones. Square names/indices identify diagnostics.
This formulation uses O(sum nnz(a_k)+number_of_squares) extra linear entries and diagonal curvature. Expanding 2*sum w_k*a_k*a_k' can cause quadratic fill-in and floating rounding can destroy exact PSD of the submitted matrix. The lifted route avoids both issues, at the cost of additional rows/columns and possible conditioning/nullspace costs. These costs must be measured, not assumed away.
Reject non-finite or underflowed/generated coefficients, dimensions outside HighsInt, values beyond HiGHS's infinity/range limits, and nonzero entries at or below the configured removal threshold. Multiplication by two for the Hessian must stay finite and nonzero. Do not silently drop small a_k or weights. Set the matrix threshold explicitly to 1e-12, as the existing adapter does, and audit the round-tripped backend model before solving. Do not form or alter the original linear/constant terms by an expanded-square cancellation.
Initial solver setting recommendation: qpasm, one worker, zero seed, qp_regularization_value=0, and an explicit bounded nullspace/iteration policy. The zero-regularization choice needs direct comparison with the pinned default on singular/ill-conditioned fixtures before adoption. A later robustness fallback may use nonzero regularization only with separate recorded settings and the same unregularized acceptance gates; no retry may restart the total budget.
Candidate declarations; implementation review may simplify names, not semantics:
QuadraticSnapshot exposes const variable/row/full-objective views and identity, not a public ModelSnapshot or Model&, and has no conversion operator. Its private data can contain a copied ModelSnapshot plus squares for compiler reuse. The mutable wrapper can privately own Model: normalize/validate every square and finish all allocating staging before calling Model::set_objective for the linear part and revision increment, then swap the already-staged squares without throwing. Thus quadratic-only objective changes advance the same revision, and failed mutation preserves both old objective and revision. Moves preserve the owner; moved-from access fails explicitly. Snapshot data owns all metadata after model destruction. Do not attach squares to an externally accessible linear Model with the same identity/revision.
An import from an existing linear model, if added later, must allocate a fresh wrapper owner and return an explicit original-to-wrapper handle mapping, while rejecting unsupported active types/metadata. It must not borrow the original owner and create two different objectives with identical identity and revision.
A finite-box continuous objective is bounded whenever feasible. Therefore a backend Unbounded/ambiguous infeasible-or-unbounded report is a numerical failure for this slice, not a valid unbounded conclusion. A numerical infeasible report must not coexist with an independently valid primal witness. If accepted as Infeasible, identify it as the backend's numerical conclusion; do not claim an independently checked Farkas certificate. Stronger infeasibility validation is a separate later feature.
Use the original positive squares and any finite chosen t_k, for example a numerical approximation of a_k'x+b_k. Completing a square gives
Choose any finite signed row multipliers lambda_i, selecting finite row lower bounds for positive multipliers and finite upper bounds for negative ones. Set a multiplier to zero when its chosen side is unavailable; it is a proposal, not a solver-authenticated proof value. Define
Then D <= min F(x) for every original feasible point. The calculation uses the original rows/bounds/squares, not the lifted matrix. It remains valid with a singular Hessian, inaccurate duals, nonstationary candidate, or infeasible candidate; those may only make the bound weaker. This is a derived application of weak duality and the quadratic conjugate, not a claim that HiGHS exports such a certificate. This parameterization also avoids division by small square weights. Boyd and Vandenberghe, Convex Optimization, duality/conjugates.
Implement checked one-sided enclosures, not a guessed epsilon subtracted from a floating answer. Enclose each arithmetic operation and use the lower endpoint for K. For a residual interval [rlo,rhi], use a lower enclosure of the minimum of all four endpoint products with [l,u]. Overflow, non-finite arithmetic, unsupported rounding behavior, or budget exhaustion makes the bound unavailable. Test the enclosure routine against an exact rational oracle, including subnormals, cancellation and extreme ratios. Require IEEE semantics/no fast-math, or use a verified higher-precision alternative; do not assume long double is wider on arm64. Keep the Numerical solve guarantee even if the bound subroutine is checked.
Convert the final bound back as D for minimization or -D for maximization; F already included the signed original offset, so do not add it twice. Restore row/bound dual signs and report original objective values consistently. Never use a MIP bound field, a stationarity residual rounded to zero, or the vendor primal objective as a substitute for this computation.
For a future unbounded original domain, a nonzero residual can make its box infimum -infinity, even if tiny. Supporting those models with strong finite bounds needs verified stationarity or a retained positive-curvature residual bound, or independently justified finite domain tightening. Do not drop this residual or clip the domain to make a gap appear closed.
| Existing entry point | First-slice rule and required regression |
|---|---|
| solve(Model/ModelSnapshot), Auto | Unchanged. Wrapper is not convertible; use only explicit solve_quadratic. Optional future typed solve(QuadraticSnapshot) may delegate, never expose its private linear part as a user model. |
| solve_native, solve_native_lp, solve_native_search | No quadratic overload or implicit conversion. Compile-time detection tests show wrapper/snapshot cannot bind. Explicit Backend::Native passed to solve_quadratic returns Unsupported. |
| presolve_integer and postsolve | No wrapper conversion, so integer presolve cannot drop squares. Future quadratic substitution must update square offsets/full objective and preserve owning identity. |
| pools, repair, lexicographic workflow, diagnostics | No wrapper overload in Q1. Do not convert to the private linear snapshot. A later feasibility-only diagnostic may deliberately ignore an objective, but must have a typed documented contract. Quadratic retention locks are QCP and cannot be passed to a linear lex workflow. |
| incremental Session | Reject by type; no hidden Hessian omission or stale basis. A dedicated QP session is later work with its own revision and warm-start rules. |
| common validation | Add a typed quadratic checker. Internal reuse of ordinary row/bound validation is permitted, but its linear objective cannot be returned as the original quadratic objective. |
| LP/MPS I/O and CLI | No wrapper export/import in Q1. Existing strict parsers continue rejecting nonlinear LP syntax and unsupported MPS sections; add explicit QP-file negative fixtures. No file may be partially written before unsupported capability is reported. |
| C API/Python | No opaque wrapper token is an existing linear Model token. Future QP bindings use a new handle kind and versioned objective payload; existing functions reject a wrong kind. No ABI struct reinterpretation, no addition of hidden squares to existing Model tokens. |
| snapshots/results | Existing C++ aggregate ModelSnapshot layout stays unchanged. QP snapshots are immutable distinct types; results retain wrapper owner/revision and original slots. All lifted indices remain private. |
If shared ModelSnapshot quadratic metadata is introduced in a later version, all of these routes require explicit active-quadratic capability checks before any transformation/backend conversion. Every full-replacement versus linear-only objective mutation must be specified, and serialized/binary compatibility must be versioned. The isolated wrapper avoids that cross-cutting risk now.
Proposed independently owned files:
Root owns registration, installation/umbrella integration and capability exposure. Expose the supported class through quadratic_capabilities(); leave the ordinary Model capability response unchanged until its API can express quadratic data. No existing shared source needs editing beyond that integration for Q1. Avoid a new required dense linear-algebra dependency. Reuse the pinned HiGHS build; OSQP is an optional differential research oracle, not a new runtime requirement.
One monotonic budget starts before snapshot/copy and covers normalization, preflight/lifting, backend import, solve and independent acceptance. Pass the remaining deadline and QP iteration limit to HiGHS. No starts, node quotas or multiple workers in Q1; reject rather than silently reinterpret them. Check a cancelled token before/after backend work and before publishing; a live active-set callback is not promised. Enforce auxiliary/nonzero caps before large allocations. No missing HiGHS fallback. Nullspace/solver failures are explicit, not evidence of nonconvexity, infeasibility, or a supported problem becoming an LP.
Primary research to read/replicate next:
A future arbitrary sparse Hessian API requires a separate verified PSD/NSD acceptance mechanism. A floating Cholesky failure does not distinguish singular PSD from indefinite input reliably; tolerating negative pivots or projecting negative eigenvalues changes the model. Exact/rational or rigorously enclosed factorization, or sufficient verified diagonal-dominance subclasses, are possible later gates. Convexity only on an equality-restricted feasible space is also outside Q1. Preserve these boundaries until their own proofs and conformance oracles exist.