Skip to content

Conversation

@Ordoviz
Copy link
Contributor

@Ordoviz Ordoviz commented Nov 4, 2025

This is a simple fix for a nasty issue:
I would expect that the Sage expression graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5))) returns a star graph on 4 edges. But it actually returned an edgeless graph! This is because the subgraph function expects the edges parameter to be a list that can be iterated over twice but the generator expression ((0, v) for v in range(5)) becomes empty after looping over it once, which caused edges_to_keep_unlabeled to be empty.

While the documentation for subgraph() does not mention that edges is allowed to be a generator expression, many other functions that expect an "iterable container" as parameter work just fine if a generator expression is passed instead. For example, subdivide_edges(), delete_edges() and G.subgraph(v for v in range(4)) work as expected.

There are multiple ways to fix this issue. The simplest and most reliable would be to write edges = list(edges), which would go well with vertices = list(vertices). Instead I opted to fix the symptom by only iterating over edges once, which I believe is faster and uses less memory.

@dcoudert
Copy link
Contributor

dcoudert commented Nov 4, 2025

Good catch.
It would be nice to mention the issue number in the doctest.

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

Documentation preview for this PR (built with commit 5b6555d; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@Ordoviz Ordoviz force-pushed the fix-subgraph-edges-generator branch from c2f230d to b016761 Compare November 4, 2025 14:50
@Ordoviz
Copy link
Contributor Author

Ordoviz commented Nov 4, 2025

I promoted the doctest from TESTS to EXAMPLES so that the issue number (PR number to be precise) is part of the rendered documentation.

The edges generator was looped over twice. If the generator is a
generator expression like `((0, v) for v in range(5))` it becomes empty
after the first loop, causing `edges_to_keep_unlabeled` to be empty.
@Ordoviz Ordoviz force-pushed the fix-subgraph-edges-generator branch from b016761 to 5b6555d Compare November 4, 2025 20:55
Copy link
Contributor

@dcoudert dcoudert left a comment

Choose a reason for hiding this comment

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

LGTM.

vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 8, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 8, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 9, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 9, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 10, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 11, 2025
sagemathgh-41130: Fix G.subgraph(edges=generator) deleting all edges
    
This is a simple fix for a nasty issue:
I would expect that the Sage expression
`graphs.CompleteGraph(5).subgraph(edges=((0, v) for v in range(5)))`
returns a star graph on 4 edges. But it actually returned an edgeless
graph! This is because the `subgraph` function expects the `edges`
parameter to be a list that can be iterated over twice but the
[generator expression](https://peps.python.org/pep-0289/) `((0, v) for v
in range(5))` becomes empty after looping over it once, which caused
`edges_to_keep_unlabeled` to be empty.

While the [documentation for `subgraph()`](https://doc-develop--sagemath
.netlify.app/html/en/reference/graphs/sage/graphs/generic_graph.html#sag
e.graphs.generic_graph.GenericGraph.subgraph) does not mention that
`edges` is allowed to be a generator expression, many other functions
that expect an "iterable container" as parameter work just fine if a
generator expression is passed instead. For example,
`subdivide_edges()`, `delete_edges()` and `G.subgraph(v for v in
range(4))` work as expected.

There are multiple ways to fix this issue. The simplest and most
reliable would be to write `edges = list(edges)`, which would go well
with [`vertices = list(vertices)`](https://github.com/sagemath/sage/blob
/aa27703384a568d85f1751197efe06ff135be352/src/sage/graphs/generic_graph.
py#L14400). Instead I opted to fix the symptom by only iterating over
`edges` once, which I believe is faster and uses less memory.
    
URL: sagemath#41130
Reported by: Lennard Hofmann
Reviewer(s): David Coudert
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants