[WIP] Add tolerance constructor to approximation configs#105
[WIP] Add tolerance constructor to approximation configs#105acostarelli wants to merge 4 commits into
Conversation
… configs Users can now build a config from an error tolerance instead of inverting the method's error formula by hand. Each config with a documented closed-form gap gets a keyword-only outer constructor that takes `tolerance` and `max_delta` (plus `max_delta_x`/`max_delta_y` for bilinear), resolves `depth`, and delegates to the existing positional constructor. Bin2 and HybS get informative error stubs since their composite gap formula isn't documented in-source yet; the no-op configs fall through to Julia's natural MethodError because an empty-struct kw stub would clobber the auto-generated zero-arg constructor. Replaces the four "Relaxation gap <= 2^(...)" tests in test_nmdt_approximations.jl with a new test_tolerance_dispatch.jl that requests several tolerances and asserts achieved gap <= tolerance for each implemented method. Monotonic convergence and structural-correctness tests are retained — only the one-to-one bound checks are replaced. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Performance Results This branch |
- Move all quadratic and bilinear config constructors inside the struct body as inner constructors using new(...). Quadratic configs take either depth or (tolerance, max_delta) via a single merged kwargs constructor; Bin2Config/HybSConfig keep quad_config positional with kwargs for the remaining fields. Auto-generated all-positional constructors are now suppressed, so every call site moves to kwargs. - Update every positional call site in src/ and test/ accordingly, including internal EpigraphQuadConfig calls in sawtooth.jl, hybs.jl, and nmdt_common.jl, plus the bilinear_delta_benchmark wrappers. - Drop explanatory comments at the top of both no_approx.jl files and the stale "see test_tolerance_dispatch.jl" comment in test_nmdt_approximations.jl. - In test_tolerance_dispatch.jl: rename greek-letter variables to ASCII (eps -> tol, delta), drop the +1e-6 solver-tolerance slack in favor of +1e-10 (pure float-roundoff guard at SOS2 exact-integer boundaries), remove the stub-configs-error-informatively testset, and generalize the non-unit-domain testset to iterate over every config. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Approximation config constructors take only depth/segments now. A new
`tol_depth(::Type{Cfg}; tolerance, max_delta, …)::Int` family derives the
discrete knob from a target gap. Bilinear configs `Bin2Config{Q}` and
`HybSConfig{Q}` are parameterized on their inner quad type so helpers can
dispatch on the pair; HybS also exposes `tol_epigraph_depth` for its cross-
term knob. Both bilinear helpers restrict to the inner Qs for which the
formulation is structurally valid and raise MethodError otherwise.
Helper docstrings carry the math derivations (one-sided 2× factor for
Bin2 over Sawtooth/SOS2, half-and-half budget split for HybS), so the
inversion is auditable from the source.
Sawtooth's `epigraph_depth` docstring is corrected: when nonzero it gates
a free variable z in [epigraph(x), sawtooth(x)], so the worst-case error
becomes `max(Δ²·2^{-2L_s-2}, Δ²·2^{-2L_e-2})` and the epigraph side can
dominate when `L_e < L_s`. SOS2 `pwmcc_segments` is documented as an LP-
relaxation tightener that does not enter the PWL error bound.
Tests cover analytical worst-case points plus a dense grid and log
`max_gap / tolerance` per case; ratios stay ≤ 1 across the suite.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- rename tol_depth → tolerance_depth, tol_epigraph_depth → tolerance_epigraph_depth
- share _ceil_positive(x::Float64) helper in quadratic common.jl
- generalize _normed_variable! to accept any AbstractJuMPScalar (AffExpr too)
- extend Bin2Config{Q} tolerance_depth to support NMDTQuadConfig / DNMDTQuadConfig
inner Qs (require epigraph_depth = 0); rewrite bin2 math/notation
- rewrite hybs.jl docstring: explain why Q must over-estimate, derive
lower/upper from the sandwich inequalities, drop the "budget" wording
- state the epigraph_depth ∈ {0} ∪ [depth, ∞) contract in Sawtooth/NMDT/DNMDT
tolerance_depth docstrings; add tolerance_epigraph_depth helpers; clarify
in struct docstrings that epigraph_depth is a structural MIP change,
contrasted with the LP-only pwmcc_segments
- drop pwmcc_segments = 0 overrides from tolerance/quadratic tests (no effect
on MIP optimum)
- split NMDT tightening test into named with/without-tightening cases
- test_tolerance_dispatch: multiple dispatch over the if/elseif sampler,
include boundary corner points, assert ratio ≤ 1, Δ = 4 → Δ = 7 for
SolverSOS2, rename shadowing loop vars, drop @test_throws MethodError
testsets
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| from `xy` under MIN/MAX objectives. | ||
|
|
||
| **Caveat for NMDT/DNMDT inner Q**: these are only one-sided-over when their | ||
| `epigraph_depth = 0`. With `epigraph_depth > 0`, the inner result becomes free |
There was a problem hiding this comment.
Is this true that they are one-sided when epi_depth=0? I don't agree intuitively. And if this is true, shouldn't this mean we can use this with HybS?
| in the lower bound and sign `+` in the upper bound, so if `z_x` could | ||
| *under*-estimate `x²` then the `−z_x` term in the lower can drive `lower > xy` | ||
| and the sandwich is invalid. This rules out `EpigraphQuadConfig` (one-sided | ||
| under) and the two-sided `NMDTQuadConfig` / `DNMDTQuadConfig` for the tolerance |
There was a problem hiding this comment.
So are they one sided or two sided, the nmdt quads?
| # --- Tolerance helpers --- | ||
| # | ||
| # Notation: Δx, Δy are domain lengths; ε denotes errors. Let | ||
| # ε_q = max(x² − z_x, y² − z_y, 0) inner-quad one-sided-over error |
There was a problem hiding this comment.
If
There was a problem hiding this comment.
Replace your math explanation with mine:
Since
We are using the same approximation for both inner quadratics, and the same for both
There was a problem hiding this comment.
The other docstrings should be notationally consistent with what I've used here, if not already.
There was a problem hiding this comment.
And also, if you can modify the other docstrings to approach a similar proof style as I've done, do that too.
| Defined for one-sided-over inner quads: `SawtoothQuadConfig`, `SolverSOS2QuadConfig`, | ||
| `ManualSOS2QuadConfig`, `NMDTQuadConfig`, `DNMDTQuadConfig`. `EpigraphQuadConfig` | ||
| is excluded — it is one-sided-under, so the sign of `ε_p` flips and the bound | ||
| above no longer applies; an Epigraph inner quad can drive `z` arbitrarily far |
There was a problem hiding this comment.
Thinking out loud: can we do Bin3 + epigraph?
TODO: