Skip to content

eliminate over-approximates the projection by up to ~2.5e-4 on some instances #3

Description

@cl445

Summary

eliminate can return a projected polytope whose bounding box is noticeably larger than the true projection, by up to ~2.5e-4 on some instances. Since a projection preserves the extent in the kept dimensions, bounding_box(eliminate(p, ids)) should equal bounding_box(p) in those dimensions. On degenerate random polytopes it does not, and the gap is far above the solver tolerance.

Reproduction

using PolyDAQP, Random
Random.seed!(1305)
A, b = randn(6,40), rand(40)
p  = Polyhedron(A, b)
ub, lb = bounding_box(p)          # exact bounding box of p (all 6 dims)
pn = eliminate(p, [4,5,6])        # project onto dims 1,2,3
ubn, lbn = bounding_box(pn)
ubn[3] - ub[3]                    # 0.00025336583177260064, should be ~0

The eliminated polytope is a strict over-approximation (ubn > ub, never smaller): a facet that should bound the projection is missing.

Root cause

The over-approximation comes from the combinatorial pruning in eliminate, in two parts.

1. The sum(Hcand) > level+1 Chernikov filter drops real facets. That cardinality bound (a combination's history has at most level+1 original constraints) only holds under non-degeneracy. Random polytopes are degenerate, so a genuine facet of the projection can have a larger history and is discarded. On seed 1305 (error in the dim-3 upper bound):

variant error #constraints
current (cardinality filter) 2.5e-4 116
subset-adjacency filter 5.9e-8 129
no combinatorial filter 6.7e-16 4658

Disabling the filter entirely makes it exact, which confirms the filter is what drops the facet, but that blows the intermediate constraint count up about 40x, so it is not a usable fix.

A cheap adjacency filter is not sufficient either. Replacing the cardinality test with the standard subset-adjacency test (skip a combination only if some other constraint's history is a subset of the combined one) is never worse than the current code over 2000 random seeds and fixes the single worst case, but it still leaves 8/2000 failures and a 5.5e-5 worst case, because the subset test also has false positives on degenerate instances.

2. A second, smaller source is minrep. Even with no combinatorial filter, a residual around 1e-7 remains, from the redundancy check running at DAQP's default primal_tol = 1e-6: a constraint protruding by about 1e-7 is classified as redundant and dropped.

Bottom line

The accuracy eliminate can currently deliver on degenerate inputs is around 1e-4 with the fast filter. The elimination testset in test/runtests.jl asserts this to δ = 1e-8, so it fails whenever CI lands on one of these instances (8 of 2000 random seeds here). The follow-up comment identifies the fix: replacing the cardinality filter with history-dedup removes the macroscopic errors (machine epsilon on most seeds). A residual around 1e-7 remains from LP-based redundancy removal on the degenerate intermediate polytopes, so the test's δ should also be relaxed to about 1e-6.

Relation to darnstrom/daqp#160

This is what turns the PolyDAQP.jl check red on darnstrom/daqp#160, but the two are unrelated: that PR is a division-to-reciprocal rewrite in the DAQP LDP transform, and on arm64 it produces bit-identical bounding boxes to master across all 2000 seeds here. The over-approximation is present on unmodified master.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions