-
Notifications
You must be signed in to change notification settings - Fork 194
Read epsilon-constraint duals as frontier slope / exchange rate in multi-objective skill #1406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cafzal
wants to merge
9
commits into
NVIDIA:main
Choose a base branch
from
cafzal:claude/elastic-goodall-3693ff
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+23
−5
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
fe13bd5
Read epsilon-constraint duals as frontier slope / exchange rate in mu…
cafzal 8ec84d8
Refine dual-accuracy wording: solve tolerance, knee two-sidedness
cafzal c8d65c7
Fact-check fixes: LP eval + no-dual-for-quadratic-constraint caveat
cafzal 992e14d
Restore QP eval: QP duals confirmed (barrier, 26.06)
cafzal 84a9856
Note zero dual = slack ε-bound (complementary slackness)
cafzal 2f407c1
Align quadratic-constraint dual caveat with verified whole-solve beha…
cafzal 46a684c
Tighten Step 3 dual note: MECE, distilled
cafzal d08d295
Align dual wording with #1408 review: drop "shadow price" and "barrie…
cafzal 65d958e
Final-pass refinements: drop redundant parenthetical, precise bend/we…
cafzal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,10 +92,12 @@ subject to f2(x) ≤ ε2 | |
|
|
||
| Sweep each `ε_k` across the range from the payoff table. Each `(ε2, ε3, …)` combination is a single standard cuOpt solve. This recovers the **full** frontier, including the concave regions weighted-sum cannot reach, which is why it's the default when completeness matters. The cost is more solves (a grid over the constrained objectives) and bookkeeping of the ε values. | ||
|
|
||
| ε-constrain *linear* objectives directly. A quadratic objective (e.g. risk `xᵀΣx`) is simplest kept as the objective `f1` while you ε-constrain the linear ones. A **convex** quadratic objective *can* instead be ε-constrained directly: add it as a quadratic constraint `xᵀQx ≤ ε` (Q positive semidefinite, inequality only), which cuOpt routes through the barrier solver as a second-order cone. Non-convex or equality quadratic constraints are unsupported, and the MILP path stays linear-constraint only. | ||
| ε-constrain *linear* objectives directly. A quadratic objective (e.g. risk `xᵀΣx`) is simplest kept as the objective `f1` while you ε-constrain the linear ones. A **convex** quadratic objective *can* instead be ε-constrained directly: add it as a quadratic constraint `xᵀQx ≤ ε`, which cuOpt handles as a second-order cone. Non-convex or equality quadratic constraints are unsupported, and the MILP path stays linear-constraint only. | ||
|
|
||
| Spot it in existing code: a hand-coded loop over a target or budget value (a return target, a cost cap) is already the ε-constraint method — name it as such, filter dominated points, and read the swept constraint's dual (LP/QP only). | ||
|
|
||
| **That dual is the frontier's local slope.** The dual on a swept ε-constraint is how much the kept objective `f1` moves per unit of that bound — the exchange rate between the two objectives, and the frontier's tangent at that point, read off the solve for free (differencing two solves gives only a secant across any bend between them). A **zero** dual means the bound is slack, not binding — no tradeoff there, so the sweep has run past the frontier's edge. It applies to **LP/QP** off a **linear** ε-constraint only: MILP optima have no duals, and any quadratic constraint voids them for the whole solve, so keep a quadratic objective as `f1` and ε-constrain the linear ones; where no dual is available, difference adjacent points instead. (`cuopt-numerical-optimization-formulation` covers what duals mean and which problem types expose them.) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the paragraph adding much beyond "That dual is the frontier's local slope."? There's also an implicit assumption that the frontier is smooth at this point and therefore has a slope. If not, the dual is not the slope. |
||
|
|
||
| **Picking a method:** weighted-sum for a quick convex sketch or when you know the frontier is convex (e.g. a pure-LP/QP tradeoff); ε-constraint when the problem is MILP, when the frontier may be non-convex, or when the user needs a faithful and complete curve. | ||
|
|
||
| ## Step 4 — sweep, collect, and filter | ||
|
|
@@ -117,14 +119,15 @@ Practical notes: | |
| - **Cap each MILP solve.** Set a per-solve time limit on MILP sweeps (see `cuopt-numerical-optimization-api-python`) — a sweep is many solves, and branch-and-bound can over-spend certifying optimality past a tiny gap, while cuOpt sets no limit by default and won't warn. Report the points as optimal *to the gap you set*, not certified optimal. | ||
| - **Filter dominated points.** A correct sweep can still emit dominated points (especially weighted-sum near the hull, or MILP). Drop them; they are not part of the frontier. | ||
| - **Resolution is a budget.** Curve fidelity trades against solve count. Start coarse to see the shape, then refine the grid only where the curve bends. | ||
| - **Spend the budget where the slope changes (LP/QP).** Because the ε-constraint dual is the frontier's local slope, compare it across solved points: where it barely changes, the curve is nearly straight — interpolate rather than add solves; where it jumps by more than the solve tolerance, the frontier bends between those points — refine there (smaller differences are solver noise, not curvature). This concentrates solves where the curve actually bends instead of spreading them over a uniform grid. MILP has no duals, so judge where to refine from the gaps between primal objective values instead. | ||
| - **Verify, don't assume.** When you claim one method beats another, measure it — e.g. count the efficient points ε-constraint recovered that weighted-sum missed — rather than asserting it; and flag any solve returning feasible-but-not-`Optimal` so a non-certified point is never read as exact. | ||
|
|
||
| ## Step 5 — interpret the frontier | ||
|
|
||
| - **Report tradeoffs, not single numbers.** A frontier point means nothing in isolation. Quote the exchange rate — "≈ $4k of extra cost per 1% of added coverage in this region" — so the user can judge whether a move is worth it. | ||
| - **Flag knee points; don't auto-pick them.** The "knee" is where the curve bends most sharply — beyond it you pay a lot for a little. It's often the best-balanced compromise and worth highlighting, but the final choice is the user's preference, not a rule. | ||
| - **Report tradeoffs, not single numbers.** A frontier point means nothing in isolation. Quote the exchange rate — "≈ $4k of extra cost per 1% of added coverage in this region" — so the user can judge whether a move is worth it. On an LP/QP frontier this exchange rate is the swept constraint's dual at that point — the local slope of the frontier, accurate to the solve's optimality tolerance (tighten it before relying on a dual); on MILP, estimate it from the gap to the adjacent frontier point. | ||
| - **Flag knee points; don't auto-pick them.** The "knee" is where the curve bends most sharply — beyond it you pay a lot for a little. It's often the best-balanced compromise and worth highlighting, but the final choice is the user's preference, not a rule. At the knee the slope is two-sided — the dual just below differs from just above — so quote the exchange rate there as a range, not one number. | ||
| - **Treat dominated or gappy output as a diagnostic.** If dominated points survive filtering, or the frontier is implausibly sparse or perfectly linear, suspect the sweep or the model — most often weighted-sum hiding a concave region (switch to ε-constraint) or a normalization mistake. | ||
| - **State the weighting/ε you used.** Every reported point is conditional on its scalarization. Make that explicit so a single solve is never mistaken for "the" optimum. | ||
| - **State the weighting/ε you used.** Every reported point is conditional on its scalarization. Make that explicit so a single solve is never mistaken for "the" optimum. On LP/QP, the ε-constraint duals are the *implicit weights* at that point — the effective price the solution puts on each constrained objective, and the weights a weighted-sum solve would need to reproduce that tradeoff. Reporting them makes the accepted tradeoff ratio explicit. | ||
|
|
||
| ## Interfaces | ||
|
|
||
|
|
||
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.