Skip to content

Implement as_disjoint_union for unions of regions - #205

Open
Chessing234 wants to merge 3 commits into
teorth:mainfrom
Chessing234:region-union-disjoint
Open

Implement as_disjoint_union for unions of regions#205
Chessing234 wants to merge 3 commits into
teorth:mainfrom
Chessing234:region-union-disjoint

Conversation

@Chessing234

Copy link
Copy Markdown
Contributor

What happens

Region.as_disjoint_union is how a region gets rewritten into the form the rest
of the Python code can work with: a list of convex polytopes that cover it
without overlapping. For Region_Type.UNION it did not exist —

if self.region_type == Region_Type.UNION:
    raise NotImplementedError(self.region_type) # TODO: implement this

so a region built with Region.union could not be converted at all, and neither
could anything containing one.

Fix

Each child's pieces are trimmed against the pieces already accepted, with
Polytope.set_minus, which splits A \ B into pairwise disjoint parts. The
accumulated list therefore stays disjoint at every step and its union is
unchanged, which is exactly the invariant the caller needs.

Subtracting a bounded piece from another leaves unbounded parts routinely, and
those reach Polytope.try_union through the simplification helpers, where they
hit the finite-polytope guard:

>>> Polytope.try_union([Polytope([[0, 1, 0]]), Polytope.rect((0, 1), (0, 1))])
ValueError: Polytope.try_union only supports finite polytopes (an input has extreme rays)

try_union answers "do these have a convex union?", and every caller already
treats None as "no, keep them separate". Raising turns that routine answer
into a crash of the whole pipeline, so the guard now returns None. The
vertex-only feasibility checks still cannot see extreme rays, so the check
itself stays.

Verification

tests/test_region.py gains a case in the style of the ones next to it: 50
trials of three random rectangles, with real overlaps.

  • the disjoint pieces contain exactly the points the union contains
  • no two pieces share an interior point (p.intersect(q).is_empty(include_boundary=False))

Ran separately over random 3-dimensional boxes as well — 2400 sample points
across 6 configurations, no point covered zero times that should be covered, and
none covered twice.

tests/test_region.py passes. Note that tests/test_all.py still fails on
test_affine2's import of large_values, which is the breakage #200 fixes;
this branch does not touch it.

try_union answers "do these polytopes have a convex union?", and every
caller already handles None by keeping the pieces separate. Raising for
an unbounded input therefore turns a routine "no" into a crash of
whatever pipeline is simplifying regions -- and unbounded pieces are
ordinary: subtracting a bounded domain from a half-space produces them.

The vertex-only feasibility checks below still cannot see extreme rays,
so the guard itself stays; only its answer changes.
Region.as_disjoint_union raised NotImplementedError for UNION, so any
region built with Region.union could not be rewritten as a disjoint
union -- the representation the zero-density and large-value code paths
need before they can integrate or compare over a region.

Each child piece is trimmed against the pieces already accepted, using
Polytope.set_minus, which splits A \\ B into pairwise disjoint parts. The
accumulated list therefore stays disjoint and its union is unchanged.
Three random rectangles per trial, so the overlaps are real: the pieces
must contain exactly the points the union contains, and no two of them
may share an interior point.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant