@@ -22965,17 +22965,18 @@ def is_hamiltonian(self, solver=None, constraint_generation=None,
22965
22965
except EmptySetError:
22966
22966
return False
22967
22967
22968
+
22968
22969
def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False):
22969
22970
r"""
22970
22971
Tests for isomorphism between self and other.
22971
22972
22972
22973
INPUT:
22973
22974
22974
- - ``certificate`` -- if True, then output is `(a, b)`, where `a`
22975
- is a boolean and `b` is either a map or ``None``.
22975
+ - ``certificate`` -- if True, then output is `(a, b)`, where `a`
22976
+ is a boolean and `b` is either a map or ``None``
22976
22977
22977
- - ``edge_labels`` -- boolean (default: ``False``); if ``True`` allows
22978
- only permutations respecting edge labels.
22978
+ - ``edge_labels`` -- boolean (default: ``False``); if ``True`` allows
22979
+ only permutations respecting edge labels
22979
22980
22980
22981
OUTPUT:
22981
22982
@@ -23200,10 +23201,12 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False
23200
23201
if not self.order() and not other.order():
23201
23202
return (True, None) if certificate else True
23202
23203
23203
- if (self.is_directed() != other.is_directed() or self.order() != other.order() or
23204
- self.size() != other.size() or self.degree_sequence() != other.degree_sequence()):
23204
+ if (self.is_directed() != other.is_directed() or
23205
+ self.order() != other.order() or
23206
+ self.size() != other.size() or
23207
+ self.degree_sequence() != other.degree_sequence()):
23205
23208
if certificate:
23206
- return False,None
23209
+ return False, None
23207
23210
else:
23208
23211
return False
23209
23212
@@ -23215,36 +23218,53 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False
23215
23218
if edge_labels and sorted(self.edge_labels(), key=str) != sorted(other.edge_labels(), key=str):
23216
23219
return (False, None) if certificate else False
23217
23220
else:
23218
- G, partition, relabeling, G_edge_labels = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True)
23219
- self_vertices = sum(partition,[])
23220
- G2, partition2, relabeling2, G2_edge_labels = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True)
23221
+ ret = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True,
23222
+ ignore_edge_labels=(not edge_labels),
23223
+ return_edge_labels=True)
23224
+ G, partition, relabeling, G_edge_labels = ret
23225
+ self_vertices = sum(partition, [])
23226
+ ret = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True,
23227
+ ignore_edge_labels=(not edge_labels),
23228
+ return_edge_labels=True)
23229
+ G2, partition2, relabeling2, G2_edge_labels = ret
23230
+
23221
23231
if [len(_) for _ in partition] != [len(_) for _ in partition2]:
23222
23232
return (False, None) if certificate else False
23223
- multilabel = (lambda e:e) if edge_labels else (lambda e:[[None, el[1]] for el in e])
23233
+
23234
+ if edge_labels:
23235
+ def multilabel(e):
23236
+ return e
23237
+ else:
23238
+ def multilabel(e):
23239
+ return [[None, el[1]] for el in e]
23240
+
23224
23241
if [multilabel(_) for _ in G_edge_labels] != [multilabel(_) for _ in G2_edge_labels]:
23225
23242
return (False, None) if certificate else False
23226
- partition2 = sum(partition2,[])
23243
+ partition2 = sum(partition2, [])
23227
23244
other_vertices = partition2
23228
23245
else:
23229
23246
G = self
23230
23247
partition = [self_vertices]
23231
23248
G2 = other
23232
23249
partition2 = other_vertices
23233
- G_to = {u: i for i,u in enumerate(self_vertices)}
23234
- from sage.graphs.graph import Graph
23235
- from sage.graphs.digraph import DiGraph
23236
- DoDG = DiGraph if self._directed else Graph
23250
+ G_to = {u: i for i, u in enumerate(self_vertices)}
23251
+ if self._directed:
23252
+ from sage.graphs.digraph import DiGraph
23253
+ DoDG = DiGraph
23254
+ else:
23255
+ from sage.graphs.graph import Graph
23256
+ DoDG = Graph
23237
23257
H = DoDG(len(self_vertices), loops=G.allows_loops())
23238
23258
HB = H._backend
23239
- for u,v in G.edge_iterator(labels=False):
23259
+ for u, v in G.edge_iterator(labels=False):
23240
23260
HB.add_edge(G_to[u], G_to[v], None, G._directed)
23241
23261
G = HB.c_graph()[0]
23242
23262
partition = [[G_to[vv] for vv in cell] for cell in partition]
23243
23263
GC = G
23244
- G2_to = {u: i for i,u in enumerate(other_vertices)}
23264
+ G2_to = {u: i for i, u in enumerate(other_vertices)}
23245
23265
H2 = DoDG(len(other_vertices), loops=G2.allows_loops())
23246
23266
H2B = H2._backend
23247
- for u,v in G2.edge_iterator(labels=False):
23267
+ for u, v in G2.edge_iterator(labels=False):
23248
23268
H2B.add_edge(G2_to[u], G2_to[v], None, G2._directed)
23249
23269
G2 = H2B.c_graph()[0]
23250
23270
partition2 = [G2_to[vv] for vv in partition2]
@@ -23448,7 +23468,6 @@ class by some canonization function `c`. If `G` and `H` are graphs,
23448
23468
....: assert gcan0 == gcan1, (edges, labels, part, pp)
23449
23469
....: assert gcan0 == gcan2, (edges, labels, part, pp)
23450
23470
"""
23451
-
23452
23471
# Check parameter combinations
23453
23472
if algorithm not in [None, 'sage', 'bliss']:
23454
23473
raise ValueError("'algorithm' must be equal to 'bliss', 'sage', or None")
@@ -23492,29 +23511,29 @@ class by some canonization function `c`. If `G` and `H` are graphs,
23492
23511
if edge_labels or self.has_multiple_edges():
23493
23512
G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition, return_relabeling=True)
23494
23513
G_vertices = list(chain(*partition))
23495
- G_to = {u: i for i,u in enumerate(G_vertices)}
23514
+ G_to = {u: i for i, u in enumerate(G_vertices)}
23496
23515
DoDG = DiGraph if self._directed else Graph
23497
23516
H = DoDG(len(G_vertices), loops=G.allows_loops())
23498
23517
HB = H._backend
23499
- for u,v in G.edge_iterator(labels=False):
23518
+ for u, v in G.edge_iterator(labels=False):
23500
23519
HB.add_edge(G_to[u], G_to[v], None, G._directed)
23501
23520
GC = HB.c_graph()[0]
23502
23521
partition = [[G_to[vv] for vv in cell] for cell in partition]
23503
- a,b, c = search_tree(GC, partition, certificate=True, dig=dig)
23522
+ a, b, c = search_tree(GC, partition, certificate=True, dig=dig)
23504
23523
# c is a permutation to the canonical label of G, which depends only on isomorphism class of self.
23505
23524
H = copy(self)
23506
23525
c_new = {v: c[G_to[relabeling[v]]] for v in self}
23507
23526
else:
23508
23527
G_vertices = list(chain(*partition))
23509
- G_to = {u: i for i,u in enumerate(G_vertices)}
23528
+ G_to = {u: i for i, u in enumerate(G_vertices)}
23510
23529
DoDG = DiGraph if self._directed else Graph
23511
23530
H = DoDG(len(G_vertices), loops=self.allows_loops())
23512
23531
HB = H._backend
23513
23532
for u, v in self.edge_iterator(labels=False):
23514
23533
HB.add_edge(G_to[u], G_to[v], None, self._directed)
23515
23534
GC = HB.c_graph()[0]
23516
23535
partition = [[G_to[vv] for vv in cell] for cell in partition]
23517
- a,b, c = search_tree(GC, partition, certificate=True, dig=dig)
23536
+ a, b, c = search_tree(GC, partition, certificate=True, dig=dig)
23518
23537
H = copy(self)
23519
23538
c_new = {v: c[G_to[v]] for v in G_to}
23520
23539
H.relabel(c_new)
@@ -23523,8 +23542,8 @@ class by some canonization function `c`. If `G` and `H` are graphs,
23523
23542
else:
23524
23543
return H
23525
23544
23526
- def is_cayley(self, return_group = False, mapping = False,
23527
- generators = False, allow_disconnected = False):
23545
+ def is_cayley(self, return_group= False, mapping= False,
23546
+ generators= False, allow_disconnected= False):
23528
23547
r"""
23529
23548
Check whether the graph is a Cayley graph.
23530
23549
@@ -23629,11 +23648,11 @@ def is_cayley(self, return_group = False, mapping = False,
23629
23648
....: generators = True)
23630
23649
(False, False, False)
23631
23650
"""
23632
- if self.order() == 0 :
23651
+ if not self :
23633
23652
n = return_group + mapping + generators
23634
- if n == 0 :
23653
+ if not n :
23635
23654
return False
23636
- return tuple([False] * (n+ 1))
23655
+ return tuple([False] * (n + 1))
23637
23656
23638
23657
compute_map = mapping or generators
23639
23658
certificate = return_group or compute_map
@@ -23642,7 +23661,7 @@ def is_cayley(self, return_group = False, mapping = False,
23642
23661
if allow_disconnected and self.is_vertex_transitive():
23643
23662
C = self.connected_components_subgraphs()
23644
23663
if certificate:
23645
- c, CG = C[0].is_cayley(return_group = True)
23664
+ c, CG = C[0].is_cayley(return_group= True)
23646
23665
if c:
23647
23666
from sage.groups.perm_gps.permgroup import PermutationGroup
23648
23667
I = [C[0].is_isomorphic(g, certificate=True)[1] for g in C]
@@ -23652,24 +23671,24 @@ def is_cayley(self, return_group = False, mapping = False,
23652
23671
for h in CG.gens()] + \
23653
23672
[[tuple([M[v] for M in I])
23654
23673
for v in C[0].vertices(sort=False)]]
23655
- G = PermutationGroup(gens, domain = self.vertices(sort=False))
23674
+ G = PermutationGroup(gens, domain= self.vertices(sort=False))
23656
23675
else:
23657
- c = C[0].is_cayley(return_group = False)
23658
- elif not self.allows_loops() and not self.allows_multiple_edges() and \
23659
- self.density() > Rational(1)/Rational(2):
23676
+ c = C[0].is_cayley(return_group= False)
23677
+ elif ( not self.allows_loops() and not self.allows_multiple_edges() and
23678
+ self.density() > Rational(1)/Rational(2) ):
23660
23679
if certificate:
23661
- c, G = self.complement().is_cayley(return_group = True,
23662
- allow_disconnected = True)
23680
+ c, G = self.complement().is_cayley(return_group= True,
23681
+ allow_disconnected= True)
23663
23682
else:
23664
- c = self.complement().is_cayley(return_group = False,
23665
- allow_disconnected = True)
23683
+ c = self.complement().is_cayley(return_group= False,
23684
+ allow_disconnected= True)
23666
23685
else:
23667
23686
A = self.automorphism_group()
23668
23687
if certificate:
23669
- G = A.has_regular_subgroup(return_group = True)
23688
+ G = A.has_regular_subgroup(return_group= True)
23670
23689
c = G is not None
23671
23690
else:
23672
- c = A.has_regular_subgroup(return_group = False)
23691
+ c = A.has_regular_subgroup(return_group= False)
23673
23692
if c and compute_map:
23674
23693
v = next(self.vertex_iterator())
23675
23694
map = {(f**-1)(v): f for f in G}
@@ -23912,7 +23931,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
23912
23931
raise ValueError('the parameter alpha must be strictly positive')
23913
23932
23914
23933
n = self.order()
23915
- if n == 0 :
23934
+ if not n :
23916
23935
raise ValueError('graph is empty')
23917
23936
if vertices is None:
23918
23937
vertices = self.vertices(sort=True)
@@ -23930,15 +23949,15 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None):
23930
23949
raise ValueError('the parameter alpha must be less than the reciprocal of the spectral radius of the graph')
23931
23950
23932
23951
In = matrix.identity(n)
23933
- K = (In - alpha * A.transpose()).inverse() - In
23952
+ K = (In - alpha * A.transpose()).inverse() - In
23934
23953
if nonedgesonly:
23935
23954
onesmat = matrix(QQ, n, n, lambda i, j: 1)
23936
23955
Missing = onesmat - A - In
23937
23956
return K.elementwise_product(Missing)
23938
23957
else:
23939
23958
return K
23940
23959
23941
- def katz_centrality(self, alpha , u=None):
23960
+ def katz_centrality(self, alpha, u=None):
23942
23961
r"""
23943
23962
Return the Katz centrality of vertex `u`.
23944
23963
@@ -24118,7 +24137,7 @@ def edge_polytope(self, backend=None):
24118
24137
dim = self.num_verts()
24119
24138
e = identity_matrix(dim).rows()
24120
24139
dic = {v: e[i] for i, v in enumerate(self)}
24121
- vertices = ((dic[i] + dic[j]) for i,j in self.edge_iterator(sort_vertices=False, labels=False))
24140
+ vertices = ((dic[i] + dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False))
24122
24141
parent = Polyhedra(ZZ, dim, backend=backend)
24123
24142
return parent([vertices, [], []], None)
24124
24143
@@ -24249,13 +24268,13 @@ def symmetric_edge_polytope(self, backend=None):
24249
24268
dim = self.num_verts()
24250
24269
e = identity_matrix(dim).rows()
24251
24270
dic = {v: e[i] for i, v in enumerate(self)}
24252
- vertices = chain(((dic[i] - dic[j]) for i,j in self.edge_iterator(sort_vertices=False, labels=False)),
24253
- ((dic[j] - dic[i]) for i,j in self.edge_iterator(sort_vertices=False, labels=False)))
24271
+ vertices = chain(((dic[i] - dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)),
24272
+ ((dic[j] - dic[i]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)))
24254
24273
parent = Polyhedra(ZZ, dim, backend=backend)
24255
24274
return parent([vertices, [], []], None)
24256
24275
24257
24276
24258
- def tachyon_vertex_plot(g, bgcolor=(1,1, 1),
24277
+ def tachyon_vertex_plot(g, bgcolor=(1, 1, 1),
24259
24278
vertex_colors=None,
24260
24279
vertex_size=0.06,
24261
24280
pos3d=None,
@@ -24286,12 +24305,12 @@ def tachyon_vertex_plot(g, bgcolor=(1,1,1),
24286
24305
from math import sqrt
24287
24306
from sage.plot.plot3d.tachyon import Tachyon
24288
24307
24289
- c = [0,0, 0]
24308
+ c = [0, 0, 0]
24290
24309
r = []
24291
24310
verts = list(g)
24292
24311
24293
24312
if vertex_colors is None:
24294
- vertex_colors = {(1,0, 0): verts}
24313
+ vertex_colors = {(1, 0, 0): verts}
24295
24314
try:
24296
24315
for v in verts:
24297
24316
c[0] += pos3d[v][0]
@@ -24324,14 +24343,17 @@ def tachyon_vertex_plot(g, bgcolor=(1,1,1),
24324
24343
i = 0
24325
24344
for color in vertex_colors:
24326
24345
i += 1
24327
- TT.texture('node_color_%d'% i, ambient=0.1, diffuse=0.9,
24346
+ TT.texture('node_color_%d' % i, ambient=0.1, diffuse=0.9,
24328
24347
specular=0.03, opacity=1.0, color=color)
24329
24348
for v in vertex_colors[color]:
24330
- TT.sphere((pos3d[v][0], pos3d[v][1], pos3d[v][2]), vertex_size, 'node_color_%d'% i)
24349
+ TT.sphere((pos3d[v][0], pos3d[v][1], pos3d[v][2]), vertex_size, 'node_color_%d' % i)
24331
24350
24332
24351
return TT, pos3d
24333
24352
24334
- def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None, return_relabeling=False, return_edge_labels=False, inplace=False, ignore_edge_labels=False):
24353
+
24354
+ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None,
24355
+ return_relabeling=False, return_edge_labels=False,
24356
+ inplace=False, ignore_edge_labels=False):
24335
24357
r"""
24336
24358
Helper function for canonical labeling of edge labeled (di)graphs.
24337
24359
@@ -24549,13 +24571,12 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab
24549
24571
24550
24572
# We build the list of distinct edge labels
24551
24573
edge_labels = []
24552
- for _,_, label in G.edge_iterator():
24574
+ for _, _, label in G.edge_iterator():
24553
24575
if label != standard_label and label not in edge_labels:
24554
24576
edge_labels.append(label)
24555
24577
24556
24578
edge_labels = sorted(edge_labels, key=str)
24557
24579
24558
-
24559
24580
# We now add to G, for each edge (u, v, l), a new vertex i in [n..n + m] and
24560
24581
# arcs (u, i, None) and (i, v, None). We record for each distinct label l
24561
24582
# the list of added vertices.
@@ -24571,7 +24592,7 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab
24571
24592
edges = list(G._backend.iterator_edges(G, True))
24572
24593
24573
24594
i = G_order
24574
- for u,v, l in edges:
24595
+ for u, v, l in edges:
24575
24596
if l != standard_label:
24576
24597
for el, part in edge_partition:
24577
24598
if el == l:
@@ -24621,7 +24642,7 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab
24621
24642
24622
24643
else:
24623
24644
# Flatten edge_partition to [list of edges, list of edges, ...]
24624
- edge_partition = [part for _,part in edge_partition]
24645
+ edge_partition = [part for _, part in edge_partition]
24625
24646
24626
24647
new_partition = [part for part in chain(partition, edge_partition) if part]
24627
24648
0 commit comments