Conversation
Store the constant term of the objective (cᵀx + c0) directly in the `MILP` struct. `objective_value` now includes the offset, and `c0` is threaded through preconditioning, type conversion, and GPU adaptation. The MOI wrapper passes `obj_constant` as `c0` at construction time instead of reapplying it manually after solving. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
|
I don't like giving them free advertising by letting it put itself as a "contributor"... I believe there is a setting somewhere to turn that off. Or you can just commit yourself (which I have come to prefer since it forces me to review each commit) |
it's worth thinking about this some more. it does change things since we are computing relative metrics not absolute like |
|
It's my very first vibe-coding experiment, I haven't reviewed it in detail but of course I plan to, just wanted to start off with a really easy feature. As for commit signature, I actually consider it a good practice. Not to wash my hands clean of the responsibility, but to be able to track AI use in my codebases, with commit statistics and history. This is necessary for some publications which require disclosure of LLM use, and possibly in the future for legal aspects. See e.g. https://www.deployhq.com/blog/how-to-use-git-with-claude-code-understanding-the-co-authored-by-attribution for both sides of the debate. Note that once I move to a containerized setup where I give the agent free rein to run stuff in a safe environment, I will give it a secondary GitHub account like |
|
As for scaling and sign issues:
|
|
Regarding the attribution, just a personal preference thing. Fine to keep it if you prefer that. Agreed on |
Closes #29
Summary
This PR adds a
c0::Tfield to theMILPstruct to store the constant term of the objective function, so that the full objective iscᵀx + c0rather than justcᵀx.Changes
Core
src/problems/milp.jl: Addedc0::Tfield toMILP(afteruc, beforeD1). The constructor acceptsc0 = falseas a default (promotes correctly to the float typeT). UpdatedBase.isapproxto comparec0values. TheQPSDataconstructor now passesc0 = qps.c0.src/problems/solution.jl:objective_value(x, milp)now returnsdot(x, milp.c) + milp.c0.Propagation
src/problems/modify.jl:c0is threaded throughset_eltype(with type conversionT(c0)),set_indtype,set_matrix_type, andAdapt.adapt_structure.src/components/preconditioning.jl:c0is passed unchanged throughprecondition(milp, prec)— the diagonal scalings D1, D2 do not affect a scalar constant.MOI wrapper
src/MOI_wrapper.jl:obj_constantis now passed asc0at MILP construction time. For maximization problems,obj_constantis negated alongsidecso that the storedc0always corresponds to the equivalent minimization. The dual objective value is updated to±(raw_dual_obj + milp.c0).Tests
test/problems/solution.jl: verifiesobjective_valueincludes the offset.test/problems/milp.jl: verifiesisapproxcorrectly distinguishes MILPs with differentc0values.test/components/preconditioning.jl: verifiesc0is unchanged after preconditioning.Notes
kkt_errors!) are intentionally not modified: the primal-dual gap is scale-invariant with respect to the objective constant (it cancels between primal and dual sides), so the convergence check is unaffected.c0field does not interact with preconditioning: it is a scalar constant, not scaled by D1 or D2.🤖 Generated with Claude Code