Skip to content

Fix open ReebGraph.slice dropping edges whose endpoints lie on the slice bounds - #124

Merged
lizliz merged 3 commits into
masterfrom
123-reebgraphslicetypeopen-drops-edges-whose-endpoints-lie-exactly-on-the-slice-bounds
Sep 24, 2026
Merged

lizliz merged 3 commits into
masterfrom
123-reebgraphslicetypeopen-drops-edges-whose-endpoints-lie-exactly-on-the-slice-bounds

Conversation

@ishikaghosh2201

Copy link
Copy Markdown
Collaborator

Description

Fixes two problems in ReebGraph.slice when type="open" (the default):

  1. Edges with an endpoint exactly on a bound were dropped. The crossing-edge check used strict inequalities (f(u) < a and f(v) > b). In an open slice, a vertex at exactly a or b is excluded from v_list, so an edge running from a to b matched neither rule and disappeared. The check is now f(u) <= a and f(v) >= b. It also skips edges already picked up through an included endpoint, so no edge is counted twice.
  2. A zero-width open slice returned points. slice(a, a, type="open") now returns an empty ReebGraph, since (a, a) is the empty set.

For closed slices, an endpoint outside [a, b] with f(u) <= a must have f(u) < a, so the new condition reduces to the old strict one. Closed-slice output doesn't change.

Changes:

  • cereeberus/cereeberus/reeb/reebgraph.py: early return for a zero-width open slice; updated crossing-edge condition and comment in slice.
  • tests/test_reeb_class.py: four new tests (see below).

Motivation and Context

Fixes #___

Example with the package's torus graph (vertices at heights 0, 1, 4, 5 and a double edge from 1 to 4):

Call Before After
ex_rg.torus().slice(1, 4) empty graph 2 arcs (4 vertices, 2 edges, 2 components)
ex_rg.torus().slice(0, 1) empty graph 1 edge
ex_rg.torus().slice(2, 2) 2 isolated points empty graph

Internal code isn't affected. smoothing_and_maps, smoothing and thickening_distance only call slice(..., type="closed"), so their output doesn't change, and neither does the interleaving code built on them.

Related: #115 / #116 (performance changes to slice). The two PRs touch different lines of reebgraph.py and merge there without conflicts. Both add tests to tests/test_reeb_class.py, so whichever merges second will need a small conflict resolution in that file (keep both sets of tests).

How has this been tested?

New tests in tests/test_reeb_class.py:

  • test_slice_open_endpoint_on_bound: a single edge from 0 to 2, sliced at (0, 2), (0, 1) and (1, 2), gives 2 vertices, 1 edge and 1 component, with the new vertices at a and b. Also run with the edge added high→low.
  • test_slice_open_parallel_edges_on_bounds: three parallel edges sliced at (0, 2) stay as 3 separate components, and torus.slice(1, 4) gives 2 arcs.
  • test_slice_open_zero_width_is_empty: torus.slice(a, a) is empty at every height.
  • test_slice_closed_unchanged: closed slices give the same results as before, including single-height slices.

The first three fail on master and pass with this change. The fourth passes on both, which confirms closed slices are unchanged.

make tests: all 88 tests pass (84 existing + 4 new).

I also compared the old and new code on the package's example graphs (Reeb, mapper and merge trees) and on random Reeb graphs:

  • Every closed slice gave identical output.
  • smoothing_and_maps, thickening_distance and the interleaving distance on interleave_example_A vs interleave_example_B didn't change.
  • Every open slice that changed now matches an independent count of components and edges; each one was wrong before.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist

  • I have incremented the version number in the pyproject.toml file if a new version needs to be pushed to pypi. Note that if the number isn't incremented, the package will not be pushed to pypi, which is useful if this PR is only for updating documentation.
  • My code follows the code style of this project and I have run make format to clean up the code with black.
  • My change requires a change to the documentation. I have updated the documentation as necessary and compiled locally to ensure it is clean.
  • I have added tests to cover my changes, and all new and existing tests passed (run make tests).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…graphslicetypeopen-drops-edges-whose-endpoints-lie-exactly-on-the-slice-bounds

@lizliz lizliz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

@lizliz
lizliz merged commit 0bbeb6d into master Sep 24, 2026
4 checks passed
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.

ReebGraph.slice(type="open") drops edges whose endpoints lie exactly on the slice bounds

3 participants