From 7c1450bf50613ce68bd4b04f35846451f7db30f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 13 Dec 2025 13:11:58 +0100 Subject: [PATCH 1/2] some annotations and pep8 in generic_graph.py --- src/sage/graphs/generic_graph.py | 113 ++++++++++++++++--------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 917019a392e..0eaf2ae235d 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -972,10 +972,10 @@ def _latex_(self): return self.latex_options().latex() def tikz(self, format=None, edge_labels=None, - color_by_label=False, prog='dot', rankdir='down', - standalone_config=None, usepackage=None, - usetikzlibrary=None, macros=None, - use_sage_preamble=None, **kwds): + color_by_label=False, prog='dot', rankdir='down', + standalone_config=None, usepackage=None, + usetikzlibrary=None, macros=None, + use_sage_preamble=None, **kwds): r""" Return a TikzPicture of the graph. @@ -1133,8 +1133,9 @@ def tikz(self, format=None, edge_labels=None, edge_labels = True self.latex_options().set_options(format=format, - edge_labels=edge_labels, color_by_label=color_by_label, - prog=prog, rankdir=rankdir, **kwds) + edge_labels=edge_labels, + color_by_label=color_by_label, + prog=prog, rankdir=rankdir, **kwds) # by default use sage preamble only for format tkz_graph # because content generated by tkz_graph depends on it @@ -1216,7 +1217,7 @@ def _repr_(self): name = self.name() + ": " + name return name - def is_immutable(self): + def is_immutable(self) -> bool: """ Check whether the graph is immutable. @@ -1659,14 +1660,14 @@ def export_to_file(self, filename, format=None, **kwds): """ import networkx - formats = {"adjlist" : networkx.write_adjlist, - "dot" : networkx.drawing.nx_pydot.write_dot, - "edgelist" : networkx.write_edgelist, - "gexf" : networkx.write_gexf, - "gml" : networkx.write_gml, - "graphml" : networkx.write_graphml, - "multiline_adjlist" : networkx.write_multiline_adjlist, - "pajek" : networkx.write_pajek} + formats = {"adjlist": networkx.write_adjlist, + "dot": networkx.drawing.nx_pydot.write_dot, + "edgelist": networkx.write_edgelist, + "gexf": networkx.write_gexf, + "gml": networkx.write_gml, + "graphml": networkx.write_graphml, + "multiline_adjlist": networkx.write_multiline_adjlist, + "pajek": networkx.write_pajek} if format is None: ext = filename[1 + filename.rfind("."):] @@ -3498,7 +3499,7 @@ def connected(u, v): "the list associated with {}".format(u, v, u, v)) return True - def has_loops(self): + def has_loops(self) -> bool: """ Return whether there are loops in the (di)graph. @@ -3542,7 +3543,7 @@ def has_loops(self): """ return self.allows_loops() and any(self.has_edge(v, v) for v in self) - def allows_loops(self): + def allows_loops(self) -> bool: """ Return whether loops are permitted in the (di)graph. @@ -3586,7 +3587,7 @@ def allows_loops(self): """ return self._backend.loops(None) - def allow_loops(self, new, check=True): + def allow_loops(self, new, check=True) -> None: """ Change whether loops are permitted in the (di)graph. @@ -3748,7 +3749,7 @@ def number_of_loops(self): """ return len(self.loop_edges()) - def loop_vertices(self): + def loop_vertices(self) -> list: """ Return a list of vertices with loops. @@ -3762,7 +3763,7 @@ def loop_vertices(self): return [v for v in self if self.has_edge(v, v)] return [] - def has_multiple_edges(self, to_undirected=False): + def has_multiple_edges(self, to_undirected=False) -> bool: """ Return whether there are multiple edges in the (di)graph. @@ -3854,7 +3855,7 @@ def has_multiple_edges(self, to_undirected=False): s.add(a) return False - def allows_multiple_edges(self): + def allows_multiple_edges(self) -> bool: """ Return whether multiple edges are permitted in the (di)graph. @@ -4221,7 +4222,7 @@ def name(self, new=None): self._name = str(new) - def get_pos(self, dim=2): + def get_pos(self, dim=2) -> dict: """ Return the position dictionary. @@ -6004,7 +6005,7 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, if self.has_multiple_edges() or self.has_loops(): raise NotImplementedError("cannot compute with embeddings of multiple-edged or looped graphs") elif (self.is_directed() and - any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False))): + any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False))): raise NotImplementedError("cannot compute with embeddings of digraphs with pairs of opposite arcs") if on_embedding is not None: @@ -6488,15 +6489,15 @@ def layout_planar(self, set_embedding=False, on_embedding=None, _compute_coordinates(G, tree_nodes) # Delete all the edges added to the graph - #G.delete_edges( extra_edges ) - #self.delete_edges( other_added_edges ) + # G.delete_edges( extra_edges ) + # self.delete_edges( other_added_edges ) if embedding_copy is not None: self._embedding = embedding_copy return G._pos - def is_drawn_free_of_edge_crossings(self): + def is_drawn_free_of_edge_crossings(self) -> bool: """ Check whether the position dictionary for this graph is set and that position dictionary gives a planar embedding. @@ -8944,13 +8945,13 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, # the two in a directed graph (the graph is connected). if (self.order() <= 1 or (s is not None and ( - (s not in self) or - (self._directed and not self.out_degree(s)) or - (not self._directed and not self.degree(s)))) or + (s not in self) or + (self._directed and not self.out_degree(s)) or + (not self._directed and not self.degree(s)))) or (t is not None and ( - (t not in self) or - (self._directed and not self.in_degree(t)) or - (not self._directed and not self.degree(t)))) or + (t not in self) or + (self._directed and not self.in_degree(t)) or + (not self._directed and not self.degree(t)))) or (self._directed and (s is not None) and (t is not None) and not self.shortest_path(s, t))): if self._directed: @@ -9658,7 +9659,7 @@ def weight(label): (vv, uu, self.edge_label(vv, uu))] answer = self.subgraph(edges=edges, immutable=self.is_immutable()) answer.set_pos(self.get_pos()) - answer._name = "TSP from "+self.name() + answer._name = "TSP from " + self.name() return answer elif self.allows_multiple_edges() and len(self.edge_label(uu, vv)) > 1: if maximize: @@ -11818,7 +11819,7 @@ def delete_vertices(self, vertices): self._backend.del_vertices(vertices) - def has_vertex(self, vertex): + def has_vertex(self, vertex) -> bool: """ Check if ``vertex`` is one of the vertices of this graph. @@ -13326,7 +13327,7 @@ def set_edge_label(self, u, v, l): "multiple edges from %s to %s" % (u, v)) self._backend.set_edge_label(u, v, l, self._directed) - def has_edge(self, u, v=None, label=None): + def has_edge(self, u, v=None, label=None) -> bool: r""" Check whether ``(u, v)`` is an edge of the (di)graph. @@ -15292,7 +15293,7 @@ def subgraph_decompositions(self, H, induced=False): from sage.combinat.matrices.dancing_links import dlx_solver edges = list(self.edges(labels=False)) - edge_to_column_id = {edge:i for i, edge in enumerate(edges)} + edge_to_column_id = {edge: i for i, edge in enumerate(edges)} rows = set() for h in self.subgraph_search_iterator(H, induced=induced, return_graphs=True): @@ -19427,9 +19428,9 @@ def breadth_first_search(self, start, ignore_direction=False, if (neighbors is None and not isinstance(start, list) and distance is None and hasattr(self._backend, "breadth_first_search")): yield from self._backend.breadth_first_search( - start, ignore_direction=ignore_direction, - report_distance=report_distance, edges=edges, - forbidden_vertices=forbidden_vertices) + start, ignore_direction=ignore_direction, + report_distance=report_distance, edges=edges, + forbidden_vertices=forbidden_vertices) else: if neighbors is None: if not self._directed or ignore_direction: @@ -22000,7 +22001,7 @@ def layout_tutte(self, external_face=None, external_face_pos=None, **options): M[i, j] = -1 M[i, i] = len(nv) - sol = M.pseudoinverse()*b + sol = M.pseudoinverse() * b return dict(zip(self, sol)) def _layout_bounding_box(self, pos): @@ -22125,11 +22126,11 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, from math import cos, pi, sin for i, v in enumerate(vertices): - i += shift + theta = 2 * (i + shift) * pi / n # We round cos and sin to avoid results like 1.2246467991473532e-16 # when asking for sin(pi) - v_x = c_x + radius * round(cos(angle + 2*i*pi / n), 10) - v_y = c_y + radius * round(sin(angle + 2*i*pi / n), 10) + v_x = c_x + radius * round(cos(angle + theta), 10) + v_y = c_y + radius * round(sin(angle + theta), 10) pos[v] = (v_x, v_y) if return_dict: @@ -22857,14 +22858,14 @@ def plot3d(self, bgcolor=(1, 1, 1), R = rainbow(l) vertex_colors = {R[i]: partition[i] for i in range(l)} else: - vertex_colors = {(1, 0, 0) : list(self)} + vertex_colors = {(1, 0, 0): list(self)} if color_by_label: if edge_colors is None: # do the coloring edge_colors = self._color_by_label(format=color_by_label) elif edge_colors is None: - edge_colors = {(0, 0, 0) : self.edges(sort=False)} + edge_colors = {(0, 0, 0): self.edges(sort=False)} # by default turn off the frame if 'frame' not in kwds: @@ -22907,7 +22908,7 @@ def plot3d(self, bgcolor=(1, 1, 1), edge_colors = self._color_by_label(format=color_by_label) if edge_colors is None: - edge_colors = {(0, 0, 0) : self.edges(sort=False)} + edge_colors = {(0, 0, 0): self.edges(sort=False)} i = 0 @@ -22916,7 +22917,7 @@ def plot3d(self, bgcolor=(1, 1, 1), TT.texture('edge_color_%d' % i, ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=color) if self._directed: - for u,v,l in edge_colors[color]: + for u, v, l in edge_colors[color]: TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size, 'edge_color_%d' % i) @@ -23606,7 +23607,7 @@ def graphviz_string(self, **options): color_by_edge = {} for color in options['edge_colors'].keys(): for edge in options['edge_colors'][color]: - assert isinstance(edge, (list, tuple)) and len(edge) >= 2 and len(edge) <= 3,\ + assert isinstance(edge, (list, tuple)) and len(edge) >= 2 and len(edge) <= 3, \ "%s is not a valid format for edge" % (edge) u = edge[0] v = edge[1] @@ -23668,10 +23669,10 @@ def graphviz_string(self, **options): 'backward': False, 'dot': None, 'edge_string': default_edge_string, - 'color' : default_color, - 'label' : label, + 'color': default_color, + 'label': label, 'label_style': options['labels'] if options['edge_labels'] else None - } + } for f in edge_option_functions: edge_options.update(f((u, v, label))) @@ -25047,8 +25048,10 @@ def is_vertex_transitive(self, partition=None, verbosity=0, return False new_partition = self.automorphism_group(partition, - verbosity=verbosity, edge_labels=edge_labels, - order=False, return_group=False, orbits=True) + verbosity=verbosity, + edge_labels=edge_labels, + order=False, + return_group=False, orbits=True) return (len(partition) == len(new_partition)) @@ -25904,7 +25907,7 @@ def is_cayley(self, return_group=False, mapping=False, else: c = C[0].is_cayley(return_group=False) elif (not self.allows_loops() and not self.allows_multiple_edges() and - self.density() > Rational(1)/Rational(2)): + self.density() > Rational(1) / Rational(2)): if certificate: c, G = self.complement().is_cayley(return_group=True, allow_disconnected=True) @@ -26201,7 +26204,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): if spectral_radius == 0: raise ValueError('the spectral radius of the graph must not be zero') - if alpha >= 1/spectral_radius: + if alpha >= 1 / spectral_radius: raise ValueError('the parameter alpha must be less than the reciprocal of the spectral radius of the graph') In = matrix.identity(n) From 8d58d5bcd0de163ee5c087b8320f5537b7093580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 13 Dec 2025 13:15:32 +0100 Subject: [PATCH 2/2] little code detail --- src/sage/graphs/generic_graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 0eaf2ae235d..25306a29f22 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -22126,11 +22126,11 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, from math import cos, pi, sin for i, v in enumerate(vertices): - theta = 2 * (i + shift) * pi / n + theta = angle + 2 * (i + shift) * pi / n # We round cos and sin to avoid results like 1.2246467991473532e-16 # when asking for sin(pi) - v_x = c_x + radius * round(cos(angle + theta), 10) - v_y = c_y + radius * round(sin(angle + theta), 10) + v_x = c_x + radius * round(cos(theta), 10) + v_y = c_y + radius * round(sin(theta), 10) pos[v] = (v_x, v_y) if return_dict: