@@ -3515,7 +3515,7 @@ def allow_multiple_edges(self, new, check=True, keep_label='any'):
3515
3515
3516
3516
self._backend.multiple_edges(new)
3517
3517
3518
- def multiple_edges(self, to_undirected=False, labels=True, sort=False):
3518
+ def multiple_edges(self, to_undirected=False, labels=True, sort=False, key=None ):
3519
3519
"""
3520
3520
Return any multiple edges in the (di)graph.
3521
3521
@@ -3525,7 +3525,11 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False):
3525
3525
3526
3526
- ``labels`` -- boolean (default: ``True``); whether to include labels
3527
3527
3528
- - ``sort`` - boolean (default: ``False``); whether to sort the result
3528
+ - ``sort`` -- boolean (default: ``False``); whether to sort the result
3529
+
3530
+ - ``key`` -- a function (default: ``None``); a function that takes an
3531
+ edge as its one argument and returns a value that can be used for
3532
+ comparisons in the sorting algorithm (we must have ``sort=True``)
3529
3533
3530
3534
EXAMPLES::
3531
3535
@@ -3574,7 +3578,36 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False):
3574
3578
[]
3575
3579
sage: G.multiple_edges(to_undirected=True, sort=True)
3576
3580
[(1, 2, 'h'), (2, 1, 'g')]
3581
+
3582
+ Using the ``key`` argument to order multiple edges of incomparable
3583
+ types (see :trac:`35903`)::
3584
+
3585
+ sage: G = Graph([('A', 'B', 3), (1, 2, 1), ('A', 'B', 4), (1, 2, 2)], multiedges=True)
3586
+ sage: G.multiple_edges(sort=True)
3587
+ Traceback (most recent call last):
3588
+ ...
3589
+ TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '<class 'str'>'
3590
+ sage: G.multiple_edges(labels=False, sort=True, key=str)
3591
+ [('A', 'B'), ('A', 'B'), (1, 2), (1, 2)]
3592
+ sage: G.multiple_edges(sort=True, key=str)
3593
+ [('A', 'B', 3), ('A', 'B', 4), (1, 2, 1), (1, 2, 2)]
3594
+ sage: G.multiple_edges(labels=True, sort=True, key=lambda e:e[2])
3595
+ [(1, 2, 1), (1, 2, 2), ('A', 'B', 3), ('A', 'B', 4)]
3596
+ sage: G.multiple_edges(labels=False, sort=True, key=lambda e:e[2])
3597
+ Traceback (most recent call last):
3598
+ ...
3599
+ IndexError: tuple index out of range
3600
+
3601
+ TESTS::
3602
+
3603
+ sage: Graph().multiple_edges(sort=False, key=str)
3604
+ Traceback (most recent call last):
3605
+ ...
3606
+ ValueError: sort keyword is False, yet a key function is given
3577
3607
"""
3608
+ if (not sort) and key:
3609
+ raise ValueError('sort keyword is False, yet a key function is given')
3610
+
3578
3611
multi_edges = []
3579
3612
seen = set()
3580
3613
@@ -3647,7 +3680,7 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False):
3647
3680
multi_edges.extend((u, v) for _ in L)
3648
3681
3649
3682
if sort:
3650
- multi_edges.sort( )
3683
+ return sorted(multi_edges, key=key )
3651
3684
return multi_edges
3652
3685
3653
3686
def name(self, new=None):
@@ -5092,7 +5125,7 @@ def cycle_basis(self, output='vertex'):
5092
5125
sage: G.cycle_basis() # needs networkx
5093
5126
[[0, 2], [2, 1, 0]]
5094
5127
sage: G.cycle_basis(output='edge') # needs networkx
5095
- [[(0, 2, 'a '), (2, 0, 'b ')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]]
5128
+ [[(0, 2, 'b '), (2, 0, 'a ')], [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'a')]]
5096
5129
sage: H = Graph([(1, 2), (2, 3), (2, 3), (3, 4), (1, 4),
5097
5130
....: (1, 4), (4, 5), (5, 6), (4, 6), (6, 7)], multiedges=True)
5098
5131
sage: H.cycle_basis() # needs networkx
@@ -5134,10 +5167,9 @@ def cycle_basis(self, output='vertex'):
5134
5167
sage: G.cycle_basis() # needs networkx
5135
5168
[[2, 3], [4, 3, 2, 1], [4, 3, 2, 1]]
5136
5169
sage: G.cycle_basis(output='edge') # needs networkx
5137
- [[(2, 3, 'b '), (3, 2, 'c ')],
5170
+ [[(2, 3, 'c '), (3, 2, 'b ')],
5138
5171
[(4, 3, 'd'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')],
5139
5172
[(4, 3, 'e'), (3, 2, 'b'), (2, 1, 'a'), (1, 4, 'f')]]
5140
-
5141
5173
"""
5142
5174
if output not in ['vertex', 'edge']:
5143
5175
raise ValueError('output must be either vertex or edge')
@@ -12568,7 +12600,7 @@ def edges(self, vertices=None, labels=True, sort=None, key=None,
12568
12600
return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key,
12569
12601
ignore_direction=ignore_direction, sort_vertices=sort_vertices)
12570
12602
12571
- def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
12603
+ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False, key=None ):
12572
12604
r"""
12573
12605
Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1``
12574
12606
and ``v`` in ``vertices2``.
@@ -12586,6 +12618,10 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
12586
12618
12587
12619
- ``sort`` -- boolean (default: ``False``); whether to sort the result
12588
12620
12621
+ - ``key`` -- a function (default: ``None``); a function that takes an
12622
+ edge as its one argument and returns a value that can be used for
12623
+ comparisons in the sorting algorithm (we must have ``sort=True``)
12624
+
12589
12625
EXAMPLES::
12590
12626
12591
12627
sage: K = graphs.CompleteBipartiteGraph(9, 3)
@@ -12610,6 +12646,23 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
12610
12646
sage: D.edge_boundary([0], labels=False, sort=True)
12611
12647
[(0, 1), (0, 2)]
12612
12648
12649
+ Using the ``key`` argument to order multiple edges of incomparable
12650
+ types (see :trac:`35903`)::
12651
+
12652
+ sage: G = Graph([(1, 'A', 4), (1, 2, 3)])
12653
+ sage: G.edge_boundary([1], sort=True)
12654
+ Traceback (most recent call last):
12655
+ ...
12656
+ TypeError: unsupported operand parent(s) for <: 'Integer Ring' and '<class 'str'>'
12657
+ sage: G.edge_boundary([1], sort=True, key=str)
12658
+ [('A', 1, 4), (1, 2, 3)]
12659
+ sage: G.edge_boundary([1], sort=True, key=lambda e:e[2])
12660
+ [(1, 2, 3), ('A', 1, 4)]
12661
+ sage: G.edge_boundary([1], labels=False, sort=True, key=lambda e:e[2])
12662
+ Traceback (most recent call last):
12663
+ ...
12664
+ IndexError: tuple index out of range
12665
+
12613
12666
TESTS::
12614
12667
12615
12668
sage: G = graphs.DiamondGraph()
@@ -12619,7 +12672,14 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
12619
12672
[]
12620
12673
sage: G.edge_boundary([2], [0])
12621
12674
[(0, 2, None)]
12675
+ sage: G.edge_boundary([2], [0], sort=False, key=str)
12676
+ Traceback (most recent call last):
12677
+ ...
12678
+ ValueError: sort keyword is False, yet a key function is given
12622
12679
"""
12680
+ if (not sort) and key:
12681
+ raise ValueError('sort keyword is False, yet a key function is given')
12682
+
12623
12683
vertices1 = set(v for v in vertices1 if v in self)
12624
12684
if self._directed:
12625
12685
if vertices2 is not None:
@@ -12639,7 +12699,7 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
12639
12699
output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False)
12640
12700
if e[1] not in vertices1 or e[0] not in vertices1]
12641
12701
if sort:
12642
- output.sort( )
12702
+ return sorted(output, key=key )
12643
12703
return output
12644
12704
12645
12705
def edge_iterator(self, vertices=None, labels=True, ignore_direction=False, sort_vertices=True):
0 commit comments