Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BipartiteGraph blindly trusts generic graphs #28897

Closed
kliem opened this issue Dec 18, 2019 · 22 comments
Closed

BipartiteGraph blindly trusts generic graphs #28897

kliem opened this issue Dec 18, 2019 · 22 comments

Comments

@kliem
Copy link
Contributor

kliem commented Dec 18, 2019

BipartiteGraph does currently check edges, when using the method add_edges:

sage: bg = BipartiteGraph()
bg.add_vertices([0, 1, 2], left=[True, False, True])
bg.add_edges([[0, 2]]) 

This doesn't raise an error, but it should.

While BipartiteGraph has its own method add_edge, it seems to trust generic graph do add_edges by iterating over the edges and calling add_edge. This is not the case (anymore).

We fix this, by implementing the method add_edges for BipartiteGraph, which just calls the backend on the prechecked edges.

Component: graph theory

Keywords: bipartite graph, add edges

Author: Jonathan Kliem

Branch/Commit: b0753d2

Reviewer: David Coudert

Issue created by migration from https://trac.sagemath.org/ticket/28897

@kliem kliem added this to the sage-9.0 milestone Dec 18, 2019
@kliem
Copy link
Contributor Author

kliem commented Dec 18, 2019

New commits:

4110553add a doctest to not blindly trust generic graph

@kliem
Copy link
Contributor Author

kliem commented Dec 18, 2019

Commit: 4110553

@kliem
Copy link
Contributor Author

kliem commented Dec 18, 2019

Branch: public/28897

@dcoudert
Copy link
Contributor

comment:2

Actually, the added doctest shows that we need a specific method for add_edges. The one of generic graph calls a backend that is not specific to bipartite graphs.

@kliem
Copy link
Contributor Author

kliem commented Dec 20, 2019

comment:4

At the moment everything works fine. add_edges calls add_edge, which checks that the vertices lie in different partitions.

However, once one modifies add_edges to directly call the backend, BipartiteGraph needs a modified version of it. If we add a special version now, we still have to remember it, once we optimize add_edges in generic graph.

The doctest would just ensure that one doesn't miss it with little effort for now.

@dcoudert
Copy link
Contributor

comment:5

No. In 9.0.beta9, add_edges calls self._backend.add_edge(u, v, label, self._directed), and so the added doctest fails.
The patchbots are reporting that failing doctest.

@kliem
Copy link
Contributor Author

kliem commented Dec 20, 2019

comment:6

Ok. Never mind. I must have misread and not tested it (even though I thought I did).

@kliem

This comment has been minimized.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Dec 21, 2019

Changed commit from 4110553 to a038512

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Dec 21, 2019

Branch pushed to git repo; I updated commit sha1. New commits:

a038512implement add_edges for BipartiteGraph

@dcoudert
Copy link
Contributor

Reviewer: David Coudert

@dcoudert
Copy link
Contributor

comment:10

You must change the documentation for parameter loops as loops should not be allowed in a bipartite graph. I suggest to set it to False by default, and document that it is always considered as False. This is exactly what current implementation do. For instance, with this patch, we get

sage: G = BipartiteGraph([(0,0)], loops=True)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-273b7e5c1458> in <module>()
----> 1 G = BipartiteGraph([(Integer(0),Integer(0))], loops=True)

/Users/dcoudert/sage3/sage/local/lib/python3.7/site-packages/sage/graphs/bipartite_graph.py in __init__(self, data, partition, check, *args, **kwds)
    309         else:
    310             if 'loops' in kwds and kwds['loops']:
--> 311                 raise ValueError('loops are not allowed in bipartite graphs')
    312             kwds['loops'] = False
    313 

ValueError: loops are not allowed in bipartite graphs

I just realized that some input parameters of BipartiteGraph are not documented, like weighted, multiedges, and of course loops.

Instead of defining a function check_edge and call self._backend.add_edges(map...), it might be faster to make a loop for e in edges in which you check the validity of that edge and if the edge is ok, then call self._backend.add_edge(u, v, label, self._directed). Indeed, method self._backend.add_edges also has to check if an edge is a pair or a triple.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Dec 22, 2019

Changed commit from a038512 to b0753d2

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Dec 22, 2019

Branch pushed to git repo; I updated commit sha1. New commits:

b0753d2improved method add_edges and documentation

@kliem
Copy link
Contributor Author

kliem commented Dec 22, 2019

comment:12

Ok.

As for ignoring loops, I wouldn't allow it. In a generic graph, I can see that one wants the method to remove loops for comfort.

In a bipartite graph, one needs to clean up the input anyway. Loops is just one of many cases, where the ends of an edge are not in different parts.

@dcoudert
Copy link
Contributor

comment:13

Please set the default value of loops to False.

Once done, you can set to positive review on my behalf.

@kliem
Copy link
Contributor Author

kliem commented Dec 22, 2019

comment:14

I don't understand. Doesn't False mean that we just skip loops without error?

@dcoudert
Copy link
Contributor

comment:15

No, in Graph we raise an error when loops is False or None. The behavior has been changed some months ago after years of deprecation warnings.

sage: G = Graph(loops=False)
sage: G.add_edge(0,0)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-a53374f9e702> in <module>()
----> 1 G.add_edge(Integer(0),Integer(0))

/Users/dcoudert/sage3/sage/local/lib/python3.7/site-packages/sage/graphs/generic_graph.py in add_edge(self, u, v, label)
  10816                     pass
  10817 
> 10818         self._backend.add_edge(u, v, label, self._directed)
  10819 
  10820     def add_edges(self, edges, loops=True):

/Users/dcoudert/sage3/sage/local/lib/python3.7/site-packages/sage/graphs/base/sparse_graph.pyx in sage.graphs.base.sparse_graph.SparseGraphBackend.add_edge (build/cythonized/sage/graphs/base/sparse_graph.c:17581)()
   1500 
   1501         if u_int == v_int and not self._loops:
-> 1502             raise ValueError(f"cannot add edge from {u!r} to {v!r} in graph without loops")
   1503 
   1504         if not self.multiple_edges(None):

ValueError: cannot add edge from 0 to 0 in graph without loops
sage: G = Graph(loops=None)
sage: G.add_edge(0,0)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-a53374f9e702> in <module>()
----> 1 G.add_edge(Integer(0),Integer(0))

/Users/dcoudert/sage3/sage/local/lib/python3.7/site-packages/sage/graphs/generic_graph.py in add_edge(self, u, v, label)
  10816                     pass
  10817 
> 10818         self._backend.add_edge(u, v, label, self._directed)
  10819 
  10820     def add_edges(self, edges, loops=True):

/Users/dcoudert/sage3/sage/local/lib/python3.7/site-packages/sage/graphs/base/sparse_graph.pyx in sage.graphs.base.sparse_graph.SparseGraphBackend.add_edge (build/cythonized/sage/graphs/base/sparse_graph.c:17581)()
   1500 
   1501         if u_int == v_int and not self._loops:
-> 1502             raise ValueError(f"cannot add edge from {u!r} to {v!r} in graph without loops")
   1503 
   1504         if not self.multiple_edges(None):

ValueError: cannot add edge from 0 to 0 in graph without loops

@kliem
Copy link
Contributor Author

kliem commented Dec 22, 2019

comment:16

Yes. But when you do

sage: G.add_edges([[0, 0]], loops=False)

it just ignores all the loops and does not raise an error (as is documented in add_edges).

@dcoudert
Copy link
Contributor

comment:17

Right.

LGTM.

@fchapoton
Copy link
Contributor

comment:18

9.0 is out

@fchapoton fchapoton modified the milestones: sage-9.0, sage-9.1 Jan 1, 2020
@vbraun
Copy link
Member

vbraun commented Jan 5, 2020

Changed branch from public/28897 to b0753d2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants