Skip to content

Conversation

dcoudert
Copy link
Contributor

@dcoudert dcoudert commented Apr 7, 2025

Currently, method chromatic_polynomial raises an error for immutable graphs with multiple edges.

sage: G = Graph([(0, 1), (0, 1)], multiedges=True, immutable=True)
sage: G.chromatic_polynomial()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[13], line 1
----> 1 G.chromatic_polynomial()

File ~/sage/src/sage/graphs/chrompoly.pyx:172, in sage.graphs.chrompoly.chromatic_polynomial()
    170 cdef mpz_t *coeffs
    171 G = G.relabel(inplace=False)
--> 172 G.remove_multiple_edges()
    173 G.remove_loops()
    174 nverts = G.num_verts()

File ~/sage/src/sage/graphs/generic_graph.py:13733, in GenericGraph.remove_multiple_edges(self)
  13731 labels = self.edge_label(u, v)
  13732 if len(labels) > 1:
> 13733     self.delete_edges((u, v, labels[i]) for i in range(1, len(labels)))

File ~/sage/src/sage/graphs/generic_graph.py:12843, in GenericGraph.delete_edges(self, edges)
  12819 def delete_edges(self, edges):
  12820     """
  12821     Delete edges from an iterable container.
  12822 
   (...)
  12841         120
  12842     """
> 12843     self._backend.del_edges(edges, self._directed)

File ~/sage/src/sage/graphs/base/static_sparse_backend.pyx:707, in sage.graphs.base.static_sparse_backend.StaticSparseBackend.del_edges()
    705         ValueError: graph is immutable; please change a copy instead (use function copy())
    706     """
--> 707     raise ValueError("graph is immutable; please change a copy instead (use function copy())")
    708 
    709 def set_edge_label(self, u, v, l, directed):

ValueError: graph is immutable; please change a copy instead (use function copy())

This is due to a call to relabel followed by a call to remove_multiple_edges which fails in this case.

When algorithm='Python', method chromatic_polynomial_with_cache needs a mutable copy of the input graph.

We fix both issue. Further more, we avoid trying to remove loops from the graph as the chromatic polynomial of a graph with loops is 0.

📝 Checklist

  • The title is concise and informative.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation and checked the documentation preview.

⌛ Dependencies

Copy link

github-actions bot commented Apr 7, 2025

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

Copy link
Contributor

@fchapoton fchapoton left a comment

Choose a reason for hiding this comment

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

good to go, thanx

vbraun pushed a commit to vbraun/sage that referenced this pull request Jun 17, 2025
sagemathgh-39896: fix issue with immutable graphs in `src/sage/graphs/chrompoly.pyx`
    
Currently, method `chromatic_polynomial` raises an error for immutable
graphs with multiple edges.
```sage
sage: G = Graph([(0, 1), (0, 1)], multiedges=True, immutable=True)
sage: G.chromatic_polynomial()
------------------------------------------------------------------------
---
ValueError                                Traceback (most recent call
last)
Cell In[13], line 1
----> 1 G.chromatic_polynomial()

File ~/sage/src/sage/graphs/chrompoly.pyx:172, in
sage.graphs.chrompoly.chromatic_polynomial()
    170 cdef mpz_t *coeffs
    171 G = G.relabel(inplace=False)
--> 172 G.remove_multiple_edges()
    173 G.remove_loops()
    174 nverts = G.num_verts()

File ~/sage/src/sage/graphs/generic_graph.py:13733, in
GenericGraph.remove_multiple_edges(self)
  13731 labels = self.edge_label(u, v)
  13732 if len(labels) > 1:
> 13733     self.delete_edges((u, v, labels[i]) for i in range(1,
len(labels)))

File ~/sage/src/sage/graphs/generic_graph.py:12843, in
GenericGraph.delete_edges(self, edges)
  12819 def delete_edges(self, edges):
  12820     """
  12821     Delete edges from an iterable container.
  12822
   (...)
  12841         120
  12842     """
> 12843     self._backend.del_edges(edges, self._directed)

File ~/sage/src/sage/graphs/base/static_sparse_backend.pyx:707, in
sage.graphs.base.static_sparse_backend.StaticSparseBackend.del_edges()
    705         ValueError: graph is immutable; please change a copy
instead (use function copy())
    706     """
--> 707     raise ValueError("graph is immutable; please change a copy
instead (use function copy())")
    708
    709 def set_edge_label(self, u, v, l, directed):

ValueError: graph is immutable; please change a copy instead (use
function copy())
```

This is due to a call to `relabel` followed by a call to
`remove_multiple_edges` which fails in this case.

When `algorithm='Python'`, method `chromatic_polynomial_with_cache`
needs a mutable copy of the input graph.

We fix both issue. Further more, we avoid trying to remove loops from
the graph as the chromatic polynomial of a graph with loops is 0.


### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [ ] I have updated the documentation and checked the documentation
preview.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#39896
Reported by: David Coudert
Reviewer(s): Frédéric Chapoton
vbraun pushed a commit to vbraun/sage that referenced this pull request Jun 18, 2025
sagemathgh-39896: fix issue with immutable graphs in `src/sage/graphs/chrompoly.pyx`
    
Currently, method `chromatic_polynomial` raises an error for immutable
graphs with multiple edges.
```sage
sage: G = Graph([(0, 1), (0, 1)], multiedges=True, immutable=True)
sage: G.chromatic_polynomial()
------------------------------------------------------------------------
---
ValueError                                Traceback (most recent call
last)
Cell In[13], line 1
----> 1 G.chromatic_polynomial()

File ~/sage/src/sage/graphs/chrompoly.pyx:172, in
sage.graphs.chrompoly.chromatic_polynomial()
    170 cdef mpz_t *coeffs
    171 G = G.relabel(inplace=False)
--> 172 G.remove_multiple_edges()
    173 G.remove_loops()
    174 nverts = G.num_verts()

File ~/sage/src/sage/graphs/generic_graph.py:13733, in
GenericGraph.remove_multiple_edges(self)
  13731 labels = self.edge_label(u, v)
  13732 if len(labels) > 1:
> 13733     self.delete_edges((u, v, labels[i]) for i in range(1,
len(labels)))

File ~/sage/src/sage/graphs/generic_graph.py:12843, in
GenericGraph.delete_edges(self, edges)
  12819 def delete_edges(self, edges):
  12820     """
  12821     Delete edges from an iterable container.
  12822
   (...)
  12841         120
  12842     """
> 12843     self._backend.del_edges(edges, self._directed)

File ~/sage/src/sage/graphs/base/static_sparse_backend.pyx:707, in
sage.graphs.base.static_sparse_backend.StaticSparseBackend.del_edges()
    705         ValueError: graph is immutable; please change a copy
instead (use function copy())
    706     """
--> 707     raise ValueError("graph is immutable; please change a copy
instead (use function copy())")
    708
    709 def set_edge_label(self, u, v, l, directed):

ValueError: graph is immutable; please change a copy instead (use
function copy())
```

This is due to a call to `relabel` followed by a call to
`remove_multiple_edges` which fails in this case.

When `algorithm='Python'`, method `chromatic_polynomial_with_cache`
needs a mutable copy of the input graph.

We fix both issue. Further more, we avoid trying to remove loops from
the graph as the chromatic polynomial of a graph with loops is 0.


### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [ ] I have updated the documentation and checked the documentation
preview.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#39896
Reported by: David Coudert
Reviewer(s): Frédéric Chapoton
vbraun pushed a commit to vbraun/sage that referenced this pull request Jun 21, 2025
sagemathgh-39896: fix issue with immutable graphs in `src/sage/graphs/chrompoly.pyx`
    
Currently, method `chromatic_polynomial` raises an error for immutable
graphs with multiple edges.
```sage
sage: G = Graph([(0, 1), (0, 1)], multiedges=True, immutable=True)
sage: G.chromatic_polynomial()
------------------------------------------------------------------------
---
ValueError                                Traceback (most recent call
last)
Cell In[13], line 1
----> 1 G.chromatic_polynomial()

File ~/sage/src/sage/graphs/chrompoly.pyx:172, in
sage.graphs.chrompoly.chromatic_polynomial()
    170 cdef mpz_t *coeffs
    171 G = G.relabel(inplace=False)
--> 172 G.remove_multiple_edges()
    173 G.remove_loops()
    174 nverts = G.num_verts()

File ~/sage/src/sage/graphs/generic_graph.py:13733, in
GenericGraph.remove_multiple_edges(self)
  13731 labels = self.edge_label(u, v)
  13732 if len(labels) > 1:
> 13733     self.delete_edges((u, v, labels[i]) for i in range(1,
len(labels)))

File ~/sage/src/sage/graphs/generic_graph.py:12843, in
GenericGraph.delete_edges(self, edges)
  12819 def delete_edges(self, edges):
  12820     """
  12821     Delete edges from an iterable container.
  12822
   (...)
  12841         120
  12842     """
> 12843     self._backend.del_edges(edges, self._directed)

File ~/sage/src/sage/graphs/base/static_sparse_backend.pyx:707, in
sage.graphs.base.static_sparse_backend.StaticSparseBackend.del_edges()
    705         ValueError: graph is immutable; please change a copy
instead (use function copy())
    706     """
--> 707     raise ValueError("graph is immutable; please change a copy
instead (use function copy())")
    708
    709 def set_edge_label(self, u, v, l, directed):

ValueError: graph is immutable; please change a copy instead (use
function copy())
```

This is due to a call to `relabel` followed by a call to
`remove_multiple_edges` which fails in this case.

When `algorithm='Python'`, method `chromatic_polynomial_with_cache`
needs a mutable copy of the input graph.

We fix both issue. Further more, we avoid trying to remove loops from
the graph as the chromatic polynomial of a graph with loops is 0.


### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [ ] I have updated the documentation and checked the documentation
preview.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#39896
Reported by: David Coudert
Reviewer(s): Frédéric Chapoton
@vbraun vbraun merged commit 7399268 into sagemath:develop Jun 25, 2025
23 of 25 checks passed
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.

3 participants