Repository navigation
Add the setting child_order and the branching rule LEAST_FRACTIONAL - #2
Draft
baggepinnen wants to merge 2 commits into
Draft
baggepinnen wants to merge 2 commits into
baggepinnen wants to merge 2 commits into
Conversation
DAQPSettings.child_order selects which child of a branch-and-bound node is explored first: the one whose bound of the binary constraint is nearest to the relaxation (DAQP_CHILD_NEAREST, the default and the previous behavior), the farthest (DAQP_CHILD_FARTHEST), the one with the upper bound active (DAQP_CHILD_UP) or the one with the lower bound active (DAQP_CHILD_DOWN). The lower bounds of the children, which are computed from the distance of the relaxation to the nearest and the farthest bound, remain attached to the child that activates the corresponding bound. DAQP_BRANCHING_LEAST_FRACTIONAL selects, among the binary constraints that the relaxation does not satisfy, the one nearest to its nearest bound relative to the distance between its bounds. The field is appended to DAQPSettings; the code generation, the Julia, Python and MATLAB interfaces and the documentation are updated. The test 31_bnb_child_order and the Julia test sets check that every rule with every child order finds the optimal solution, that the child order changes the explored tree, that a parallel portfolio of rules and child orders finds the same solution and that generated code holds the setting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
child_order is not compared by daqp_parallel_compatible, so the threads of a parallel solve may use different child orders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Merged the updated
The review found no defect in the changes of this PR. Results after the merge: ctest 34/34, Julia 2035/2035. The benchmark in the description was run on the code before these fixes. Only the parallel solves with large objective offsets ( Host: demeter2, session |
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.
Adds the setting
child_orderand the branching ruleDAQP_BRANCHING_LEAST_FRACTIONALto branch and bound. Based on JuliaComputing/daqp#1 (bnb-portfolio) so that portfolios ofdaqp_solve_parallelcan mix rules and child orders.Design
DAQPSettings.child_order(appended at the end of the struct) selects the child of a node that is explored first:DAQP_CHILD_NEAREST(0, default, previous behavior),DAQP_CHILD_FARTHEST(1),DAQP_CHILD_UP(2, upper bound active),DAQP_CHILD_DOWN(3, lower bound active).daqp_branch_oncomputes the lower bounds of the near and the far child as before and attaches each one to the child that activates the corresponding bound: the child spawned innode+1(explored first) receives the bound of the bound it activates, so a flipped order does not exchange the bounds used for pruning.DAQP_BRANCHING_LEAST_FRACTIONAL(4) selects, among the binary constraints that the relaxation does not satisfy, the one with the smallest distance to its nearest bound relative to half the distance between its bounds (ties: the first in the order of the constraints). It shares the loop ofMOST_FRACTIONALindaqp_get_branch_id.DAQPSettings:daqp_default_settings,codegen/codegen.c(positional initializer), JuliaDAQPSettingsand constants, Pythondaqp.pxd/daqp.pyx(keyword, settings getter/setter), MATLABdaqpmex.c, anddocs/docs/settings.md,docs/docs/miqp.md.Tests
interfaces/daqp-eigen/tests/31_bnb_child_order.cpp: 40 problems x {eq_reduction off, on} x 4 rules (FIRST, LAST, MOST_FRACTIONAL, LEAST_FRACTIONAL) x 4 child orders reach the optimum of the default (abs_subopt = 0); the default equals NEAREST node for node; the child order changes the node count of every rule; LEAST and MOST fractional differ; a 6-threaddaqp_solve_parallelportfolio of mixed rules and child orders finds the same optimum. Exchanging the two lower bounds indaqp_branch_on(mutation check) makes this test fail.child_order(compiled with gcc). Testset "Parallel BnB": a 4-model portfolio of mixed rules and child orders finds the optimum.ctest -j32: 33/33 passed (including the Julia test suite).Node counts over the 40 problems of the test (eq_reduction off):
Benchmark
Release build on demeter2 (shared machine, other jobs running at low priority, so the times contain some noise). Every problem is solved with a fresh model per solve, wall time around
solve(minimum of 3 repetitions if below 0.2 s),time_limit = 5s.Problem families (problems x variables / binaries):
pwa N8,pwa N12: LinearMPC examplepwa_rotation(27 states each; 32/8, 48/12).spring N6,spring N8: LinearMPC examplehybrid_spring(35 each; 90/36, 120/48).sat N20,sat N30: LinearMPC examplesatellite(binary thrusters; 35 each; 60/40, 90/60).rand 30/20,rand 40/30:generate_test_MIQP(20 and 10 problems).UC 5x8: unit commitment, 5 units x 8 steps, on/off binaries with minimum and maximum power and a demand constraint (12 problems; 80/40).thermo N30: condensed MPC of a first-order thermal system with an on/off input over 30 steps (12 problems; 30/30).The MIQPs of the LinearMPC examples were taken along the closed-loop trajectory of the example scenario and at random states. The example
invpend_contactis infeasible already at the origin (also with LinearMPC and its own DAQP) and is excluded. No combination returned an objective different from the default (relative tolerance 1e-6).Single rule x child order
Shifted geometric mean (shift 0.1 ms) of the time relative to the fastest combination on each problem (1.00 = fastest on every problem):
Absolute times (shifted geometric mean) of the default first/nearest: pwa N8 0.22 ms, pwa N12 3.96 ms, spring N6 10.8 ms, spring N8 90.8 ms, sat N20 0.095 ms, sat N30 0.55 ms, rand 0.05 / 0.15 ms, UC 2636 ms, thermo 23.4 ms.
Number of problems on which a combination is the fastest (ties within 0.01 % counted for all), selected families:
UC 5x8 within the time limit of 5 s: mostfrac/up solves 9 of 12, first/nearest 5, last/nearest 8, leastfrac (any order) at most 1. The times of the UC family are bounded by the limit, so its ratios understate the differences.
Observations:
Parallel portfolios (
daqp_solve_parallel)248 problems (all families above). Greedy portfolios: members added in order of the largest reduction of the shifted geometric mean of the per-problem best member time, starting from first/nearest (selected on the same problems, so in-sample). "> 1 ms": the 135 problems on which first/nearest takes more than 1 ms.
Per family (parallel sgm [ms], default in parentheses), rules4_nearest: spring N8 83.4 (90.8), UC 1284 (2636), sat N30 0.53 (0.55), pwa N12 3.41 (3.96), sat N20 0.137 (0.095), rand 30/20 0.098 (0.051). On UC the parallel time is below the best single member (1996 ms) since the shared incumbent bound prunes the trees of all threads.
Open points
invpend_contactproblems:daqp_solvereturns infeasible (-1, 1 node), whiledaqp_solve_parallelwithpresolve = 1returns exit flag 5 withfvalabout 1.8e44 after the time limit (withpresolve = 0it returns -1). The problems have 36 soft constraints that can only be satisfied with very large slacks; the single solve prunes the root since its objective exceedsfval_bound = DAQP_INF, whiledaqp_bnb_lbadds the constantctofval_boundwhenwork->bnb->shared != NULL, which presumably raises the bound above the root objective. Not addressed here.Host: demeter2, session session_01JGy8Ya4ZvmiQUA33aivGGJ (sub-agent), working directory /tmp/daqp-childorder
🤖 Generated with Claude Code