From 69ab5abf24d534eb4cf3cf195d73a364ecb5b5b0 Mon Sep 17 00:00:00 2001 From: Sagar-math Date: Mon, 16 Sep 2024 15:58:28 +0530 Subject: [PATCH 001/108] Returns the Tutte symmetric function of a graph `G`. Added references accordingly. --- src/doc/en/reference/references/index.rst | 9 +++ src/sage/graphs/graph.py | 84 +++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index aaaf7a410c0..92230f5d7d4 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1982,6 +1982,10 @@ REFERENCES: .. [CS2018] Craig Costello and Benjamin Smith: Montgomery curves and their arithmetic. J. Cryptogr. Eng. 8 (2018), 227-240. +.. [CS2022] \Logan Crew, and Sophie Spirkl. *Modular relations of the Tutte symmetric function*, + Journal of Combinatorial Theory, Series A, Volume 187, 2022, 105572, + :doi:`10.1016/j.jcta.2021.105572.` + .. [CST2010] Tullio Ceccherini-Silberstein, Fabio Scarabotti, Filippo Tolli. *Representation Theory of the Symmetric Groups: The @@ -6101,6 +6105,11 @@ REFERENCES: of the chromatic polynomial of a graph*, Adv. Math., ***111*** no.1 (1995), 166-194. :doi:`10.1006/aima.1995.1020`. +.. [Sta1998] \R. P. Stanley, *Graph colorings and related symmetric functions: + ideas and applications A description of results, interesting applications, + & notable open problems*, Discrete Mathematics, 193, no.1-3, (1998), + 267-286. :doi:`10.1016/S0012-365X(98)00146-0`. + .. [Sta2002] Richard P. Stanley, *The rank and minimal border strip decompositions of a skew partition*, diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 134fe000df9..8666419cea1 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4122,6 +4122,90 @@ def asc(sigma): ret += M.term(sigma.to_composition(), t**asc(sigma)) return ret + @doc_index("Coloring") + def tutte_symmetric_function(self, R=None, t=None): + r""" + Return the Tutte symmetric function of ``self``. + + Let `G` be a graph. The Tutte symmetric function `XB_G` of the graph `G` was introduced in [Sta1998]_. We present + the equivalent definition given in [CS2022]_. + + .. MATH:: + + XB_G = \sum_{\pi \vdash V} (1+t)^{e(\pi)} \tilde{m}_{\lambda(\pi)}, + + where the sum ranges over all set-partitions `\pi` of the vertex set `V`, `\lambda(pi)` is the + partition determined by the sizes of the blocks of `\pi`, and `e(pi)` is the number of edges whose endpoints + lie in the same block of `\pi`. In particular, the coefficients of `XB_G` + when expanded in terms of augmented monomial symmetric functions are polynomials in `t` with + non-negative integer coefficients. + + For an integer partition `\lambda = 1^{r_1}2^{r_2}\cdots` expressed in the exponential notation, the augmented monomial symmetric function is defined as + + .. MATH:: + + \tilde{m}_{\lambda} = \(\prod_{i} r_i!\) m_{\lambda}. + + + INPUT: + + - ``R`` -- (optional) the base ring for the symmetric functions; + this uses `\ZZ` by default + + - ``t`` -- (optional) the parameter `t`; uses the variable `t` in + `\ZZ[t]` by default + + EXAMPLES: + + sage: p = SymmetricFunctions(ZZ).p() # needs sage.combinat sage.modules + sage: G = Graph([[1,2],[2,3],[3,4],[4,1],[1,3]]) + sage: XB_G = G.tutte_symmetric_function(); XB_G # needs sage.combinat sage.modules + 24*m[1, 1, 1, 1] + (10*t+12)*m[2, 1, 1] + (4*t^2+10*t+6)*m[2, 2] + (2*t^3+8*t^2+10*t+4)*m[3, 1] + (t^5+5*t^4+10*t^3+10*t^2+5*t+1)*m[4] + sage: p(XB_G) # needs sage.combinat sage.modules + p[1, 1, 1, 1] + 5*t*p[2, 1, 1] + 2*t^2*p[2, 2] + (2*t^3+8*t^2)*p[3, 1] + (t^5+5*t^4+8*t^3)*p[4] + + Graphs are allowed to have multiedges and loops:: + + sage: G = Graph([[1,2],[2,3],[2,3]], multiedges = True) + sage: XB_G = G.tutte_symmetric_function(); XB_G # needs sage.combinat sage.modules + 6*m[1, 1, 1] + (t^2+3*t+3)*m[2, 1] + (t^3+3*t^2+3*t+1)*m[3] + + + We check that at `t = -1`, we recover the usual chromatic symmetric function:: + + sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,5]], multiedges=True) + sage: XB_G = G.tutte_symmetric_function(t=-1); XB_G # needs sage.combinat sage.modules + 120*m[1, 1, 1, 1, 1] + 36*m[2, 1, 1, 1] + 12*m[2, 2, 1] + 2*m[3, 1, 1] + m[3, 2] + sage: X_G = G.chromatic_symmetric_function(); X_G # needs sage.combinat sage.modules + p[1, 1, 1, 1, 1] - 4*p[2, 1, 1, 1] + 3*p[2, 2, 1] + 3*p[3, 1, 1] - 2*p[3, 2] - 2*p[4, 1] + p[5] + sage: XB_G == X_G # needs sage.combinat sage.modules + True + + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.set_partition import SetPartitions + from sage.misc.misc_c import prod + from sage.arith.misc import factorial + if t is None: + t = ZZ['t'].gen() + if R is None: + R = t.parent() + m = SymmetricFunctions(R).m() + ret = m.zero() + V = self.vertices() + E = list(self.edges(labels=False)) + + def mono(pi): + arcs = 0 + for s in pi: + for u in s: + arcs += sum(E.count((u, v)) for v in s if self.has_edge(u, v)) + return arcs + + for pi in SetPartitions(V): + ret += prod([factorial(i) for i in pi.to_partition().to_exp()])*m[pi.to_partition()]*(1+t)**mono(pi) + return ret + @doc_index("Leftovers") def matching(self, value_only=False, algorithm='Edmonds', use_edge_labels=False, solver=None, verbose=0, From 872c66e6b68b4e4341924ff2ad70d2aa96dc1fbb Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 17 Sep 2024 15:48:12 +0200 Subject: [PATCH 002/108] refresh the branch --- src/sage/graphs/connectivity.pyx | 205 ++++++++++++++++++++++--------- src/sage/graphs/generic_graph.py | 4 +- 2 files changed, 147 insertions(+), 62 deletions(-) diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index ba515980093..dc5e4db5c25 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -26,6 +26,7 @@ Here is what the module can do: :meth:`is_cut_edge` | Check whether the input edge is a cut-edge or a bridge. :meth:`is_edge_cut` | Check whether the input edges form an edge cut. :meth:`is_cut_vertex` | Check whether the input vertex is a cut-vertex. + :meth:`is_vertex_cut` | Check whether the input vertices form a vertex cut. :meth:`edge_connectivity` | Return the edge connectivity of the graph. :meth:`vertex_connectivity` | Return the vertex connectivity of the graph. @@ -971,58 +972,64 @@ def is_cut_edge(G, u, v=None, label=None): return sol -def is_cut_vertex(G, u, weak=False): +def is_vertex_cut(G, cut, weak=False): r""" - Check whether the input vertex is a cut-vertex. + Check whether the input vertices form a vertex cut. - A vertex is a cut-vertex if its removal from the (di)graph increases the - number of (strongly) connected components. Isolated vertices or leafs are - not cut-vertices. This function works with simple graphs as well as graphs - with loops and multiple edges. + A set of vertices is a vertex cut if its removal from the (di)graph + increases the number of (strongly) connected components. This function works + with simple graphs as well as graphs with loops and multiple edges. INPUT: - ``G`` -- a Sage (Di)Graph - - ``u`` -- a vertex + - ``cut`` -- a set of vertices - ``weak`` -- boolean (default: ``False``); whether the connectivity of directed graphs is to be taken in the weak sense, that is ignoring edges orientations - OUTPUT: - - Return ``True`` if ``u`` is a cut-vertex, and ``False`` otherwise. - EXAMPLES: - Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a - pending edge:: + Giving a cycle graph of order 4:: - sage: from sage.graphs.connectivity import is_cut_vertex - sage: G = graphs.LollipopGraph(4, 2) - sage: is_cut_vertex(G, 0) + sage: from sage.graphs.connectivity import is_vertex_cut + sage: G = graphs.CycleGraph(4) + sage: is_vertex_cut(G, [0, 1]) False - sage: is_cut_vertex(G, 3) + sage: is_vertex_cut(G, [0, 2]) True - sage: G.is_cut_vertex(3) + + Giving a disconnected graph:: + + sage: from sage.graphs.connectivity import is_vertex_cut + sage: G = graphs.CycleGraph(4) * 2 + sage: G.connected_components() + [[0, 1, 2, 3], [4, 5, 6, 7]] + sage: is_vertex_cut(G, [0, 2]) + True + sage: is_vertex_cut(G, [4, 6]) + True + sage: is_vertex_cut(G, [0, 6]) + False + sage: is_vertex_cut(G, [0, 4, 6]) True Comparing the weak and strong connectivity of a digraph:: - sage: from sage.graphs.connectivity import is_strongly_connected sage: D = digraphs.Circuit(6) - sage: is_strongly_connected(D) + sage: D.is_strongly_connected() True - sage: is_cut_vertex(D, 2) + sage: is_vertex_cut(D, [2]) True - sage: is_cut_vertex(D, 2, weak=True) + sage: is_vertex_cut(D, [2], weak=True) False Giving a vertex that is not in the graph:: sage: G = graphs.CompleteGraph(4) - sage: is_cut_vertex(G, 7) + sage: is_vertex_cut(G, [7]) Traceback (most recent call last): ... ValueError: vertex (7) is not a vertex of the graph @@ -1031,7 +1038,7 @@ def is_cut_vertex(G, u, weak=False): If ``G`` is not a Sage graph, an error is raised:: - sage: is_cut_vertex('I am not a graph', 0) + sage: is_vertex_cut('I am not a graph', [0]) Traceback (most recent call last): ... TypeError: the input must be a Sage graph @@ -1040,68 +1047,144 @@ def is_cut_vertex(G, u, weak=False): if not isinstance(G, GenericGraph): raise TypeError("the input must be a Sage graph") - if u not in G: - raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(u))) - - # Initialization - cdef set CC - cdef list neighbors_func - if not G.is_directed() or weak: - # Weak connectivity + cdef set cutset = set(cut) + for u in cutset: + if u not in G: + raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(u))) - if G.degree(u) < 2: - # An isolated or a leaf vertex is not a cut vertex - return False - - neighbors_func = [G.neighbor_iterator] - start = next(G.neighbor_iterator(u)) - CC = set(G) + if len(cutset) >= G.order() - 1: + # A vertex cut must be of size at most n - 2 + return False + # We deal with graphs with multiple (strongly) connected components + cdef list CC + if G.is_directed() and not weak: + CC = G.strongly_connected_components() else: - # Strong connectivity for digraphs - - if not G.out_degree(u) or not G.in_degree(u): - # A vertex without in or out neighbors is not a cut vertex - return False + CC = G.connected_components(sort=False) + if len(CC) > 1: + for comp in CC: + subcut = cutset.intersection(comp) + if subcut and is_vertex_cut(G.subgraph(comp), subcut, weak=weak): + return True + return False - # We consider only the strongly connected component containing u - CC = set(strongly_connected_component_containing_vertex(G, u)) + cdef list boundary = G.vertex_boundary(cutset) + if not boundary: + # We need at least 1 vertex in the boundary of the cut + return False - # We perform two DFS starting from an out neighbor of u and avoiding - # u. The first DFS follows the edges directions, and the second is - # in the reverse order. If both allow to reach all neighbors of u, - # then u is not a cut vertex - neighbors_func = [G.neighbor_out_iterator, G.neighbor_in_iterator] - start = next(G.neighbor_out_iterator(u)) + cdef list cases = [(G.neighbor_iterator, boundary)] + if not weak and G.is_directed(): + # Strong connectivity for digraphs. + # We perform two DFS starting from an out neighbor of cut and avoiding + # cut. The first DFS follows the edges directions, and the second is + # in the reverse order. If both allow to reach all neighbors of cut, + # then it is not a vertex cut. + # We set data for the reverse order + in_boundary = set() + for u in cutset: + in_boundary.update(G.neighbor_in_iterator(u)) + in_boundary.difference_update(cutset) + if not in_boundary: + return False + cases.append((G.neighbor_in_iterator, list(in_boundary))) - CC.discard(u) - CC.discard(start) cdef list queue cdef set seen cdef set targets + start = boundary[0] - for neighbors in neighbors_func: + for neighbors, this_boundary in cases: - # We perform a DFS starting from a neighbor of u and avoiding u + # We perform a DFS starting from start and avoiding cut queue = [start] - seen = set(queue) - targets = CC.intersection(G.neighbor_iterator(u)) + seen = set(cutset) + seen.add(start) + targets = set(this_boundary) targets.discard(start) - while queue and targets: + while queue: v = queue.pop() for w in neighbors(v): - if w not in seen and w in CC: + if w not in seen: seen.add(w) queue.append(w) targets.discard(w) - # If some neighbors cannot be reached, u is a cut vertex. + # If some neighbors cannot be reached, we have a vertex cut if targets: return True return False +def is_cut_vertex(G, u, weak=False): + r""" + Check whether the input vertex is a cut-vertex. + + A vertex is a cut-vertex if its removal from the (di)graph increases the + number of (strongly) connected components. Isolated vertices or leaves are + not cut-vertices. This function works with simple graphs as well as graphs + with loops and multiple edges. + + INPUT: + + - ``G`` -- a Sage (Di)Graph + + - ``u`` -- a vertex + + - ``weak`` -- boolean (default: ``False``); whether the connectivity of + directed graphs is to be taken in the weak sense, that is ignoring edges + orientations + + OUTPUT: + + Return ``True`` if ``u`` is a cut-vertex, and ``False`` otherwise. + + EXAMPLES: + + Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a + pending edge:: + + sage: from sage.graphs.connectivity import is_cut_vertex + sage: G = graphs.LollipopGraph(4, 2) + sage: is_cut_vertex(G, 0) + False + sage: is_cut_vertex(G, 3) + True + sage: G.is_cut_vertex(3) + True + + Comparing the weak and strong connectivity of a digraph:: + + sage: D = digraphs.Circuit(6) + sage: D.is_strongly_connected() + True + sage: is_cut_vertex(D, 2) + True + sage: is_cut_vertex(D, 2, weak=True) + False + + Giving a vertex that is not in the graph:: + + sage: G = graphs.CompleteGraph(4) + sage: is_cut_vertex(G, 7) + Traceback (most recent call last): + ... + ValueError: vertex (7) is not a vertex of the graph + + TESTS: + + If ``G`` is not a Sage graph, an error is raised:: + + sage: is_cut_vertex('I am not a graph', 0) + Traceback (most recent call last): + ... + TypeError: the input must be a Sage graph + """ + return is_vertex_cut(G, [u], weak=weak) + + def edge_connectivity(G, value_only=True, implementation=None, diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6ed8446ae1c..5684ebf1e3d 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -245,7 +245,8 @@ :meth:`~GenericGraph.blocks_and_cuts_tree` | Compute the blocks-and-cuts tree of the graph. :meth:`~GenericGraph.is_cut_edge` | Check whether the input edge is a cut-edge or a bridge. :meth:`~GenericGraph.`is_edge_cut` | Check whether the input edges form an edge cut. - :meth:`~GenericGraph.is_cut_vertex` | Return ``True`` if the input vertex is a cut-vertex. + :meth:`~GenericGraph.is_cut_vertex` | Check whether the input vertex is a cut-vertex. + :meth:`~GenericGraph.is_vertex_cut` | Check whether the input vertices form a vertex cut. :meth:`~GenericGraph.edge_cut` | Return a minimum edge cut between vertices `s` and `t` :meth:`~GenericGraph.vertex_cut` | Return a minimum vertex cut between non-adjacent vertices `s` and `t` :meth:`~GenericGraph.flow` | Return a maximum flow in the graph from ``x`` to ``y`` @@ -25003,6 +25004,7 @@ def is_self_complementary(self): from sage.graphs.connectivity import is_cut_edge from sage.graphs.connectivity import is_edge_cut from sage.graphs.connectivity import is_cut_vertex + from sage.graphs.connectivity import is_vertex_cut from sage.graphs.connectivity import edge_connectivity from sage.graphs.connectivity import vertex_connectivity from sage.graphs.distances_all_pairs import szeged_index From c999704947620c0a7724631830697c5b054684cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 31 Jul 2024 22:10:49 +0200 Subject: [PATCH 003/108] work on Simon two-descent --- .../elliptic_curves/ell_number_field.py | 9 -- .../elliptic_curves/ell_rational_field.py | 69 ++++++------ src/sage/schemes/elliptic_curves/gp_simon.py | 103 ++++++++---------- 3 files changed, 75 insertions(+), 106 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 8ccdbcd452d..eea2e5cc243 100755 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -250,15 +250,6 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, listpoints = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] (1, 1, [(1/2*a + 3/2 : -a - 2 : 1)]) - sage: v = E.simon_two_descent(verbose=2) - K = bnfinit(y^2 + 7); - a = Mod(y,K.pol); - bnfellrank(K, [0, 0, 0, 1, a], [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7)]]); - ... - v = [1, 1, [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7)]]] - sage: v - (1, 1, [(1/2*a + 3/2 : -a - 2 : 1)]) - A curve with 2-torsion:: sage: K. = NumberField(x^2 + 7) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 993c25f38db..f3c397cd042 100755 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -1837,6 +1837,10 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, ... DeprecationWarning: Use E.rank(algorithm="pari") instead, as this script has been ported over to pari. See https://github.com/sagemath/sage/issues/35621 for details. + doctest:warning + ... + DeprecationWarning: please use the 2-descent algorithm over QQ inside pari + See https://github.com/sagemath/sage/issues/38461 for details. (0, 0, []) sage: E = EllipticCurve('37a1') sage: E.simon_two_descent() @@ -1937,7 +1941,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, return rank_low_bd, two_selmer_rank, pts - two_descent_simon = simon_two_descent + two_descent_simon = simon_two_descent # deprecated in #35621 def three_selmer_rank(self, algorithm='UseSUnits'): r""" @@ -2388,21 +2392,9 @@ def _compute_gens(self, proof, TESTS:: sage: P = E.lift_x(611429153205013185025/9492121848205441) - sage: set(E.gens(use_database=False, algorithm='pari',pari_effort=4)) <= set([P+T for T - ....: in E.torsion_points()] + [-P+T for T in E.torsion_points()]) - True - - sage: E = EllipticCurve([-157^2,0]) - sage: E.gens(use_database=False, algorithm='pari') - Traceback (most recent call last): - ... - RuntimeError: generators could not be determined. So far we found []. Hint: increase pari_effort. - sage: ge = E.gens(use_database=False, algorithm='pari',pari_effort=10) - sage: ge #random - [(-166136231668185267540804/2825630694251145858025 : 167661624456834335404812111469782006/150201095200135518108761470235125 : 1)] - sage: P = E.lift_x(-166136231668185267540804/2825630694251145858025) - sage: set(E.gens(use_database=False, algorithm='pari',pari_effort=4)) <= set([P+T for T - ....: in E.torsion_points()] + [-P+T for T in E.torsion_points()]) + sage: ge = set(E.gens(use_database=False, algorithm='pari',pari_effort=4)) + sage: ge <= set([P+T for T in E.torsion_points()] + ....: + [-P+T for T in E.torsion_points()]) True """ # If the optional extended database is installed and an @@ -6209,10 +6201,11 @@ def point_preprocessing(free,tor): e1,e2,e3 = ei if r >= 1: #preprocessing of mw_base only necessary if rank > 0 mw_base = point_preprocessing(mw_base, tors_points) - #at most one point in E^{egg} + # at most one point in E^{egg} - elif disc < 0: # one real component => 1 root in RR (=: e3), - # 2 roots in C (e1,e2) + elif disc < 0: + # one real component => 1 root in RR (=: e3), + # 2 roots in C (e1,e2) roots = pol.roots(C,multiplicities=False) e3 = pol.roots(R,multiplicities=False)[0] roots.remove(e3) @@ -6695,16 +6688,16 @@ def test_with_T(R): for T in tors_points: test(R+T) - # For small rank and small H_q perform simple search + # For small rank and small H_q perform simple search if r == 1 and N <= 10: for P in multiples(mw_base[0],N+1): test_with_T(P) return xs - # explicit computation and testing linear combinations - # ni loops through all tuples (n_1,...,n_r) with |n_i| <= N - # stops when (0,0,...,0) is reached because after that, only inverse points of - # previously tested points would be tested + # explicit computation and testing linear combinations + # ni loops through all tuples (n_1,...,n_r) with |n_i| <= N + # stops when (0,0,...,0) is reached because after that, only inverse points of + # previously tested points would be tested E0 = E(0) ni = [-N for i in range(r)] @@ -6857,13 +6850,14 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): prec *= 2 RR = RealField(prec) ei = pol.roots(RR,multiplicities=False) - e1,e2,e3 = ei - elif disc < 0: # one real component => 1 root in RR (=: e3), - # 2 roots in C (e1,e2) + e1, e2, e3 = ei + elif disc < 0: + # one real component => 1 root in RR (=: e3), + # 2 roots in C (e1,e2) roots = pol.roots(C,multiplicities=False) e3 = pol.roots(R,multiplicities=False)[0] roots.remove(e3) - e1,e2 = roots + e1, e2 = roots len_tors = len(tors_points) n = r + 1 @@ -6896,10 +6890,10 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): if verbose: print('k1,k2,k3,k4', k1, k2, k3, k4) sys.stdout.flush() - #H_q -> [PZGH]:N_0 (due to consistency to integral_points()) + # H_q -> [PZGH]:N_0 (due to consistency to integral_points()) H_q = R(((k1/2+k2)/lamda).sqrt()) - #computation of logs + # computation of logs mw_base_log = [(pts.elliptic_logarithm().abs())*(len_tors/w1) for pts in mw_base] mw_base_p_log = [] beta = [] @@ -6909,7 +6903,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): Np = E.Np(p) cp = E.tamagawa_exponent(p) mp_temp = Z(len_tors).lcm(cp*Np) - mp.append(mp_temp) #only necessary because of verbose below + mp.append(mp_temp) # only necessary because of verbose below p_prec = 30+E.discriminant().valuation(p) p_prec_ok = False while not p_prec_ok: @@ -6920,7 +6914,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): p_prec_ok = True except ValueError: p_prec *= 2 - #reorder mw_base_p: last value has minimal valuation at p + # reorder mw_base_p: last value has minimal valuation at p mw_base_p_log_val = [mw_base_p_log[tmp][i].valuation() for i in range(r)] if verbose: print("mw_base_p_log_val = ",mw_base_p_log_val) @@ -6930,7 +6924,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): print("min_psi = ", min_psi) mw_base_p_log[tmp].remove(min_psi) mw_base_p_log[tmp].append(min_psi) - #beta needed for reduction at p later on + # beta needed for reduction at p later on try: beta.append([-mw_base_p_log[tmp][j]/min_psi for j in range(r)]) except ValueError: @@ -6945,7 +6939,8 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): print('mw_base_p_log', mw_base_p_log) sys.stdout.flush() - #constants in reduction (not needed to be computed every reduction step) + # constants in reduction + # (not needed to be computed every reduction step) k5 = R((2*len_tors)/(3*w1)) k6 = R((k2/len_S).exp()) k7 = R(lamda/len_S) @@ -6956,20 +6951,20 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): break_cond = 0 M = MatrixSpace(Z,n) - #Reduction of initial bound + # Reduction of initial bound if verbose: print('initial bound', H_q) sys.stdout.flush() while break_cond < 0.9: - #reduction at infinity + # reduction at infinity bound_list = [] c = R((H_q**n)*100) m = copy(M.identity_matrix()) for i in range(r): m[i, r] = R(c*mw_base_log[i]).round() m[r,r] = max(Z(1), R(c*w1).round()) - #LLL - implemented in sage - operates on rows not on columns + # LLL - implemented in sage - operates on rows not on columns m_LLL = m.LLL() m_gram = m_LLL.gram_schmidt()[0] b1_norm = R(m_LLL.row(0).norm()) diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index 729380dccf1..6be377e2f74 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -16,33 +16,20 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from pathlib import Path -from sage.structure.parent_gens import localvars +from cypari2.handle_error import PariError -from sage.interfaces.gp import Gp -from sage.misc.sage_eval import sage_eval +from sage.env import SAGE_EXTCODE +from sage.libs.pari import pari from sage.misc.randstate import current_randstate +from sage.misc.superseded import deprecation from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ +from sage.structure.parent_gens import localvars -gp = None - - -def init(): - """ - Function to initialize the gp process - """ - global gp - if gp is None: - import os - from sage.env import DOT_SAGE - logfile = os.path.join(DOT_SAGE, 'gp-simon.log') - gp = Gp(script_subdirectory='simon', logfile=logfile) - gp.read("ellQ.gp") - gp.read("ell.gp") - gp.read("qfsolve.gp") - gp.read("resultant3.gp") +simon_dir = Path(SAGE_EXTCODE) / 'pari' / 'simon' def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, @@ -59,6 +46,9 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, sage: import sage.schemes.elliptic_curves.gp_simon sage: E = EllipticCurve('389a1') sage: sage.schemes.elliptic_curves.gp_simon.simon_two_descent(E) + doctest:warning...: + DeprecationWarning: please use the 2-descent algorithm over QQ inside pari + See https://github.com/sagemath/sage/issues/38461 for details. (2, 2, [(5/4 : 5/8 : 1), (-3/4 : 7/8 : 1)]) TESTS:: @@ -94,37 +84,38 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, sage: E.simon_two_descent() # long time (0, 2, []) """ - init() + pari.read(simon_dir / "ellQ.gp") + pari.read(simon_dir / "ell.gp") + pari.read(simon_dir / "qfsolve.gp") + pari.read(simon_dir / "resultant3.gp") - current_randstate().set_seed_gp(gp) + current_randstate().set_seed_pari() K = E.base_ring() K_orig = K + E_orig = E + # The following is to correct the bug at #5204: the gp script # fails when K is a number field whose generator is called 'x'. # It also deals with relative number fields. - E_orig = E + if K is not QQ: K = K_orig.absolute_field('a') + y = K.gen() from_K, to_K = K.structure() E = E_orig.change_ring(to_K) - known_points = [P.change_ring(to_K) for P in known_points] - # Simon's program requires that this name be y. with localvars(K.polynomial().parent(), 'y'): - gp.eval("K = bnfinit(%s);" % K.polynomial()) - if verbose >= 2: - print("K = bnfinit(%s);" % K.polynomial()) - gp.eval("%s = Mod(y,K.pol);" % K.gen()) - if verbose >= 2: - print("%s = Mod(y,K.pol);" % K.gen()) + # Simon's program requires that this name be y. + K_pari = pari.bnfinit(K.polynomial()) + known_points = [P.change_ring(to_K) for P in known_points] else: + deprecation(38461, "please use the 2-descent algorithm over QQ inside pari") from_K = lambda x: x - to_K = lambda x: x - # The block below mimics the defaults in Simon's scripts, and needs to be changed - # when these are updated. + # The block below mimics the defaults in Simon's scripts. + # They need to be changed when these are updated. if K is QQ: - cmd = 'ellQ_ellrank(%s, %s);' % (list(E.ainvs()), [P.__pari__() for P in known_points]) + over_QQ = True if lim1 is None: lim1 = 5 if lim3 is None: @@ -132,7 +123,7 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, if limtriv is None: limtriv = 3 else: - cmd = 'bnfellrank(K, %s, %s);' % (list(E.ainvs()), [P.__pari__() for P in known_points]) + over_QQ = False if lim1 is None: lim1 = 2 if lim3 is None: @@ -140,29 +131,21 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, if limtriv is None: limtriv = 2 - gp('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;' % ( - verbose, lim1, lim3, limtriv, maxprob, limbigprime)) - - if verbose >= 2: - print(cmd) - s = gp.eval('ans=%s;' % cmd) - if s.find(" *** ") != -1: - raise RuntimeError("\n%s\nAn error occurred while running Simon's 2-descent program" % s) - if verbose > 0: - print(s) - v = gp.eval('ans') - if v == 'ans': # then the call to ellQ_ellrank() or bnfellrank() failed - raise RuntimeError("An error occurred while running Simon's 2-descent program") - if verbose >= 2: - print("v = %s" % v) - - # pari represents field elements as Mod(poly, defining-poly) - # so this function will return the respective elements of K - def _gp_mod(*args): - return args[0] - ans = sage_eval(v, {'Mod': _gp_mod, 'y': K.gen(0)}) - lower = ZZ(ans[0]) - upper = ZZ(ans[1]) - points = [E_orig([from_K(c) for c in list(P)]) for P in ans[2]] + pari('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;' % ( + verbose, lim1, lim3, limtriv, maxprob, limbigprime)) + + try: + if over_QQ: + ans = pari("ellQ_ellrank")(E, known_points) + else: + ans = pari("bnfellrank")(K_pari, E, known_points) + except PariError as err: + raise RuntimeError("an error occurred while running Simon's 2-descent program") from err + + loc = {} if over_QQ else {'y': y} + lower, upper, pts = ans.sage(locals=loc) + lower = ZZ(lower) + upper = ZZ(upper) + points = [E_orig([from_K(c) for c in P]) for P in pts] points = [P for P in points if P.has_infinite_order()] return lower, upper, points From 19d65ea33ef0e99bbe47a262bf5cb3905b85bd3c Mon Sep 17 00:00:00 2001 From: Sagar-math Date: Thu, 19 Sep 2024 14:19:54 +0530 Subject: [PATCH 004/108] incorporated changes suggested by dcoudert --- src/sage/graphs/graph.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 8666419cea1..3a8c12f1756 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4186,6 +4186,8 @@ def tutte_symmetric_function(self, R=None, t=None): from sage.combinat.set_partition import SetPartitions from sage.misc.misc_c import prod from sage.arith.misc import factorial + from collections import Counter + if t is None: t = ZZ['t'].gen() if R is None: @@ -4194,16 +4196,18 @@ def tutte_symmetric_function(self, R=None, t=None): ret = m.zero() V = self.vertices() E = list(self.edges(labels=False)) - + M = Counter(E) + fact = [factorial(i) for i in range(len(V)+1)] def mono(pi): arcs = 0 for s in pi: for u in s: - arcs += sum(E.count((u, v)) for v in s if self.has_edge(u, v)) + arcs += sum(M[(u, v)] for v in s if self.has_edge(u, v)) return arcs for pi in SetPartitions(V): - ret += prod([factorial(i) for i in pi.to_partition().to_exp()])*m[pi.to_partition()]*(1+t)**mono(pi) + pa = pi.to_partition() + ret += prod([fact[i] for i in pa.to_exp()])*m[pa]*(1+t)**mono(pi) return ret @doc_index("Leftovers") From c3dec8d71409d32001f4f499e84ee96fcd793b20 Mon Sep 17 00:00:00 2001 From: Sagar-math Date: Thu, 19 Sep 2024 14:26:57 +0530 Subject: [PATCH 005/108] incorporated changes following pycodestyle-minimal --- src/sage/graphs/graph.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 3a8c12f1756..6825b452f09 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4198,6 +4198,7 @@ def tutte_symmetric_function(self, R=None, t=None): E = list(self.edges(labels=False)) M = Counter(E) fact = [factorial(i) for i in range(len(V)+1)] + def mono(pi): arcs = 0 for s in pi: From 52b0994db216a18baf8adbeeedc8e081d572b9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 19 Sep 2024 16:00:19 +0200 Subject: [PATCH 006/108] fix doctest (adding ...) --- src/sage/schemes/elliptic_curves/BSD.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index a1520670e15..4473aa8727c 100755 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -95,6 +95,7 @@ def simon_two_descent_work(E, two_tor_rk): ... DeprecationWarning: Use E.rank(algorithm="pari") instead, as this script has been ported over to pari. See https://github.com/sagemath/sage/issues/35621 for details. + ... (0, 0, 0, 0, []) sage: E = EllipticCurve('37a') sage: simon_two_descent_work(E, E.two_torsion_rank()) From 65e3d783309f1dd7be07415b01971ad3117358e6 Mon Sep 17 00:00:00 2001 From: Sagar-math Date: Mon, 23 Sep 2024 12:03:01 +0530 Subject: [PATCH 007/108] Aligned documentation to columns 80 and other minor modifications --- src/sage/graphs/graph.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 6825b452f09..fa51562f0ab 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4127,26 +4127,29 @@ def tutte_symmetric_function(self, R=None, t=None): r""" Return the Tutte symmetric function of ``self``. - Let `G` be a graph. The Tutte symmetric function `XB_G` of the graph `G` was introduced in [Sta1998]_. We present - the equivalent definition given in [CS2022]_. + Let `G` be a graph. The Tutte symmetric function `XB_G` of the graph + `G` was introduced in [Sta1998]_. We present the equivalent definition + given in [CS2022]_. .. MATH:: XB_G = \sum_{\pi \vdash V} (1+t)^{e(\pi)} \tilde{m}_{\lambda(\pi)}, - where the sum ranges over all set-partitions `\pi` of the vertex set `V`, `\lambda(pi)` is the - partition determined by the sizes of the blocks of `\pi`, and `e(pi)` is the number of edges whose endpoints - lie in the same block of `\pi`. In particular, the coefficients of `XB_G` - when expanded in terms of augmented monomial symmetric functions are polynomials in `t` with - non-negative integer coefficients. + where the sum ranges over all set-partitions `\pi` of the vertex set + `V`, `\lambda(pi)` is the partition determined by the sizes of the + blocks of `\pi`, and `e(pi)` is the number of edges whose endpoints + lie in the same block of `\pi`. In particular, the coefficients of + `XB_G` when expanded in terms of augmented monomial symmetric functions + are polynomials in `t` with non-negative integer coefficients. - For an integer partition `\lambda = 1^{r_1}2^{r_2}\cdots` expressed in the exponential notation, the augmented monomial symmetric function is defined as + For an integer partition `\lambda = 1^{r_1}2^{r_2}\cdots` expressed in + the exponential notation, the augmented monomial symmetric function + is defined as .. MATH:: \tilde{m}_{\lambda} = \(\prod_{i} r_i!\) m_{\lambda}. - INPUT: - ``R`` -- (optional) the base ring for the symmetric functions; @@ -4160,9 +4163,12 @@ def tutte_symmetric_function(self, R=None, t=None): sage: p = SymmetricFunctions(ZZ).p() # needs sage.combinat sage.modules sage: G = Graph([[1,2],[2,3],[3,4],[4,1],[1,3]]) sage: XB_G = G.tutte_symmetric_function(); XB_G # needs sage.combinat sage.modules - 24*m[1, 1, 1, 1] + (10*t+12)*m[2, 1, 1] + (4*t^2+10*t+6)*m[2, 2] + (2*t^3+8*t^2+10*t+4)*m[3, 1] + (t^5+5*t^4+10*t^3+10*t^2+5*t+1)*m[4] + 24*m[1, 1, 1, 1] + (10*t+12)*m[2, 1, 1] + (4*t^2+10*t+6)*m[2, 2] + + (2*t^3+8*t^2+10*t+4)*m[3, 1] + + (t^5+5*t^4+10*t^3+10*t^2+5*t+1)*m[4] sage: p(XB_G) # needs sage.combinat sage.modules - p[1, 1, 1, 1] + 5*t*p[2, 1, 1] + 2*t^2*p[2, 2] + (2*t^3+8*t^2)*p[3, 1] + (t^5+5*t^4+8*t^3)*p[4] + p[1, 1, 1, 1] + 5*t*p[2, 1, 1] + 2*t^2*p[2, 2] + + (2*t^3+8*t^2)*p[3, 1] + (t^5+5*t^4+8*t^3)*p[4] Graphs are allowed to have multiedges and loops:: @@ -4171,13 +4177,16 @@ def tutte_symmetric_function(self, R=None, t=None): 6*m[1, 1, 1] + (t^2+3*t+3)*m[2, 1] + (t^3+3*t^2+3*t+1)*m[3] - We check that at `t = -1`, we recover the usual chromatic symmetric function:: + We check that at `t = -1`, we recover the usual chromatic symmetric + function:: sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,5]], multiedges=True) sage: XB_G = G.tutte_symmetric_function(t=-1); XB_G # needs sage.combinat sage.modules - 120*m[1, 1, 1, 1, 1] + 36*m[2, 1, 1, 1] + 12*m[2, 2, 1] + 2*m[3, 1, 1] + m[3, 2] + 120*m[1, 1, 1, 1, 1] + 36*m[2, 1, 1, 1] + 12*m[2, 2, 1] + + 2*m[3, 1, 1] + m[3, 2] sage: X_G = G.chromatic_symmetric_function(); X_G # needs sage.combinat sage.modules - p[1, 1, 1, 1, 1] - 4*p[2, 1, 1, 1] + 3*p[2, 2, 1] + 3*p[3, 1, 1] - 2*p[3, 2] - 2*p[4, 1] + p[5] + p[1, 1, 1, 1, 1] - 4*p[2, 1, 1, 1] + 3*p[2, 2, 1] + 3*p[3, 1, 1] + - 2*p[3, 2] - 2*p[4, 1] + p[5] sage: XB_G == X_G # needs sage.combinat sage.modules True @@ -4195,8 +4204,7 @@ def tutte_symmetric_function(self, R=None, t=None): m = SymmetricFunctions(R).m() ret = m.zero() V = self.vertices() - E = list(self.edges(labels=False)) - M = Counter(E) + M = Counter(list(self.edges(labels=False))) fact = [factorial(i) for i in range(len(V)+1)] def mono(pi): From 2f2d683b91694a20182e37fe17a7b2bdf22e72c0 Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+sagar-math@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:54:06 +0530 Subject: [PATCH 008/108] incorporated suggested changes --- src/sage/graphs/graph.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index fa51562f0ab..e397380b556 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4152,23 +4152,22 @@ def tutte_symmetric_function(self, R=None, t=None): INPUT: - - ``R`` -- (optional) the base ring for the symmetric functions; - this uses `\ZZ` by default + - ``R`` -- (default: the parent of ``t``) the base ring for the symmetric + functions - - ``t`` -- (optional) the parameter `t`; uses the variable `t` in - `\ZZ[t]` by default + - ``t`` -- (default: `t` in `\ZZ[t]`) the parameter `t` - EXAMPLES: + EXAMPLES:: sage: p = SymmetricFunctions(ZZ).p() # needs sage.combinat sage.modules sage: G = Graph([[1,2],[2,3],[3,4],[4,1],[1,3]]) sage: XB_G = G.tutte_symmetric_function(); XB_G # needs sage.combinat sage.modules 24*m[1, 1, 1, 1] + (10*t+12)*m[2, 1, 1] + (4*t^2+10*t+6)*m[2, 2] - + (2*t^3+8*t^2+10*t+4)*m[3, 1] - + (t^5+5*t^4+10*t^3+10*t^2+5*t+1)*m[4] + + (2*t^3+8*t^2+10*t+4)*m[3, 1] + + (t^5+5*t^4+10*t^3+10*t^2+5*t+1)*m[4] sage: p(XB_G) # needs sage.combinat sage.modules p[1, 1, 1, 1] + 5*t*p[2, 1, 1] + 2*t^2*p[2, 2] - + (2*t^3+8*t^2)*p[3, 1] + (t^5+5*t^4+8*t^3)*p[4] + + (2*t^3+8*t^2)*p[3, 1] + (t^5+5*t^4+8*t^3)*p[4] Graphs are allowed to have multiedges and loops:: @@ -4176,20 +4175,18 @@ def tutte_symmetric_function(self, R=None, t=None): sage: XB_G = G.tutte_symmetric_function(); XB_G # needs sage.combinat sage.modules 6*m[1, 1, 1] + (t^2+3*t+3)*m[2, 1] + (t^3+3*t^2+3*t+1)*m[3] - We check that at `t = -1`, we recover the usual chromatic symmetric function:: sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,5]], multiedges=True) sage: XB_G = G.tutte_symmetric_function(t=-1); XB_G # needs sage.combinat sage.modules 120*m[1, 1, 1, 1, 1] + 36*m[2, 1, 1, 1] + 12*m[2, 2, 1] - + 2*m[3, 1, 1] + m[3, 2] + + 2*m[3, 1, 1] + m[3, 2] sage: X_G = G.chromatic_symmetric_function(); X_G # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 4*p[2, 1, 1, 1] + 3*p[2, 2, 1] + 3*p[3, 1, 1] - - 2*p[3, 2] - 2*p[4, 1] + p[5] + - 2*p[3, 2] - 2*p[4, 1] + p[5] sage: XB_G == X_G # needs sage.combinat sage.modules True - """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.set_partition import SetPartitions @@ -4205,7 +4202,8 @@ def tutte_symmetric_function(self, R=None, t=None): ret = m.zero() V = self.vertices() M = Counter(list(self.edges(labels=False))) - fact = [factorial(i) for i in range(len(V)+1)] + fact = [1] + fact.extend(fact[-1] * i for i in range(1, len(V)+1)) def mono(pi): arcs = 0 @@ -4216,7 +4214,7 @@ def mono(pi): for pi in SetPartitions(V): pa = pi.to_partition() - ret += prod([fact[i] for i in pa.to_exp()])*m[pa]*(1+t)**mono(pi) + ret += prod(fact[i] for i in pa.to_exp()) * m[pa] * (1+t)**mono(pi) return ret @doc_index("Leftovers") From 985ff17349449e1d565b2002ac888e52f46d793b Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+s-s-sawant@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:54:08 +0530 Subject: [PATCH 009/108] removed white space --- src/sage/graphs/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index e397380b556..291e7471d6d 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4152,7 +4152,7 @@ def tutte_symmetric_function(self, R=None, t=None): INPUT: - - ``R`` -- (default: the parent of ``t``) the base ring for the symmetric + - ``R`` -- (default: the parent of ``t``) the base ring for the symmetric functions - ``t`` -- (default: `t` in `\ZZ[t]`) the parameter `t` From 623ad04deb50a93a5f5a52650ee705cfe87b4a4f Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+s-s-sawant@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:59:31 +0530 Subject: [PATCH 010/108] rectified parenthesis in documention for tutte_symmetric_function --- src/sage/graphs/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 291e7471d6d..4f30cfd075c 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4148,7 +4148,7 @@ def tutte_symmetric_function(self, R=None, t=None): .. MATH:: - \tilde{m}_{\lambda} = \(\prod_{i} r_i!\) m_{\lambda}. + \tilde{m}_{\lambda} = \left(\prod_{i} r_i! \right) m_{\lambda}. INPUT: From 08c24a2c44de59f7e6e048782d5a097196c127d8 Mon Sep 17 00:00:00 2001 From: Kyle Hofmann Date: Fri, 9 Feb 2024 13:20:01 -0800 Subject: [PATCH 011/108] NotImplementedError when pow() called with modulus --- .../rings/polynomial/laurent_polynomial.pyx | 14 +++++++++++++- .../polynomial/laurent_polynomial_mpair.pyx | 14 +++++++++++++- .../polynomial/multi_polynomial_libsingular.pyx | 15 ++++++++++++++- src/sage/rings/polynomial/plural.pyx | 17 ++++++++++++++++- .../polynomial_integer_dense_flint.pyx | 15 ++++++++++++++- .../polynomial/polynomial_rational_flint.pyx | 15 ++++++++++++++- 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 70cec491cae..58a3ac2787d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1126,7 +1126,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__u.is_monomial() - def __pow__(_self, r, dummy): + def __pow__(_self, r, mod): """ EXAMPLES:: @@ -1145,9 +1145,21 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): x^-8 sage: (5*x^-4)^-3 5*x^12 + + Check that using third argument raises an error:: + + sage: L. = LaurentPolynomialRing(R) + sage: pow(x, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ cdef LaurentPolynomial_univariate self = _self cdef long right = r + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) if right != r: raise ValueError("exponent must be an integer") try: diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index e6ea53e1756..be74a847c57 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -460,7 +460,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): return P({e: c}) return super().__invert__() - def __pow__(LaurentPolynomial_mpair self, n, m): + def __pow__(LaurentPolynomial_mpair self, n, mod): """ EXAMPLES:: @@ -480,8 +480,20 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: f = (x+y+z^-1)^2 sage: f.substitute(z=1) x^2 + 2*x*y + y^2 + 2*x + 2*y + 1 + + Check that using third argument raises an error:: + + sage: L. = LaurentPolynomialRing(R) + sage: pow(x + y + z, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ cdef LaurentPolynomial_mpair ans + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) if n < 0: return ~(self ** -n) ans = self._new_c() diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index d177889bd6e..bf680ffc674 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2350,7 +2350,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): else: return (left._parent).fraction_field()(left,right_ringelement) - def __pow__(MPolynomial_libsingular self, exp, ignored): + def __pow__(MPolynomial_libsingular self, exp, mod): """ Return ``self**(exp)``. @@ -2413,7 +2413,20 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): Traceback (most recent call last): ... TypeError: R is neither an integer nor a rational + + Check that using third argument raises an error:: + + sage: R. = PolynomialRing(ZZ) + sage: pow(x + y + z, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) + if type(exp) is not Integer: try: exp = Integer(exp) diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index eb6b091c683..46289e490bb 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1671,7 +1671,7 @@ cdef class NCPolynomial_plural(RingElement): else: return (left._parent).fraction_field()(left,right) - def __pow__(NCPolynomial_plural self, exp, ignored): + def __pow__(NCPolynomial_plural self, exp, mod): """ Return ``self**(exp)``. @@ -1697,7 +1697,22 @@ cdef class NCPolynomial_plural(RingElement): Traceback (most recent call last): .... OverflowError: exponent overflow (2147483648) + + Check that using third argument raises an error:: + + sage: A. = FreeAlgebra(QQ, 3) + sage: P = A.g_algebra(relations={y*x:-x*y + z}, order='lex') + sage: P.inject_variables() + Defining x, z, y + sage: pow(x + y + z, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) if type(exp) is not Integer: try: exp = Integer(exp) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 8aa1d13b5c1..fc2ab9b584e 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -1035,7 +1035,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sig_off() return x - def __pow__(Polynomial_integer_dense_flint self, exp, ignored): + def __pow__(Polynomial_integer_dense_flint self, exp, mod): """ EXAMPLES:: @@ -1114,10 +1114,23 @@ cdef class Polynomial_integer_dense_flint(Polynomial): ... TypeError: no canonical coercion from Univariate Polynomial Ring in R over Integer Ring to Rational Field + + Check that using third argument raises an error:: + + sage: R. = PolynomialRing(ZZ, implementation='FLINT') + sage: pow(x, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ cdef long nn cdef Polynomial_integer_dense_flint res + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) + try: nn = pyobject_to_long(exp) except TypeError: diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index df25358ff3b..ceaa9d7b2d5 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -1160,7 +1160,7 @@ cdef class Polynomial_rational_flint(Polynomial): if do_sig: sig_off() return res - def __pow__(Polynomial_rational_flint self, exp, ignored): + def __pow__(Polynomial_rational_flint self, exp, mod): """ Return ``self`` raised to the power of ``exp``. @@ -1266,10 +1266,23 @@ cdef class Polynomial_rational_flint(Polynomial): ... TypeError: no canonical coercion from Univariate Polynomial Ring in R over Rational Field to Rational Field + + Check that using third argument raises an error:: + + sage: R. = PolynomialRing(QQ) + sage: pow(x, 2, x) + Traceback (most recent call last): + ... + NotImplementedError: pow() with a modulus is not implemented for this ring """ cdef Polynomial_rational_flint res cdef long n + if mod is not None: + raise NotImplementedError( + "pow() with a modulus is not implemented for this ring" + ) + try: n = pyobject_to_long(exp) except TypeError: From dd0698aa883941dbd1983bc0abc253bc802fb5cf Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+s-s-sawant@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:52:53 +0530 Subject: [PATCH 012/108] minor documentation rectifications --- src/sage/graphs/graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 4f30cfd075c..2935ab80269 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4136,8 +4136,8 @@ def tutte_symmetric_function(self, R=None, t=None): XB_G = \sum_{\pi \vdash V} (1+t)^{e(\pi)} \tilde{m}_{\lambda(\pi)}, where the sum ranges over all set-partitions `\pi` of the vertex set - `V`, `\lambda(pi)` is the partition determined by the sizes of the - blocks of `\pi`, and `e(pi)` is the number of edges whose endpoints + `V`, `\lambda(\pi)` is the partition determined by the sizes of the + blocks of `\pi`, and `e(\pi)` is the number of edges whose endpoints lie in the same block of `\pi`. In particular, the coefficients of `XB_G` when expanded in terms of augmented monomial symmetric functions are polynomials in `t` with non-negative integer coefficients. From 36bf3b9d214ff24533199a0818a98f5ffe48f11e Mon Sep 17 00:00:00 2001 From: dcoudert Date: Fri, 27 Sep 2024 10:35:53 +0200 Subject: [PATCH 013/108] fix issue 38713 --- src/sage/graphs/generic_graph.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6ed8446ae1c..a43a36057fd 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -7512,7 +7512,7 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, sage: g.edge_cut(1, 2, value_only=True, algorithm='LP') # needs sage.numerical.mip 3 - :issue:`12797`:: + Check that :issue:`12797` and :issue:`38713` are fixed:: sage: G = Graph([(0, 3, 1), (0, 4, 1), (1, 2, 1), (2, 3, 1), (2, 4, 1)]) sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True) @@ -7521,7 +7521,7 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True) [1, [(2, 1, 1)]] sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True, algorithm='LP') # needs sage.numerical.mip - (1, [(2, 1)]) + (1, [(2, 1, 1)]) """ self._scream_if_not_simple(allow_loops=True) if vertices: @@ -7574,9 +7574,10 @@ def weight(x): # frozensets otherwise if g.is_directed(): def good_edge(e): - return e + return (e[0], e[1]) else: - good_edge = frozenset + def good_edge(e): + return frozenset((e[0], e[1])) # Some vertices belong to part 1, others to part 0 p.add_constraint(v[s], min=0, max=0) @@ -7589,7 +7590,7 @@ def good_edge(e): # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut - for x, y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=False): p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) else: @@ -7597,7 +7598,7 @@ def good_edge(e): p.set_objective(p.sum(weight(w) * b[good_edge((x, y))] for x, y, w in g.edge_iterator())) # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut - for x, y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=False): p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) p.add_constraint(v[y] + b[good_edge((x, y))] - v[x], min=0) @@ -7612,7 +7613,7 @@ def good_edge(e): return obj answer = [obj] - answer.append([e for e in g.edge_iterator(labels=False) if b[good_edge(e)]]) + answer.append([e for e in g.edge_iterator(labels=True) if b[good_edge(e)]]) if vertices: v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) From bf7f14fb5b92b349e2c5baf2ba844159441c8fe6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 28 Sep 2024 21:08:42 +0200 Subject: [PATCH 014/108] provide monomial_coefficients for polynomials and allow single argument for MPolynomialRing_base.monomial --- src/sage/rings/polynomial/multi_polynomial_element.py | 2 ++ src/sage/rings/polynomial/multi_polynomial_ring_base.pyx | 7 +++++++ src/sage/rings/polynomial/polynomial_element.pyx | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 0e8d831b808..ab13879bf10 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -804,6 +804,8 @@ def dict(self): """ return self.element().dict() + monomial_coefficients = dict + def __iter__(self): """ Iterate over ``self`` respecting the term order. diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 90e736dbadf..9814d5fe385 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -1371,7 +1371,14 @@ cdef class MPolynomialRing_base(CommutativeRing): sage: m = R.monomial(1,2,3) sage: R.monomial(*m.degrees()) == m True + + We also allow to specify the exponents in a single tuple:: + + sage: R.monomial(e) + x*y^2*z^3 """ + if len(exponents) == 1 and isinstance(exponents, tuple): + return self({exponents[0]: self.base_ring().one()}) return self({exponents: self.base_ring().one()}) def monomials_of_degree(self, degree): diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4f20542237f..076d585105f 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4485,6 +4485,8 @@ cdef class Polynomial(CommutativePolynomial): X[i] = c return X + monomial_coefficients = dict + def factor(self, **kwargs): r""" Return the factorization of ``self`` over its base ring. From 24fc9a2fe235abec6358e76f6179254dcbe23065 Mon Sep 17 00:00:00 2001 From: Kyle Hofmann Date: Thu, 8 Feb 2024 14:52:11 -0800 Subject: [PATCH 015/108] Improve wrapping sig_on()/sig_off(), add doctest --- src/sage/libs/flint/nmod_poly_linkage.pxi | 27 ++++++++++++++++--- .../rings/polynomial/polynomial_template.pxi | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index b2450ed190b..61b647fd1e4 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -577,18 +577,37 @@ cdef inline int celement_gcd(nmod_poly_t res, nmod_poly_t a, nmod_poly_t b, unsi True sage: (G//d)*d == G True + + Check that we catch a case where FLINT fails. These generate the unit + ideal, so their GCD should be 1 (or another unit):: + + sage: R. = Integers(121)[] + sage: f = 11*x^2 + 1 + sage: f - 61*x*f.derivative() + 1 + sage: gcd(f, f.derivative()) + Traceback (most recent call last): + ... + RuntimeError: FLINT gcd calculation failed """ if celement_is_zero(b, n): nmod_poly_set(res, a) return 0 - # A check that the leading coefficients are invertible is *not* sufficient + # FLINT provides no interface for detecting errors here try: sig_on() - nmod_poly_gcd(res, a, b) - sig_off() + try: + nmod_poly_gcd(res, a, b) + finally: + sig_off() except RuntimeError: - raise ValueError("non-invertible elements encountered during GCD") + raise RuntimeError("FLINT gcd calculation failed") from None + + cdef unsigned long leadcoeff = nmod_poly_get_coeff_ui(res, nmod_poly_degree(res)) + cdef unsigned long modulus = nmod_poly_modulus(res) + if n_gcd(modulus,leadcoeff) == 1: + nmod_poly_make_monic(res, res) cdef inline int celement_xgcd(nmod_poly_t res, nmod_poly_t s, nmod_poly_t t, nmod_poly_t a, nmod_poly_t b, unsigned long n) except -2: """ diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 402e6831245..b76d62a9e92 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -371,7 +371,7 @@ cdef class Polynomial_template(Polynomial): sage: f.gcd(g) Traceback (most recent call last): ... - ValueError: non-invertible elements encountered during GCD + RuntimeError: FLINT gcd calculation failed """ if celement_is_zero(&self.x, (self)._cparent): return other From eb25d4d319b91cb03bb11e5864be5b4facf2cd17 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 5 Sep 2024 20:31:39 -0700 Subject: [PATCH 016/108] src/sage_docbuild/builders.py: Actually test feature presence in '.. only' --- src/sage_docbuild/builders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 871cc4705a2..ab39d93c280 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -1054,7 +1054,7 @@ def get_modules(self, filename): try: tag_name = line[line.index('feature_') + 8:].strip() for feature in all_features(): - if tag_name == feature.name.replace('.', '_'): + if tag_name == feature.name.replace('.', '_') and feature.is_present(): break else: skip = True From e2940d32e4131f8623ab915996872545b3d0d9e9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 25 Sep 2024 18:33:17 -0700 Subject: [PATCH 017/108] src/sage/rings/function_field/element.pyx: Update # needs --- src/sage/rings/function_field/element.pyx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/function_field/element.pyx b/src/sage/rings/function_field/element.pyx index f64c223f18b..2863732cf3b 100644 --- a/src/sage/rings/function_field/element.pyx +++ b/src/sage/rings/function_field/element.pyx @@ -202,6 +202,7 @@ cdef class FunctionFieldElement(FieldElement): We also substitute the generators in any base fields:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) @@ -224,6 +225,8 @@ cdef class FunctionFieldElement(FieldElement): Traceback (most recent call last): ... TypeError: in_dict must be a dict + + sage: # needs sage.rings.function_field sage: R. = K[] sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) sage: f = x + y @@ -234,6 +237,7 @@ cdef class FunctionFieldElement(FieldElement): We can also substitute using dictionary syntax:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) @@ -249,6 +253,7 @@ cdef class FunctionFieldElement(FieldElement): Check that we correctly handle extension fields:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) @@ -270,6 +275,7 @@ cdef class FunctionFieldElement(FieldElement): Test that substitution works for rational functions:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(y^4 - 3) @@ -298,6 +304,7 @@ cdef class FunctionFieldElement(FieldElement): Same purpose as above but over an extension field over the rationals:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) @@ -319,6 +326,7 @@ cdef class FunctionFieldElement(FieldElement): Test proper handling of not making substitutions:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: f = x sage: f.subs() is f @@ -357,6 +365,7 @@ cdef class FunctionFieldElement(FieldElement): Test error handling with ambiguously named generators:: + sage: # needs sage.rings.function_field sage: K. = FunctionField(QQ) sage: R. = K[] sage: L. = K.extension(x^3 - x) From 1cb84d8b9e4f29d3ce25eda67ee23a554c8dd081 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 9 Jun 2024 14:49:47 -0700 Subject: [PATCH 018/108] sage.categories: Update # needs --- .../finite_dimensional_algebras_with_basis.py | 20 +++++++++++++------ src/sage/categories/semigroups.py | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 03ae127de8f..f4a31b557f9 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -145,6 +145,7 @@ def radical_basis(self): We compute the radical basis in a subalgebra using the inherited product:: + sage: # needs sage.modules sage: scoeffs = {('a','e'): {'a':1}, ('b','e'): {'a':1, 'b':1}, ....: ('c','d'): {'a':1}, ('c','e'): {'c':1}} sage: L. = LieAlgebra(QQ, scoeffs) @@ -155,14 +156,14 @@ def radical_basis(self): TESTS:: - sage: A = KleinFourGroup().algebra(GF(2)) # needs sage.groups sage.modules - sage: A.radical_basis() # needs sage.groups sage.modules + sage: # needs sage.groups sage.modules + sage: A = KleinFourGroup().algebra(GF(2)) + sage: A.radical_basis() (() + (1,2)(3,4), (3,4) + (1,2)(3,4), (1,2) + (1,2)(3,4)) - - sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) # needs sage.groups sage.modules - sage: A.radical_basis.__module__ # needs sage.groups sage.modules + sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) + sage: A.radical_basis.__module__ 'sage.categories.finite_dimensional_algebras_with_basis' - sage: A.radical_basis() # needs sage.groups sage.modules + sage: A.radical_basis() () """ F = self.base_ring() @@ -421,6 +422,7 @@ def subalgebra(self, gens, category=None, *args, **opts): EXAMPLES:: + sage: # needs sage.modules sage: scoeffs = {('a','e'): {'a':1}, ('b','e'): {'a':1, 'b':1}, ....: ('c','d'): {'a':1}, ('c','e'): {'c':1}} sage: L. = LieAlgebra(QQ, scoeffs) @@ -429,6 +431,7 @@ def subalgebra(self, gens, category=None, *args, **opts): sage: A.dimension() 7 + sage: # needs sage.modules sage: L. = LieAlgebra(GF(3), {('x','z'): {'x':1, 'y':1}, ('y','z'): {'y':1}}) sage: MS = MatrixSpace(L.base_ring(), L.dimension()) sage: gens = [b.adjoint_matrix() for b in L.basis()] @@ -473,6 +476,7 @@ def ideal_submodule(self, gens, side='left', category=None, *args, **opts): EXAMPLES:: + sage: # needs sage.modules sage: scoeffs = {('a','e'): {'a':1}, ('b','e'): {'a':1, 'b':1}, ....: ('c','d'): {'a':1}, ('c','e'): {'c':1}} sage: L. = LieAlgebra(QQ, scoeffs) @@ -1537,18 +1541,21 @@ def simple_module_parameterization(self): EXAMPLES:: + sage: # needs sage.modules sage: TL = TemperleyLiebAlgebra(5, 30, QQ) # semisimple sage: len(TL.radical_basis()) 0 sage: TL.simple_module_parameterization() (1, 3, 5) + sage: # needs sage.modules sage: TL = TemperleyLiebAlgebra(5, 1, QQ) # not semisimple sage: len(TL.radical_basis()) 24 sage: TL.simple_module_parameterization() (1, 3, 5) + sage: # needs sage.modules sage: TL = TemperleyLiebAlgebra(6, 30, QQ) # semisimple sage: all(TL.cell_module(la).dimension() ....: == TL.cell_module(la).simple_module().dimension() @@ -1557,6 +1564,7 @@ def simple_module_parameterization(self): sage: TL.simple_module_parameterization() (0, 2, 4, 6) + sage: # needs sage.modules sage: TL = TemperleyLiebAlgebra(6, 0, QQ) # not semisimple sage: TL.simple_module_parameterization() (2, 4, 6) diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 7114761aaac..bf67a3a7bfa 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -511,6 +511,7 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): EXAMPLES:: + sage: # needs sage.groups sage: G = CyclicPermutationGroup(3) sage: M = algebras.Exterior(QQ, 'x', 3) sage: def on_basis(g, m): # cyclically permute generators @@ -1059,6 +1060,7 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): EXAMPLES:: + sage: # needs sage.broups sage: G = groups.permutation.Dihedral(5) sage: CFM = CombinatorialFreeModule(GF(2), [1, 2, 3, 4, 5]) sage: A = G.algebra(GF(2)) From 4092691ac36f4fdd29ba9af26c086ee65f914289 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 22 Jun 2024 14:31:22 -0700 Subject: [PATCH 019/108] src/sage/categories/semigroups.py: Fix # needs --- src/sage/categories/semigroups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index bf67a3a7bfa..1635296450b 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -1060,7 +1060,7 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): EXAMPLES:: - sage: # needs sage.broups + sage: # needs sage.groups sage: G = groups.permutation.Dihedral(5) sage: CFM = CombinatorialFreeModule(GF(2), [1, 2, 3, 4, 5]) sage: A = G.algebra(GF(2)) From 1ffe4384e09119931382924623516eea46b3553c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Jul 2024 13:24:25 +0200 Subject: [PATCH 020/108] src/sage/categories/triangular_kac_moody_algebras.py: Add # needs --- src/sage/categories/triangular_kac_moody_algebras.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/categories/triangular_kac_moody_algebras.py b/src/sage/categories/triangular_kac_moody_algebras.py index 19ff3846b67..d6541107a0f 100644 --- a/src/sage/categories/triangular_kac_moody_algebras.py +++ b/src/sage/categories/triangular_kac_moody_algebras.py @@ -215,6 +215,7 @@ def _triangular_key(self, x): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: L = lie_algebras.sl(QQ, 3) sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights() sage: sorted(L.basis().keys(), key=L._basis_key) @@ -352,6 +353,7 @@ def _transpose_basis_mapping(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: g = LieAlgebra(QQ, cartan_type=['A', 2]) sage: g._transpose_basis_mapping {-alpha[1]: alpha[1], @@ -384,6 +386,7 @@ def _transpose_on_basis(self, m): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: g = LieAlgebra(QQ, cartan_type=['B', 2]) sage: B = g.basis() sage: [(B[k], g._transpose_on_basis(k)) for k in B.keys()] @@ -407,6 +410,7 @@ def transpose(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: g = LieAlgebra(QQ, cartan_type=['B', 2]) sage: g.transpose Generic endomorphism of Lie algebra of ['B', 2] in the Chevalley basis @@ -425,6 +429,7 @@ def transpose(self): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: g = LieAlgebra(QQ, cartan_type=['G', 2]) sage: for b in g.basis(): ....: for bp in g.basis(): From 3dfdfa6d58fee3e0b136e4a71ceed26f2779fdd7 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 29 Sep 2024 11:35:14 +0200 Subject: [PATCH 021/108] fix thinko --- src/sage/rings/polynomial/multi_polynomial_ring_base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 9814d5fe385..8b7845479cf 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -1377,7 +1377,7 @@ cdef class MPolynomialRing_base(CommutativeRing): sage: R.monomial(e) x*y^2*z^3 """ - if len(exponents) == 1 and isinstance(exponents, tuple): + if len(exponents) == 1 and isinstance(exponents[0], tuple): return self({exponents[0]: self.base_ring().one()}) return self({exponents: self.base_ring().one()}) From db60ae344cf9b8c01d3940e319abf0ffbdcf61b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 12:21:54 +0200 Subject: [PATCH 022/108] activate linter check of E275 and clean one file --- src/sage/knots/free_knotinfo_monoid.py | 38 ++++++++++++++++---------- src/tox.ini | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/sage/knots/free_knotinfo_monoid.py b/src/sage/knots/free_knotinfo_monoid.py index c8301a4d138..d1cedbc6d8c 100644 --- a/src/sage/knots/free_knotinfo_monoid.py +++ b/src/sage/knots/free_knotinfo_monoid.py @@ -1,13 +1,15 @@ # sage_setup: distribution = sagemath-graphs r""" -Free monoid genereated by prime knots available via the :class:`~sage.knots.knotinfo.KnotInfoBase` class. +Free monoid generated by prime knots available via the +:class:`~sage.knots.knotinfo.KnotInfoBase` class. -A generator of this free abelian monoid is a prime knot according to the list at -`KnotInfo `__. A fully amphicheiral prime -knot is represented by exactly one generator with the corresponding name. For -non-chiral prime knots, there are additionally one or three generators with the -suffixes ``m``, ``r`` and ``c`` which specify the mirror and reverse images -according to their symmetry type. +A generator of this free abelian monoid is a prime knot according to +the list at `KnotInfo `__. A fully +amphicheiral prime knot is represented by exactly one generator with +the corresponding name. For non-chiral prime knots, there are +additionally one or three generators with the suffixes ``m``, ``r`` +and ``c`` which specify the mirror and reverse images according to +their symmetry type. AUTHORS: @@ -25,7 +27,8 @@ ############################################################################## from sage.knots.knotinfo import SymmetryMutant -from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid, IndexedFreeAbelianMonoidElement +from sage.monoids.indexed_free_monoid import (IndexedFreeAbelianMonoid, + IndexedFreeAbelianMonoidElement) from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -67,8 +70,10 @@ def as_knot(self): def to_knotinfo(self): r""" - Return a word representing ``self`` as a list of pairs where each pair - ``(ki, sym)`` consists of a :class:`~sage.knots.knotinfo.KontInfoBase` instance ``ki`` and + Return a word representing ``self`` as a list of pairs. + + Each pair ``(ki, sym)`` consists of a + :class:`~sage.knots.knotinfo.KnotInfoBase` instance ``ki`` and :class:`~sage.knots.knotinfo.SymmetryMutant` instance ``sym``. EXAMPLES:: @@ -109,7 +114,8 @@ def __classcall_private__(cls, max_crossing_number=6, prefix=None, **kwds): if not prefix: prefix = 'KnotInfo' # We skip the IndexedMonoid__classcall__ - return UniqueRepresentation.__classcall__(cls, max_crossing_number, prefix=prefix, **kwds) + return UniqueRepresentation.__classcall__(cls, max_crossing_number, + prefix=prefix, **kwds) def __init__(self, max_crossing_number, category=None, prefix=None, **kwds): r""" @@ -405,7 +411,8 @@ def from_knot(self, knot, unique=True): sage: FKIM.from_knot(K) # long time Traceback (most recent call last): ... - NotImplementedError: this (possibly non prime) knot cannot be identified uniquely by KnotInfo + NotImplementedError: this (possibly non prime) knot cannot be + identified uniquely by KnotInfo use keyword argument `unique` to obtain more details sage: FKIM.from_knot(K, unique=False) # long time [KnotInfo['K4_1']*KnotInfo['K5_2'], KnotInfo['K9_12']] @@ -427,10 +434,10 @@ def from_knot(self, knot, unique=True): if unique: return k else: - return[k] # to be consistent with get_knotinfo + return [k] # to be consistent with get_knotinfo if res and not unique: - return sorted(list(set(res))) + return sorted(set(res)) if unique and len(res) > 1: non_unique_hint = '\nuse keyword argument `unique` to obtain more details' raise NotImplementedError('this (possibly non prime) knot cannot be identified uniquely by KnotInfo%s' % non_unique_hint) @@ -487,7 +494,8 @@ def inject_variables(self, select=None, verbose=True): crn = select if crn > max_crn: self._set_index_dictionary(max_crossing_number=crn) - gen_list += [k for k, v in idx_dict.items() if v[0].crossing_number() == crn] + gen_list += [k for k, v in idx_dict.items() + if v[0].crossing_number() == crn] else: raise TypeError('cannot select generators by %s' % select) else: diff --git a/src/tox.ini b/src/tox.ini index 094c1f54806..d9980f72257 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -180,7 +180,7 @@ description = # W605: invalid escape sequence ‘x’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E275,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} pycodestyle --select E111,E271,E301,E302,E303,E305,E306,E401,E502,E703,E712,E713,E714,E72,W29,W391,W605, --filename *.pyx {posargs:{toxinidir}/sage/} [pycodestyle] From e6b03d4e4a9b8558f109f6de3b7e945572d7d685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 12:36:47 +0200 Subject: [PATCH 023/108] one more little fix --- src/sage/knots/link.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index dbaca5662c8..188411a62a9 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -4447,7 +4447,7 @@ def answer_list(l): a = answer(L) if a: ansl.append(a) - return sorted(list(set(ansl))) + return sorted(set(ansl)) if len(set(l)) == 1: return answer(l[0]) From ad1cc55a07ad512cca9d2bbf8f307188fda1453a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 14:02:25 +0200 Subject: [PATCH 024/108] move power series to Parent --- src/sage/rings/power_series_ring.py | 38 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 3ebcf680801..963e7a17236 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -44,7 +44,8 @@ x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 + O(x^10) sage: R. = PowerSeriesRing(QQ, default_prec=15) sage: sin(x) - x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 - 1/39916800*x^11 + 1/6227020800*x^13 + O(x^15) + x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 - 1/39916800*x^11 + + 1/6227020800*x^13 + O(x^15) An iterated example:: @@ -139,8 +140,6 @@ from sage.misc.lazy_import import lazy_import from sage.rings import ( integer, - laurent_series_ring, - laurent_series_ring_element, power_series_mpoly, power_series_poly, power_series_ring_element, @@ -153,6 +152,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.category_object import normalize_names from sage.structure.element import Expression, parent +from sage.structure.parent import Parent from sage.structure.nonexact import Nonexact from sage.structure.unique_representation import UniqueRepresentation @@ -355,7 +355,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, * :func:`sage.misc.defaults.set_series_precision` """ - #multivariate case: + # multivariate case: # examples for first case: # PowerSeriesRing(QQ,'x,y,z') # PowerSeriesRing(QQ,['x','y','z']) @@ -364,7 +364,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, names = name if isinstance(names, (tuple, list)) and len(names) > 1 or (isinstance(names, str) and ',' in names): return _multi_variate(base_ring, num_gens=arg2, names=names, - order=order, default_prec=default_prec, sparse=sparse) + order=order, default_prec=default_prec, sparse=sparse) # examples for second case: # PowerSeriesRing(QQ,3,'t') if arg2 is None and num_gens is not None: @@ -373,7 +373,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, if (isinstance(arg2, str) and isinstance(names, (int, integer.Integer))): return _multi_variate(base_ring, num_gens=names, names=arg2, - order=order, default_prec=default_prec, sparse=sparse) + order=order, default_prec=default_prec, sparse=sparse) # univariate case: the arguments to PowerSeriesRing used to be # (base_ring, name=None, default_prec=20, names=None, sparse=False), @@ -385,11 +385,10 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, elif arg2 is not None: default_prec = arg2 - ## too many things (padics, elliptic curves) depend on this behavior, - ## so no warning for now. - ## + # ## too many things (padics, elliptic curves) depend on this behavior, + # ## so no warning for now. - # if isinstance(name, (int,integer.Integer)) or isinstance(arg2,(int,integer.Integer)): + # if isinstance(name, (int, integer.Integer)) or isinstance(arg2, (int, integer.Integer)): # deprecation(issue_number, "This behavior of PowerSeriesRing is being deprecated in favor of constructing multivariate power series rings. (See Github issue #1956.)") # the following is the original, univariate-only code @@ -427,8 +426,9 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, raise TypeError("base_ring must be a commutative ring") return R + def _multi_variate(base_ring, num_gens=None, names=None, - order='negdeglex', default_prec=None, sparse=False): + order='negdeglex', default_prec=None, sparse=False): """ Construct multivariate power series ring. """ @@ -436,7 +436,7 @@ def _multi_variate(base_ring, num_gens=None, names=None, raise TypeError("you must specify a variable name or names") if num_gens is None: - if isinstance(names,str): + if isinstance(names, str): num_gens = len(names.split(',')) elif isinstance(names, (list, tuple)): num_gens = len(names) @@ -458,6 +458,7 @@ def _multi_variate(base_ring, num_gens=None, names=None, def _single_variate(): pass + def is_PowerSeriesRing(R): """ Return ``True`` if this is a *univariate* power series ring. This is in @@ -489,6 +490,7 @@ def is_PowerSeriesRing(R): else: return False + class PowerSeriesRing_generic(UniqueRepresentation, ring.CommutativeRing, Nonexact): """ A power series ring. @@ -592,9 +594,9 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, else: raise ValueError('unknown power series implementation: %r' % implementation) - ring.CommutativeRing.__init__(self, base_ring, names=name, - category=getattr(self, '_default_category', - _CommutativeRings)) + Parent.__init__(self, base=base_ring, names=name, + category=getattr(self, '_default_category', + _CommutativeRings)) Nonexact.__init__(self, default_prec) if implementation == 'pari': self.__generator = self.element_class(self, R.gen().__pari__()) @@ -832,7 +834,7 @@ def _element_constructor_(self, f, prec=infinity, check=True): elif isinstance(f, LaurentSeries) and f.parent().power_series_ring() is self: return self(f.power_series(), prec, check=check) elif isinstance(f, MagmaElement) and str(f.Type()) == 'RngSerPowElt': - v = sage_eval(f.Eltseq()) + v = sage_eval(f.Eltseq()) # could use .sage() ? return self(v) * (self.gen(0)**f.Valuation()) elif isinstance(f, FractionFieldElement): if self.base_ring().has_coerce_map_from(f.parent()): @@ -846,7 +848,8 @@ def _element_constructor_(self, f, prec=infinity, check=True): if isinstance(f, SymbolicSeries): if str(f.default_variable()) == self.variable_name(): return self.element_class(self, f.list(), - f.degree(f.default_variable()), check=check) + f.degree(f.default_variable()), + check=check) else: raise TypeError("Can only convert series into ring with same variable name.") else: @@ -1357,6 +1360,7 @@ def _get_action_(self, other, op, self_is_left): return BaseRingFloorDivAction(other, self, is_left=False) return super()._get_action_(other, op, self_is_left) + class PowerSeriesRing_over_field(PowerSeriesRing_domain): _default_category = CompleteDiscreteValuationRings() From 1480abb0a909cdc1786dd3e0fe2983c788a2666e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 14:16:59 +0200 Subject: [PATCH 025/108] fixing also multi power series and adding gens methods --- src/sage/rings/multi_power_series_ring.py | 22 ++++++++++++++++++---- src/sage/rings/power_series_ring.py | 14 +++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 89fa8548f5d..778652673ce 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -213,8 +213,8 @@ from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.term_order import TermOrder from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic -from sage.rings.ring import CommutativeRing from sage.structure.nonexact import Nonexact +from sage.structure.parent import Parent from sage.categories.commutative_rings import CommutativeRings _CommutativeRings = CommutativeRings() @@ -389,8 +389,9 @@ def __init__(self, base_ring, num_gens, name_list, # Multivariate power series rings inherit from power series rings. But # apparently we can not call their initialisation. Instead, initialise # CommutativeRing and Nonexact: - CommutativeRing.__init__(self, base_ring, name_list, category=_IntegralDomains if base_ring in - _IntegralDomains else _CommutativeRings) + Parent.__init__(self, base=base_ring, names=name_list, + category=_IntegralDomains if base_ring in + _IntegralDomains else _CommutativeRings) Nonexact.__init__(self, default_prec) # underlying polynomial ring in which to represent elements @@ -1005,7 +1006,7 @@ def gen(self, n=0): if n < 0 or n >= self._ngens: raise ValueError("Generator not defined.") #return self(self._poly_ring().gens()[int(n)]) - return self.element_class(parent=self,x=self._poly_ring().gens()[int(n)], is_gen=True) + return self.element_class(parent=self, x=self._poly_ring().gens()[int(n)], is_gen=True) def ngens(self): """ @@ -1019,6 +1020,19 @@ def ngens(self): """ return self._ngens + def gens(self): + """ + Return the generators of this ring. + + EXAMPLES:: + + sage: M = PowerSeriesRing(ZZ, 3, 'v') + sage: M.gens() + (v0, v1, v2) + """ + + return tuple(self.gen(i) for i in range(self._ngens)) + def prec_ideal(self): """ Return the ideal which determines precision; this is the ideal diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 963e7a17236..4bf2eb36c37 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -491,7 +491,7 @@ def is_PowerSeriesRing(R): return False -class PowerSeriesRing_generic(UniqueRepresentation, ring.CommutativeRing, Nonexact): +class PowerSeriesRing_generic(UniqueRepresentation, Parent, Nonexact): """ A power series ring. """ @@ -1100,6 +1100,18 @@ def gen(self, n=0): raise IndexError("generator n>0 not defined") return self.__generator + def gens(self): + """ + Return the generators of this ring. + + EXAMPLES:: + + sage: R. = PowerSeriesRing(ZZ) + sage: R.gens() + (t,) + """ + return (self.__generator,) + def uniformizer(self): """ Return a uniformizer of this power series ring if it is From 3dcc315068d8f4cf2a7c0b367e86fff61f191256 Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Sun, 29 Sep 2024 07:08:50 -0700 Subject: [PATCH 026/108] Expose Coxeter number and dual Coxeter number --- src/sage/combinat/root_system/root_system.py | 50 ++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index ac70314eae1..c177fb8e965 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -787,6 +787,56 @@ def coambient_space(self, base_ring=QQ): """ return self.dual.ambient_space(base_ring) + def coxeter_number(self): + """ + For an irreducible finite root system, reports the Coxeter number. + This function is a wrapper for the corresponding function in CartanType. + + EXAMPLES:: + + sage: rt = RootSystem(['C', 5]) + sage: rt.coxeter_number() + 10 + + .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.coxeter_number` + """ + # Check if RootSystem is finite and irreducible + if self.is_finite() and self.is_irreducible(): + # Hand over to CartanType method + return self._cartan_type.coxeter_number() + else: + raise ValueError("Coxeter number is defined only for finite and irreducible root systems.") + + def dual_coxeter_number(self): + """ + For an irreducible finite root system, reports the dual Coxeter number, + which is defined to be 1 plus the sum of the coefficients of simple roots + in the highest short root of the dual root system. This function is a + wrapper for the corresponding function in CartanType. + + EXAMPLES:: + + sage: rt = RootSystem(['C', 5]) + sage: rt.dual_coxeter_number() + 6 + + The dual Coxeter number is not the same concept as the Coxeter number + of the dual root system:: + + sage: rt.dual + Dual of root system of type ['C', 5] + sage: rt.dual.coxeter_number() + 10 + + .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.dual_coxeter_number` + """ + # Check if RootSystem is finite and irreducible + if self.is_finite() and self.is_irreducible(): + # Hand over to CartanType method + return self._cartan_type.dual_coxeter_number() + else: + raise ValueError("Dual Coxeter number is defined only for finite and irreducible root systems.") + def WeylDim(ct, coeffs): """ From 576784f9ff94d7582078f15de29b706d63bdf1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 16:31:27 +0200 Subject: [PATCH 027/108] remove empty line + add typing annotation --- src/sage/rings/multi_power_series_ring.py | 3 +-- src/sage/rings/power_series_ring.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 778652673ce..35c4d4beb32 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -1020,7 +1020,7 @@ def ngens(self): """ return self._ngens - def gens(self): + def gens(self) -> tuple: """ Return the generators of this ring. @@ -1030,7 +1030,6 @@ def gens(self): sage: M.gens() (v0, v1, v2) """ - return tuple(self.gen(i) for i in range(self._ngens)) def prec_ideal(self): diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 4bf2eb36c37..e6c932aadff 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -1100,7 +1100,7 @@ def gen(self, n=0): raise IndexError("generator n>0 not defined") return self.__generator - def gens(self): + def gens(self) -> tuple: """ Return the generators of this ring. From 6ff15892279cc4b102fa38630c70d02799b17e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 17:56:40 +0200 Subject: [PATCH 028/108] various pep8 fixes in modular folder --- src/sage/modular/abvar/constructor.py | 5 ++ src/sage/modular/abvar/cuspidal_subgroup.py | 6 +- src/sage/modular/abvar/finite_subgroup.py | 6 +- src/sage/modular/abvar/torsion_subgroup.py | 6 +- .../modular/arithgroup/arithgroup_perm.py | 21 ++++--- src/sage/modular/arithgroup/congroup_gamma.py | 8 ++- .../modular/arithgroup/congroup_gamma0.py | 8 ++- .../modular/arithgroup/congroup_gamma1.py | 15 ++--- .../modular/arithgroup/congroup_generic.py | 2 + src/sage/modular/arithgroup/congroup_sl2z.py | 2 + src/sage/modular/drinfeld_modform/element.py | 1 + src/sage/modular/drinfeld_modform/ring.py | 1 + src/sage/modular/hypergeometric_motive.py | 1 + src/sage/modular/local_comp/local_comp.py | 9 +++ src/sage/modular/local_comp/smoothchar.py | 2 + src/sage/modular/local_comp/type_space.py | 9 +-- src/sage/modular/modform/ambient_R.py | 1 + src/sage/modular/modform/ambient_eps.py | 1 + src/sage/modular/modform/constructor.py | 11 ++-- .../modular/modform/cuspidal_submodule.py | 15 +++-- src/sage/modular/modform/eis_series.py | 19 +++---- .../modular/modform/eisenstein_submodule.py | 11 ++-- src/sage/modular/modform/half_integral.py | 1 + .../modular/modform/hecke_operator_on_qexp.py | 1 + src/sage/modular/modform/j_invariant.py | 1 + src/sage/modular/modform/numerical.py | 8 ++- src/sage/modular/modform/ring.py | 7 ++- src/sage/modular/modform/space.py | 8 +-- src/sage/modular/modform/theta.py | 2 + src/sage/modular/modform/vm_basis.py | 50 ++++++++--------- src/sage/modular/modform/weight1.py | 4 ++ .../modform_hecketriangle/constructor.py | 26 ++++----- .../hecke_triangle_group_element.py | 56 +++++++++---------- .../modular/overconvergent/hecke_series.py | 14 +++++ .../modular/overconvergent/weightspace.py | 2 + src/sage/modular/pollack_stevens/modsym.py | 1 + src/sage/modular/pollack_stevens/sigma0.py | 1 + src/sage/modular/quasimodform/element.py | 7 ++- 38 files changed, 213 insertions(+), 136 deletions(-) diff --git a/src/sage/modular/abvar/constructor.py b/src/sage/modular/abvar/constructor.py index 78e160edfe6..53561063eaa 100644 --- a/src/sage/modular/abvar/constructor.py +++ b/src/sage/modular/abvar/constructor.py @@ -23,6 +23,7 @@ _cache = {} + def _get(key): """ Return the cached abelian variety with given key. This is used @@ -49,6 +50,7 @@ def _get(key): return z raise ValueError("element not in cache") + def _saved(key, J): """ Return the cached abelian variety with given key. This is used @@ -95,6 +97,7 @@ def J0(N): J = Gamma0(N).modular_abelian_variety() return _saved(key, J) + def J1(N): """ Return the Jacobian `J_1(N)` of the modular curve @@ -112,6 +115,7 @@ def J1(N): from sage.modular.arithgroup.all import Gamma1 return _saved(key, Gamma1(N).modular_abelian_variety()) + def JH(N, H): """ Return the Jacobian `J_H(N)` of the modular curve @@ -129,6 +133,7 @@ def JH(N, H): from sage.modular.arithgroup.all import GammaH return _saved(key, GammaH(N, H).modular_abelian_variety()) + def AbelianVariety(X): """ Create the abelian variety corresponding to the given defining diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index c50a2b109f8..7a0921076d9 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -59,15 +59,15 @@ True """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.matrix.constructor import matrix from sage.modular.arithgroup.all import Gamma0_class diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 347e45fa418..cfaf762eae2 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -88,15 +88,15 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.rings.abc diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index 516acf5f7fd..84ee1abe795 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -79,15 +79,15 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import divisors, gcd from sage.misc.misc_c import prod diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 3431dfcac5c..388cabfeed1 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -124,6 +124,7 @@ Lmi = SL2Z([1,-1,0,1]) # the inverse of Lm in SL(2,Z) Rmi = SL2Z([1,0,-1,1]) # the inverse of Rm in SL(2,Z) + def sl2z_word_problem(A): r""" Given an element of `\SL_2(\ZZ)`, express it as a word in the generators L = @@ -151,7 +152,7 @@ def sl2z_word_problem(A): output = [] # If A00 is zero - if A[0,0] == 0: + if A[0, 0] == 0: c = A[1,1] if c != 1: A = A*Lm**(c-1)*Rm*Lmi @@ -160,12 +161,12 @@ def sl2z_word_problem(A): A = A*Rm*Lmi output.extend([(1,-1),(0,1)]) - if A[0,0] < 0: # Make sure A00 is positive + if A[0, 0] < 0: # Make sure A00 is positive A = SL2Z(-1)*A output.extend([(1,-1), (0,1), (1,-1), (0,1), (1,-1), (0,1)]) if A[0,1] < 0: # if A01 is negative make it positive - n = (-A[0,1]/A[0,0]).ceil() #n s.t. 0 <= A[0,1]+n*A[0,0] < A[0,0] + n = (-A[0,1]/A[0,0]).ceil() # n s.t. 0 <= A[0,1]+n*A[0,0] < A[0,0] A = A*Lm**n output.append((0, -n)) # At this point A00>0 and A01>=0 @@ -180,10 +181,10 @@ def sl2z_word_problem(A): A = A*SL2Z([1,-n,0,1]) output.append((0, n)) - if A == SL2Z(1): + if A == SL2Z.one(): pass # done, so don't add R^0 - elif A[0,0] == 0: - c = A[1,1] + elif A[0, 0] == 0: + c = A[1, 1] if c != 1: A = A*Lm**(c-1)*Rm*Lmi output.extend([(0,1-c),(1,-1),(0, 1)]) @@ -199,6 +200,7 @@ def sl2z_word_problem(A): output.reverse() return output + def eval_sl2z_word(w): r""" Given a word in the format output by :func:`sl2z_word_problem`, convert it back @@ -216,6 +218,7 @@ def eval_sl2z_word(w): w1 = w return w0 * prod((mat[a[0]]**a[1] for a in w1), Idm) + def word_of_perms(w, p1, p2): r""" Given a word `w` as a list of 2-tuples ``(index,power)`` and permutations @@ -260,6 +263,7 @@ def word_of_perms(w, p1, p2): return M + def _equalize_perms(l): r""" Transform a list of lists into a list of lists with identical length. Each @@ -286,6 +290,7 @@ def _equalize_perms(l): # interpreted as L and R. Hence the order of the arguments is slightly # different from the class __init__ methods. + def ArithmeticSubgroup_Permutation( L=None, R=None, S2=None, S3=None, relabel=False, @@ -454,6 +459,7 @@ def ArithmeticSubgroup_Permutation( return G + class ArithmeticSubgroup_Permutation_class(ArithmeticSubgroup): r""" A subgroup of `\SL_2(\ZZ)` defined by the action of generators on its @@ -1484,7 +1490,7 @@ def is_congruence(self): r = R**d s = l**20 * r**onefifth * l**(-4) * ~r - #Congruence if the seven permutations below are trivial: + # Congruence if the seven permutations below are trivial: rel = ~a*~r*a*r if not rel.is_one(): verbose("Failed relation B1") @@ -1853,6 +1859,7 @@ def ncusps(self): m += 1 return n + m//2 + class EvenArithmeticSubgroup_Permutation(ArithmeticSubgroup_Permutation_class): r""" An arithmetic subgroup of `\SL(2, \ZZ)` containing `-1`, represented diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index 2eec9b267ac..78d878aaf9d 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -2,13 +2,13 @@ Congruence subgroup `\Gamma(N)` """ -#***************************************************************************** +# **************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import gcd from sage.groups.matrix_gps.finitely_generated import MatrixGroup @@ -26,6 +26,8 @@ _gamma_cache = {} + + def Gamma_constructor(N): r""" Return the congruence subgroup `\Gamma(N)`. diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index a01c1dd1683..ca0d050fe6f 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -8,8 +8,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import kronecker_symbol, divisors, euler_phi, gcd, moebius from sage.misc.cachefunc import cached_method @@ -47,6 +47,8 @@ def is_Gamma0(x): _gamma0_cache = {} + + def Gamma0_constructor(N): """ Return the congruence subgroup Gamma0(N). @@ -143,7 +145,7 @@ def __init__(self, level): # be done if needed by the _generators_for_H and _list_of_elements_in_H # methods. # - #GammaH_class.__init__(self, level, [int(x) for x in IntegerModRing(level).unit_gens()]) + # GammaH_class.__init__(self, level, [int(x) for x in IntegerModRing(level).unit_gens()]) def _repr_(self): """ diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index 18a1c8c0950..c450d98a783 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -3,13 +3,13 @@ Congruence subgroup `\Gamma_1(N)` """ -#***************************************************************************** +# **************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method @@ -44,13 +44,14 @@ def is_Gamma1(x): """ from sage.misc.superseded import deprecation deprecation(38035, "The function is_Gamma1 is deprecated; use 'isinstance(..., Gamma1_class)' instead.") - #from congroup_sl2z import is_SL2Z - #return (isinstance(x, Gamma1_class) or is_SL2Z(x)) + # from congroup_sl2z import is_SL2Z + # return (isinstance(x, Gamma1_class) or is_SL2Z(x)) return isinstance(x, Gamma1_class) _gamma1_cache = {} + def Gamma1_constructor(N): r""" Return the congruence subgroup `\Gamma_1(N)`. @@ -487,7 +488,7 @@ def dimension_cusp_forms(self, k=2, eps=None, algorithm='CohenOesterle'): from sage.modular.dims import CohenOesterle return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) ) - else: #algorithm not in ["CohenOesterle", "Quer"]: + else: # algorithm not in ["CohenOesterle", "Quer"]: raise ValueError("Unrecognised algorithm in dimension_cusp_forms") def dimension_eis(self, k=2, eps=None, algorithm='CohenOesterle'): @@ -573,7 +574,7 @@ def dimension_eis(self, k=2, eps=None, algorithm='CohenOesterle'): else: return alpha - self.dimension_cusp_forms(k, eps) - else: #algorithm not in ["CohenOesterle", "Quer"]: + else: # algorithm not in ["CohenOesterle", "Quer"]: raise ValueError("Unrecognised algorithm in dimension_eis") def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm='CohenOesterle'): diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 507418bd239..41a09602a88 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -432,6 +432,7 @@ def image_mod_n(self): """ return self.__G + class CongruenceSubgroup(CongruenceSubgroupFromGroup): r""" One of the "standard" congruence subgroups `\Gamma_0(N)`, `\Gamma_1(N)`, @@ -569,6 +570,7 @@ def _new_group_from_level(self, level): else: raise NotImplementedError + def _minimize_level(G): r""" Utility function. Given a matrix group `G` contained in `SL(2, \ZZ / N\ZZ)` diff --git a/src/sage/modular/arithgroup/congroup_sl2z.py b/src/sage/modular/arithgroup/congroup_sl2z.py index 7e15eaca383..d95c9e18764 100644 --- a/src/sage/modular/arithgroup/congroup_sl2z.py +++ b/src/sage/modular/arithgroup/congroup_sl2z.py @@ -46,6 +46,7 @@ def is_SL2Z(x): deprecation(38035, "The function is_SL2Z is deprecated; use 'isinstance(..., SL2Z_class)' instead.") return isinstance(x, SL2Z_class) + class SL2Z_class(Gamma0_class): r""" The full modular group `\SL_2(\ZZ)`, regarded as a congruence @@ -250,6 +251,7 @@ def random_element(self, bound=100, *args, **kwds): SL2Z = SL2Z_class() + def _SL2Z_ref(): """ Return SL2Z. (Used for pickling SL2Z.). diff --git a/src/sage/modular/drinfeld_modform/element.py b/src/sage/modular/drinfeld_modform/element.py index dd6d48ad99e..59d7a9e23ff 100644 --- a/src/sage/modular/drinfeld_modform/element.py +++ b/src/sage/modular/drinfeld_modform/element.py @@ -25,6 +25,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial import MPolynomial + class DrinfeldModularFormsElement(ModuleElement): r""" Element class of rings of Drinfeld modular forms. diff --git a/src/sage/modular/drinfeld_modform/ring.py b/src/sage/modular/drinfeld_modform/ring.py index c113523fc48..a0e03ea017b 100644 --- a/src/sage/modular/drinfeld_modform/ring.py +++ b/src/sage/modular/drinfeld_modform/ring.py @@ -44,6 +44,7 @@ from .element import DrinfeldModularFormsElement + class DrinfeldModularForms(Parent, UniqueRepresentation): r""" Base class for the graded ring of Drinfeld modular forms. diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 32c7c88c0cf..5418a1fff58 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -187,6 +187,7 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign, deg=None, use_f data[k] = sign * coeffs[d - k] * q**(i * (k - d / 2)) return ring(data) + def enumerate_hypergeometric_data(d, weight=None): r""" Return an iterator over parameters of hypergeometric motives (up to swapping). diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index 029dcc822b0..04d9123ab57 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -37,6 +37,7 @@ from .type_space import TypeSpace from .smoothchar import SmoothCharacterGroupQp, SmoothCharacterGroupUnramifiedQuadratic, SmoothCharacterGroupRamifiedQuadratic + def LocalComponent(f, p, twist_factor=None): r""" Calculate the local component at the prime `p` of the automorphic @@ -115,6 +116,7 @@ def LocalComponent(f, p, twist_factor=None): mintwist = LocalComponent(g, p, twist_factor) return ImprimitiveLocalComponent(f, p, twist_factor, mintwist, chi) + class LocalComponentBase(SageObject): r""" Base class for local components of newforms. Not to be directly instantiated; use the :func:`~LocalComponent` constructor function. @@ -316,6 +318,7 @@ def __ne__(self, other): """ return not (self == other) + class PrimitiveLocalComponent(LocalComponentBase): r""" Base class for primitive (twist-minimal) local components. @@ -346,6 +349,7 @@ def minimal_twist(self): """ return self + class PrincipalSeries(PrimitiveLocalComponent): r""" A principal series representation. This is an abstract base class, not to @@ -399,6 +403,7 @@ def characters(self): """ pass + class UnramifiedPrincipalSeries(PrincipalSeries): r""" An unramified principal series representation of `{\rm GL}_2(\QQ_p)` @@ -469,6 +474,7 @@ def characters(self): G = SmoothCharacterGroupQp(self.prime(), d.parent()) return Sequence([G.character(0, [d]), G.character(0, [self.newform()[self.prime()] - d])], cr=True, universe=G) + class PrimitivePrincipalSeries(PrincipalSeries): r""" A ramified principal series of the form `\pi(\chi_1, \chi_2)` @@ -500,6 +506,7 @@ def characters(self): chi2 = G.character(0, [self.prime()]) * self.central_character() / chi1 return Sequence([chi1, chi2], cr=True, universe=G) + class PrimitiveSpecial(PrimitiveLocalComponent): r""" A primitive special representation: that is, the Steinberg representation @@ -586,6 +593,7 @@ def check_tempered(self): for sigma in K.embeddings(QQbar): assert sigma(c1(p)).abs() == w + class PrimitiveSupercuspidal(PrimitiveLocalComponent): r""" A primitive supercuspidal representation. @@ -971,6 +979,7 @@ def check_tempered(self): for sigma in K.embeddings(QQbar): assert sigma(c1(p)).abs() == sigma(c2(p)).abs() == w + class ImprimitiveLocalComponent(LocalComponentBase): r""" A smooth representation which is not of minimal level among its character diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 1a05d448d9b..e2cadd4219a 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -1103,6 +1103,7 @@ def quadratic_chars(self): nr = self.character(0, [-1]) return sorted([nr] + list(ram) + [f*nr for f in ram]) + class SmoothCharacterGroupQuadratic(SmoothCharacterGroupGeneric): r""" The group of smooth characters of `E^\times`, where `E` is a quadratic extension of `\QQ_p`. @@ -1391,6 +1392,7 @@ def extend_character(self, level, chi, vals, check=True): raise ValueError("Invalid values for extension") return chiE + class SmoothCharacterGroupUnramifiedQuadratic(SmoothCharacterGroupQuadratic): r""" The group of smooth characters of `\QQ_{p^2}^\times`, where `\QQ_{p^2}` is diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 9e20c121108..ea43ec89ccf 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -62,6 +62,7 @@ def example_type_space(example_no=0): # a ramified (odd p-power level) case return TypeSpace(Newform_constructor('27a'), 3) + def find_in_space(f, A, base_extend=False): r""" Given a Newform object `f`, and a space `A` of modular symbols of the same @@ -147,6 +148,7 @@ def find_in_space(f, A, base_extend=False): return D + class TypeSpace(SageObject): r""" The modular symbol type space associated to a newform, at a prime dividing @@ -401,12 +403,11 @@ def minimal_twist(self): V = A.submodule(VV, check=False) D = V.decomposition()[0] - #if len(D.star_eigenvalues()) == 2: + # if len(D.star_eigenvalues()) == 2: # D = D.sign_submodule(1) D1 = D.modular_symbols_of_sign(1) M = ModularForms(D1.group(), D1.weight(), D1.base_ring()) - ff = Newform(M, D1, names='a') - return ff + return Newform(M, D1, names='a') ##################################### # The group action on the type space. @@ -634,7 +635,7 @@ def _discover_torus_action(self): mats = self._intertwining_basis(a) V = self.t_space.nonembedded_free_module() v = self.eigensymbol_subspace().gen(0) - w = V.submodule_with_basis([m * v for m in mats]).coordinates(v) #v * self.e_space.diamond_eigenvalue(crt(a, 1, f, self.tame_level()))) + w = V.submodule_with_basis([m * v for m in mats]).coordinates(v) # v * self.e_space.diamond_eigenvalue(crt(a, 1, f, self.tame_level()))) self._a = a self._amat = sum([mats[i] * w[i] for i in range(len(mats))]) diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index fcf8a598721..c07597e25dc 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -16,6 +16,7 @@ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method + class ModularFormsAmbient_R(ambient.ModularFormsAmbient): def __init__(self, M, base_ring): """ diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index cf2ab2b9db5..ddd4ed467bc 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -94,6 +94,7 @@ from . import cuspidal_submodule from . import eisenstein_submodule + class ModularFormsAmbient_eps(ModularFormsAmbient): """ A space of modular forms with character. diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 30a264905bc..ffe19d3d708 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -19,15 +19,15 @@ ] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import weakref import re @@ -94,13 +94,13 @@ def canonical_parameters(group, level, weight, base_ring): raise NotImplementedError("weight must be at least 1") if isinstance(group, dirichlet.DirichletCharacter): - if ( group.level() != Integer(level) ): + if group.level() != Integer(level): raise ValueError("group.level() and level do not match.") group = group.minimize_base_ring() level = Integer(level) elif isinstance(group, arithgroup.CongruenceSubgroupBase): - if ( Integer(level) != group.level() ): + if Integer(level) != group.level(): raise ValueError("group.level() and level do not match.") # normalize the case of SL2Z if isinstance(group, arithgroup.SL2Z_class) or \ @@ -132,6 +132,7 @@ def canonical_parameters(group, level, weight, base_ring): _cache = {} + def ModularForms_clear_cache(): """ Clear the cache of modular forms. diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index 2f5a94cbf58..5de0805b386 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -52,6 +52,7 @@ from .submodule import ModularFormsSubmodule from . import weight1 + class CuspidalSubmodule(ModularFormsSubmodule): """ Base class for cuspidal submodules of ambient spaces of modular forms. @@ -211,6 +212,7 @@ def change_ring(self, R): """ return self.ambient_module().change_ring(R).cuspidal_submodule() + class CuspidalSubmodule_R(CuspidalSubmodule): """ Cuspidal submodule over a non-minimal base ring. @@ -626,11 +628,13 @@ def _compute_diamond_matrix(self, d): symbs = self.modular_symbols(sign=1) return _convert_matrix_from_modsyms(symbs, symbs.diamond_bracket_matrix(d))[0] + class CuspidalSubmodule_g1_Q(CuspidalSubmodule_gH_Q): r""" Space of cusp forms for `\Gamma_1(N)` over `\QQ`. """ + class CuspidalSubmodule_eps(CuspidalSubmodule_modsym_qexp): """ Space of cusp forms with given Dirichlet character. @@ -659,6 +663,7 @@ class CuspidalSubmodule_eps(CuspidalSubmodule_modsym_qexp): """ pass + def _convert_matrix_from_modsyms(symbs, T): r""" Given a space of modular symbols and a matrix T acting on it, calculate the @@ -694,17 +699,19 @@ def _convert_matrix_from_modsyms(symbs, T): # we repeatedly use these matrices below, so we store them # once as lists to save time. - hecke_matrix_ls = [ symbs.hecke_matrix(m).list() for m in range(1,r+1) ] - hecke_image_ls = [ (T*symbs.hecke_matrix(m)).list() for m in range(1,r+1) ] + hecke_matrix_ls = [symbs.hecke_matrix(m).list() + for m in range(1, r + 1)] + hecke_image_ls = [(T * symbs.hecke_matrix(m)).list() + for m in range(1, r + 1)] # compute the q-expansions of some cusp forms and their # images under T_n for i in range(d**2): - v = X([ hecke_matrix_ls[m][i] for m in range(r) ]) + v = X([hecke_matrix_ls[m][i] for m in range(r)]) Ynew = Y.span(Y.basis() + [v]) if Ynew.rank() > Y.rank(): basis.append(v) - basis_images.append(X([ hecke_image_ls[m][i] for m in range(r) ])) + basis_images.append(X([hecke_image_ls[m][i] for m in range(r)])) Y = Ynew if len(basis) == d: break diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index dbdf09d6512..73ea6dcaf1c 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -159,7 +159,7 @@ def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): E._unsafe_mutate(0, a0) return R(E, prec) # The following is an older slower alternative to the above three lines: - #return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=False) + # return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=False) else: # This used to work with check=False, but that can only be regarded as # an improbable lucky miracle. Enabling checking is a noticeable speed @@ -170,6 +170,7 @@ def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): else: return R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True) + def __common_minimal_basering(chi, psi): """ Find the smallest basering over which chi and psi are valued, and @@ -279,7 +280,7 @@ def __find_eisen_chars(character, k): if L not in C: continue GL = C[L] - for R in divisors(N/L): + for R in divisors(N // L): if R not in C: continue GR = C[R] @@ -288,8 +289,8 @@ def __find_eisen_chars(character, k): if chi*psi == eps: chi0, psi0 = __common_minimal_basering(chi, psi) for t in divisors(N//(R*L)): - if k != 1 or ((psi0, chi0, t) not in params): - params.append( (chi0,psi0,t) ) + if k != 1 or (psi0, chi0, t) not in params: + params.append((chi0, psi0, t)) return params @@ -365,8 +366,6 @@ def __find_eisen_chars_gamma1(N, k): pairs.append((psi, chi)) else: pairs.append((chi, psi)) - #end fors - #end if triples = [] for chi, psi in pairs: @@ -376,14 +375,14 @@ def __find_eisen_chars_gamma1(N, k): if k == 2 and chi.is_trivial() and psi.is_trivial(): D.remove(1) chi, psi = __common_minimal_basering(chi, psi) - for t in D: - triples.append((chi, psi, t)) + triples.extend((chi, psi, t) for t in D) + return triples def eisenstein_series_lseries(weight, prec=53, - max_imaginary_part=0, - max_asymp_coeffs=40): + max_imaginary_part=0, + max_asymp_coeffs=40): r""" Return the `L`-series of the weight `2k` Eisenstein series on `\SL_2(\ZZ)`. diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index 2110ccf695f..fbbe2e06da3 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -119,6 +119,7 @@ def modular_symbols(self, sign=0): A = self.ambient_module() return A.modular_symbols(sign).eisenstein_submodule() + class EisensteinSubmodule_params(EisensteinSubmodule): @cached_method @@ -586,9 +587,9 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): ] """ # TODO - #def _compute_q_expansion_basis(self, prec): - #B = EisensteinSubmodule_params._compute_q_expansion_basis(self, prec) - #raise NotImplementedError, "must restrict scalars down correctly." + # def _compute_q_expansion_basis(self, prec): + # B = EisensteinSubmodule_params._compute_q_expansion_basis(self, prec) + # raise NotImplementedError("must restrict scalars down correctly.") def cyclotomic_restriction(L, K): @@ -667,8 +668,8 @@ def cyclotomic_restriction_tower(L, K): f = L.defining_polynomial() R = K['x'] g = R(f) - h_ls = [ t[0] for t in g.factor() if t[0](L.gen(0)) == 0 ] - if len(h_ls) == 0: + h_ls = [t[0] for t in g.factor() if t[0](L.gen(0)) == 0] + if not h_ls: raise ValueError(r"K (= Q(\zeta_%s)) is not contained in L (= Q(\zeta_%s))" % (K._n(), L._n())) h = h_ls[0] diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 801e3715e21..49e205cafab 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -16,6 +16,7 @@ from .theta import theta2_qexp, theta_qexp from copy import copy + def half_integral_weight_modform_basis(chi, k, prec): r""" A basis for the space of weight `k/2` forms with character diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 7191b52abfd..346a073f20a 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -26,6 +26,7 @@ from sage.modular.dirichlet import DirichletGroup, DirichletCharacter from .element import ModularFormElement + def hecke_operator_on_qexp(f, n, k, eps=None, prec=None, check=True, _return_list=False): r""" diff --git a/src/sage/modular/modform/j_invariant.py b/src/sage/modular/modform/j_invariant.py index 48b7c91fcb0..a74d42b91b2 100644 --- a/src/sage/modular/modform/j_invariant.py +++ b/src/sage/modular/modform/j_invariant.py @@ -6,6 +6,7 @@ from .vm_basis import delta_qexp from sage.rings.rational_field import QQ + def j_invariant_qexp(prec=10, K=QQ): r""" Return the `q`-expansion of the `j`-invariant to diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 253047b2eab..dd14ff15995 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -3,15 +3,15 @@ Numerical computation of newforms """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.fast_arith import prime_range from sage.matrix.constructor import matrix @@ -31,6 +31,7 @@ # This variable controls importing the SciPy library sparingly scipy = None + @richcmp_method class NumericalEigenforms(SageObject): """ @@ -488,6 +489,7 @@ def systems_of_abs(self, bound): v.set_immutable() return v + def support(v, eps): """ Given a vector `v` and a threshold eps, return all diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index bf4457d7748..dacfda54bae 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -10,7 +10,7 @@ - William Stein (2007-08-24): first version - David Ayotte (2021-06): implemented category and Parent/Element frameworks """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # 2021 David Ayotte # @@ -18,8 +18,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from random import shuffle @@ -143,6 +143,7 @@ def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=Fals verbose('span has dimension %s' % W.rank(), t) return W + @richcmp_method class ModularFormsRing(Parent): r""" diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 87d96b21356..202ea687953 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1698,15 +1698,15 @@ def newforms(self, names=None): """ M = self.modular_symbols(sign=1) factors = M.cuspidal_subspace().new_subspace().decomposition() - large_dims = [ X.dimension() for X in factors if X.dimension() != 1 ] - if len(large_dims) > 0 and names is None: + large_dims = [X.dimension() for X in factors if X.dimension() != 1] + if large_dims and names is None: raise ValueError("Please specify a name to be used when generating names for generators of Hecke eigenvalue fields corresponding to the newforms.") elif names is None: # In this case, we don't need a variable name, so insert # something to get passed along below names = 'a' - return [ Newform(self, factors[i], names=(names+str(i)) ) - for i in range(len(factors)) ] + return [Newform(self, factors[i], names=names + str(i)) + for i in range(len(factors))] @cached_method def eisenstein_submodule(self): diff --git a/src/sage/modular/modform/theta.py b/src/sage/modular/modform/theta.py index 92c5f945a1c..fbe34473f98 100644 --- a/src/sage/modular/modform/theta.py +++ b/src/sage/modular/modform/theta.py @@ -11,6 +11,7 @@ from math import sqrt + def theta2_qexp(prec=10, var='q', K=ZZ, sparse=False): r""" Return the `q`-expansion of the series `\theta_2 = \sum_{n \text{ odd}} q^{n^2}`. @@ -58,6 +59,7 @@ def theta2_qexp(prec=10, var='q', K=ZZ, sparse=False): R = PowerSeriesRing(K, sparse=sparse, names=var) return R(v, prec=prec) + def theta_qexp(prec=10, var='q', K=ZZ, sparse=False): r""" Return the `q`-expansion of the standard `\theta` series diff --git a/src/sage/modular/modform/vm_basis.py b/src/sage/modular/modform/vm_basis.py index bbbbd9b4513..58f36fd0f1a 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -19,14 +19,14 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import math @@ -156,22 +156,22 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): ls[i] = err return Sequence(ls, cr=True) - F6 = eisenstein_series_poly(6,prec) + F6 = eisenstein_series_poly(6, prec) if e == 0: A = Fmpz_poly(1) elif e == 4: - A = eisenstein_series_poly(4,prec) + A = eisenstein_series_poly(4, prec) elif e == 6: A = F6 elif e == 8: - A = eisenstein_series_poly(8,prec) + A = eisenstein_series_poly(8, prec) elif e == 10: - A = eisenstein_series_poly(10,prec) - else: # e == 14 - A = eisenstein_series_poly(14,prec) + A = eisenstein_series_poly(10, prec) + else: # e == 14 + A = eisenstein_series_poly(14, prec) - if A[0] == -1 : + if A[0] == -1: A = -A if n == 0: @@ -186,9 +186,9 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): if cusp_only: ls = [Fmpz_poly(0)] + [A] * n else: - ls = [A] * (n+1) + ls = [A] * (n + 1) - for i in range(1,n+1): + for i in range(1, n + 1): ls[n-i] *= Fprod ls[i] *= Dprod ls[n-i]._unsafe_mutate_truncate(prec) @@ -201,17 +201,17 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): P = PowerSeriesRing(ZZ, var) if cusp_only: - for i in range(1,n+1) : - for j in range(1, i) : + for i in range(1, n + 1): + for j in range(1, i): ls[j] = ls[j] - ls[j][i]*ls[i] - return Sequence([P(l.list()).add_bigoh(prec) for l in ls[1:]],cr=True) - else : - for i in range(1,n+1): - for j in range(i): - ls[j] = ls[j] - ls[j][i]*ls[i] + return Sequence([P(l.list()).add_bigoh(prec) for l in ls[1:]], cr=True) + + for i in range(1, n + 1): + for j in range(i): + ls[j] = ls[j] - ls[j][i] * ls[i] - return Sequence([P(l.list()).add_bigoh(prec) for l in ls], cr=True) + return Sequence([P(l.list()).add_bigoh(prec) for l in ls], cr=True) def _delta_poly(prec=10): @@ -284,9 +284,9 @@ def _delta_poly_modulo(N, prec=10): OUTPUT: - the polynomial of degree ``prec``-1 which is the truncation - of `\Delta` modulo `N`, as an element of the polynomial - ring in `q` over the integers modulo `N`. + the polynomial of degree ``prec``-1 which is the truncation + of `\Delta` modulo `N`, as an element of the polynomial + ring in `q` over the integers modulo `N`. EXAMPLES:: @@ -297,7 +297,7 @@ def _delta_poly_modulo(N, prec=10): 2*q^11 + 7*q^9 + 6*q^7 + 2*q^6 + 8*q^4 + 2*q^3 + 6*q^2 + q """ if prec <= 0: - raise ValueError( "prec must be positive" ) + raise ValueError("prec must be positive") v = [0] * prec # Let F = \sum_{n >= 0} (-1)^n (2n+1) q^(floor(n(n+1)/2)). @@ -324,7 +324,7 @@ def _delta_poly_modulo(N, prec=10): return f -def delta_qexp(prec=10, var='q', K=ZZ) : +def delta_qexp(prec=10, var='q', K=ZZ): r""" Return the `q`-expansion of the weight 12 cusp form `\Delta` as a power series with coefficients in the ring K (`= \ZZ` by default). diff --git a/src/sage/modular/modform/weight1.py b/src/sage/modular/modform/weight1.py index a2f5aa10108..9aa75074676 100644 --- a/src/sage/modular/modform/weight1.py +++ b/src/sage/modular/modform/weight1.py @@ -20,6 +20,7 @@ from sage.modular.arithgroup.all import Gamma0, GammaH from sage.modular.arithgroup.arithgroup_generic import ArithmeticSubgroup + @cached_function def modular_ratio_space(chi): r""" @@ -100,6 +101,7 @@ def modular_ratio_to_prec(chi, qexp, prec): fB_elt = C(fB, check=False) return fB_elt.qexp(prec) / B + @cached_function def hecke_stable_subspace(chi, aux_prime=ZZ(2)): r""" @@ -187,6 +189,7 @@ def hecke_stable_subspace(chi, aux_prime=ZZ(2)): qexps = Sequence(A(x.list()).add_bigoh(R) for x in J.gens()) return qexps + @cached_function def dimension_wt1_cusp_forms(chi): r""" @@ -200,6 +203,7 @@ def dimension_wt1_cusp_forms(chi): """ return len(hecke_stable_subspace(chi)) + @cached_function def dimension_wt1_cusp_forms_gH(group): r""" diff --git a/src/sage/modular/modform_hecketriangle/constructor.py b/src/sage/modular/modform_hecketriangle/constructor.py index e245e1d2394..e3525879e6e 100644 --- a/src/sage/modular/modform_hecketriangle/constructor.py +++ b/src/sage/modular/modform_hecketriangle/constructor.py @@ -117,11 +117,11 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): analytic_type = AT(["quasi", "mero"]) - R = PolynomialRing(base_ring,'x,y,z,d') + R = PolynomialRing(base_ring, 'x,y,z,d') F = FractionField(R) - (x,y,z,d) = R.gens() + x, y, z, d = R.gens() R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') - dhom = R.hom( R2.gens() + (R2.base().gen(),), R2) + dhom = R.hom(R2.gens() + (R2.base().gen(),), R2) f = F(f) @@ -131,12 +131,12 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): ep_denom = {ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()} if (n == infinity): - hom_num = R( num.subs(x=x**4, y=y**2, z=z**2) ) - hom_denom = R( denom.subs(x=x**4, y=y**2, z=z**2) ) + hom_num = R(num.subs(x=x**4, y=y**2, z=z**2)) + hom_denom = R(denom.subs(x=x**4, y=y**2, z=z**2)) else: n = ZZ(n) - hom_num = R( num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) - hom_denom = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) ) + hom_num = R(num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2)))) + hom_denom = R(denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2)))) # Determine whether the denominator of f is homogeneous if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): @@ -146,9 +146,9 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): return (False, False, None, None, None) # Determine whether f is homogeneous - if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()): + if len(ep_num) == 1 and dhom(hom_num).is_homogeneous(): homo = True - if (n == infinity): + if n == infinity: weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) else: weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2) @@ -160,17 +160,17 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): ep = None # Note that we intentionally leave out the d-factor! - if (n == infinity): + if n == infinity: finf_pol = (x-y**2) else: finf_pol = x**n-y**2 # Determine whether f is modular - if not ( (num.degree(z) > 0) or (denom.degree(z) > 0) ): + if not (num.degree(z) > 0 or denom.degree(z) > 0): analytic_type = analytic_type.reduce_to("mero") # Determine whether f is holomorphic - if (dhom(denom).is_constant()): + if dhom(denom).is_constant(): analytic_type = analytic_type.reduce_to(["quasi", "holo"]) # Determine whether f is cuspidal in the sense that finf divides it... # Bug in singular: finf_pol.divides(1.0) fails over RR @@ -180,7 +180,7 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): else: # -> Because of a bug with singular in some cases try: - while (finf_pol.divides(denom)): + while finf_pol.divides(denom): # a simple "denom /= finf_pol" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(finf_pol)[0] diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index df9568bb2ab..e7c56fd0e94 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -25,11 +25,11 @@ from sage.rings.infinity import infinity from sage.rings.cc import CC -lazy_import('sage.rings.qqbar', 'AA') - from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane +lazy_import('sage.rings.qqbar', 'AA') + # We want to simplify p after the coercion (pari bug for AA) def coerce_AA(p): @@ -51,7 +51,7 @@ def coerce_AA(p): """ el = AA(p) el.simplify() - #el.exactify() + # el.exactify() return el @@ -221,13 +221,13 @@ def _word_S_T_data(self): half = one / ZZ(2) while True: - a,b,c,d = M.list() + a, b, c, d = M.list() mshift = coerce_AA((4*a*c + b*d) / (4*c*c + d*d)) m = (mshift / lam + half).floor() if m != zero: res.append((one, m),) M = T**(-m) * M - a,b,c,d = M.list() + a, b, c, d = M.list() abs_t = coerce_AA((4*a*a + b*b) / (4*c*c + d*d)) if coerce_AA(abs_t) < 1: @@ -452,7 +452,7 @@ def string_repr(self, method='default'): return "-1" if sgn < 0 else "1" Lstr = list(L) - for i,(v0,v1) in enumerate(Lstr): + for i, (v0, v1) in enumerate(Lstr): if v0 == 0: Lstr[i] = "S" elif v1 == 1: @@ -479,7 +479,7 @@ def string_repr(self, method='default'): if sgn < 0: repr_str = repr_str[1:] - #if self != R.inverse().acton(self): + # if self != R.inverse().acton(self): if R.is_identity(): repr_str = "{}{}".format("-" if sgn < 0 else "", repr_str) else: @@ -496,7 +496,7 @@ def string_repr(self, method='default'): (L, R, sgn) = self._block_decomposition_data() if self.is_elliptic(): - L = [ L ] + L = [L] repr_str = "" begin = True @@ -633,7 +633,7 @@ def continued_fraction(self): if p == infinity: # TODO: The choice of r doesn't matter? r = ZZ.zero() - #elif self.is_elliptic(): + # elif self.is_elliptic(): # r = ZZ(emb(p/lam).real().floor() + 1) else: emb_res = emb(p/lam) @@ -645,7 +645,7 @@ def continued_fraction(self): cf_index += one preperiod_len = cf_dict[p] - #period_len = cf_index - preperiod_len + # period_len = cf_index - preperiod_len return (tuple(L[:preperiod_len]), tuple(L[preperiod_len:])) @@ -807,7 +807,7 @@ def _primitive_block_decomposition_data(self): L = (one, one) else: raise RuntimeError("There is something wrong in the method " - "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") + "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") return (L, R) @@ -835,11 +835,11 @@ def _primitive_block_decomposition_data(self): initial_ones = number_of_ones.pop(0) if not list_larger: - list_v1 = [-ZZ(1)] - list_vlarger = [ initial_ones + 2 ] + list_v1 = [-ZZ.one()] + list_vlarger = [initial_ones + 2] else: - list_v1 = [ v-2 for v in list_larger ] - list_vlarger = [ v+2 for v in number_of_ones ] + list_v1 = [v - 2 for v in list_larger] + list_vlarger = [v + 2 for v in number_of_ones] list_vlarger[-1] += initial_ones L = [] @@ -1363,14 +1363,14 @@ def primitive_power(self, method='cf'): for j in range(1, G.n()): Uj *= U if U_power == Uj: - #L = [one, ZZ(j)] + # L = [one, ZZ(j)] break elif U_power == -Uj: - #L = [one, ZZ(-j)] + # L = [one, ZZ(-j)] break else: raise RuntimeError("There is a problem in the method " - "'primitive_power'. Please contact sage-devel@googlegroups.com") + "'primitive_power'. Please contact sage-devel@googlegroups.com") if abs(j) < G.n()/two: return j @@ -1514,7 +1514,7 @@ def block_length(self, primitive=False): else: return sum(abs(v[1]) for v in L) - #@cached_method + # @cached_method def _block_decomposition_data(self): r""" Return a tuple ``(L, R, sgn)`` which describes the @@ -1771,7 +1771,7 @@ def block_decomposition(self): P = G.U() return ((P**L[1],), R, sgn) else: - return (tuple(G.V(v[0])**v[1] for v in L ), R, sgn) + return (tuple(G.V(v[0])**v[1] for v in L), R, sgn) def conjugacy_type(self, ignore_sign=True, primitive=False): r""" @@ -2206,7 +2206,7 @@ def is_translation(self, exclude_one=False): sage: (-HeckeTriangleGroup(n=7).I()).is_translation(exclude_one=True) False """ - a,b,c,d = self._matrix.list() + a, b, c, d = self._matrix.list() if not (c.is_zero() and a == d and (a.is_one() or (-a).is_one())): return False @@ -2488,7 +2488,7 @@ def is_simple(self): return False # The last condition is/should be equivalent to: - a,b,c,d = self._matrix.list() + a, b, c, d = self._matrix.list() return (coerce_AA(a) > 0 and coerce_AA(b) > 0 and coerce_AA(c) > 0 and coerce_AA(d) > 0) def is_hecke_symmetric(self): @@ -2675,7 +2675,7 @@ def rational_period_function(self, k): if k % 2: raise TypeError except TypeError: - raise ValueError("k={} must be an even integer!".format(k)) + raise ValueError(f"k={k} must be an even integer!") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing P = PolynomialRing(self.parent().base_ring(), 'z') @@ -2683,14 +2683,14 @@ def rational_period_function(self, k): s = P.zero() - #L1 = [] + # L1 = [] for v in self.simple_elements(): - a,b,c,d = v._matrix.list() + a, b, c, d = v._matrix.list() Q = c*z**2 + (d - a)*z - b s += Q**(-k/ZZ(2)) for v in self.inverse().simple_elements(): - a,b,c,d = v._matrix.list() + a, b, c, d = v._matrix.list() Q = c*z**2 + (d - a)*z - b s -= ZZ(-1)**(k/ZZ(2)) * Q**(-k/ZZ(2)) @@ -3049,7 +3049,7 @@ def fixed_points(self, embedded=False, order='default'): else: e = self.root_extension_field().gen() - a,b,c,d = self._matrix.list() + a, b, c, d = self._matrix.list() if order == "none": sgn = ZZ(1) @@ -3170,7 +3170,7 @@ def acton(self, tau): model = tau.model() tau = tau.to_model('UHP').coordinates() - a,b,c,d = self._matrix.list() + a, b, c, d = self._matrix.list() if tau == infinity: if c.is_zero(): diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index fedf6160c50..0b1502d2d9a 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -87,6 +87,7 @@ # AUXILIARY CODE: SPACES OF MODULAR FORMS AND LINEAR ALGEBRA + def compute_G(p, F): r""" Given a power series `F \in R[[q]]^\times`, for some ring `R`, and an @@ -151,6 +152,7 @@ def low_weight_bases(N, p, m, NN, weightbound): generators.append(list(b)) return generators + def random_low_weight_bases(N,p,m,NN,weightbound): r""" Return list of random integral bases of modular forms of level `N` and @@ -194,6 +196,7 @@ def random_low_weight_bases(N,p,m,NN,weightbound): return RandomLWB + def low_weight_generators(N,p,m,NN): r""" Return a list of lists of modular forms, and an even natural number. @@ -244,6 +247,7 @@ def low_weight_generators(N,p,m,NN): return generators, weightbound + def random_solution(B,K): r""" Return a random solution in nonnegative integers to the equation `a_1 + 2 @@ -398,6 +402,7 @@ def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound): return NewBasisCode + def complementary_spaces_modp(N, p, k0, n, elldash, LWBModp, bound): r""" Return a list of lists of lists of lists ``[j, a]``. The pairs ``[j, a]`` @@ -446,6 +451,7 @@ def complementary_spaces_modp(N, p, k0, n, elldash, LWBModp, bound): return CompSpacesCode + def complementary_spaces(N, p, k0, n, mdash, elldashp, elldash, modformsring, bound): r""" Return a list ``Ws``, each element in which is a list ``Wi`` of @@ -523,6 +529,7 @@ def complementary_spaces(N, p, k0, n, mdash, elldashp, elldash, modformsring, bo # AUXILIARY CODE: KATZ EXPANSIONS + def higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, modformsring, bound): r""" Return a matrix `e` of size ``ell x elldashp`` over the integers modulo @@ -587,6 +594,7 @@ def higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, modformsring, b return M, Ep1 + def compute_elldash(p, N, k0, n): r""" Return the "Sturm bound" for the space of modular forms of level @@ -615,6 +623,7 @@ def compute_elldash(p, N, k0, n): # *** DEGREE BOUND ON HECKE SERIES *** + def hecke_series_degree_bound(p, N, k, m): r""" Return the ``Wan bound`` on the degree of the characteristic series of the @@ -659,6 +668,7 @@ def hecke_series_degree_bound(p, N, k, m): # Returns matrix A modulo p^m from Step 6 of Algorithm 2. + def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False): r""" Return a list ``[A_k]`` of square matrices over ``IntegerRing(p^m)`` @@ -874,6 +884,7 @@ def compute_Wi(k, p, h, hj, E4, E6): return Wi, hj + def katz_expansions(k0, p, ellp, mdash, n): r""" Return a list `e` of `q`-expansions, and the Eisenstein series `E_{p-1} = 1 + @@ -926,6 +937,7 @@ def katz_expansions(k0, p, ellp, mdash, n): # *** MAIN FUNCTION FOR LEVEL 1 *** + def level1_UpGj(p, klist, m, extra_data=False): r""" Return a list `[A_k]` of square matrices over ``IntegerRing(p^m)`` @@ -1038,6 +1050,7 @@ def level1_UpGj(p, klist, m, extra_data=False): # *** CODE FOR GENERAL LEVEL *** + def is_valid_weight_list(klist, p): r""" This function checks that ``klist`` is a nonempty list of integers all of @@ -1070,6 +1083,7 @@ def is_valid_weight_list(klist, p): if (klist[i] % (p-1)) != k0: raise ValueError("List of weights must be all congruent modulo p-1 = %s, but given list contains %s and %s which are not congruent" % (p - 1, klist[0], klist[i])) + def hecke_series(p, N, klist, m, modformsring=False, weightbound=6): r""" Return the characteristic series modulo `p^m` of the Atkin operator `U_p` diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index c159ac5eee3..40110016c52 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -85,6 +85,8 @@ _wscache = {} + + def WeightSpace_constructor(p, base_ring=None): r""" Construct the `p`-adic weight space for the given prime p. diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index c892748174d..8df8655e5e9 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -114,6 +114,7 @@ def _iterate_Up(Phi, p, M, ap, q, aq, check): Phi = ~(q ** (k + 1) + 1 - aq) * Phi return Phi + class PSModSymAction(Action): def __init__(self, actor, MSspace): r""" diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index c5ae3741f2f..2659f12cfa3 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -106,6 +106,7 @@ def __call__(self, g): """ return tuple(g.list()) + class Sigma0_factory(UniqueFactory): r""" Create the monoid of non-singular matrices, upper triangular mod `N`. diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 23b11fef749..c8bbdd1a9a3 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -31,6 +31,7 @@ from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.integer_ring import ZZ + class QuasiModularFormsElement(ModuleElement): r""" A quasimodular forms ring element. Such an element is described by @@ -142,11 +143,11 @@ def q_expansion(self, prec=6): sage: E2.q_expansion(prec=10) 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 - 288*q^6 - 192*q^7 - 360*q^8 - 312*q^9 + O(q^10) """ - E2 = eisenstein_series_qexp(2, prec=prec, K=self.base_ring(), normalization='constant') #normalization -> to force integer coefficients + E2 = eisenstein_series_qexp(2, prec=prec, K=self.base_ring(), normalization='constant') # normalization -> to force integer coefficients coefficients = self._polynomial.coefficients(sparse=False) - return sum(f.q_expansion(prec=prec)*E2**idx for idx, f in enumerate(coefficients)) + return sum(f.q_expansion(prec=prec) * E2**idx for idx, f in enumerate(coefficients)) - qexp = q_expansion # alias + qexp = q_expansion # alias def _repr_(self): r""" From 8fb2832ab804aa30ea244c3b8ad9c2688606e308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 29 Sep 2024 19:04:09 +0200 Subject: [PATCH 029/108] suggested details --- src/sage/knots/free_knotinfo_monoid.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/knots/free_knotinfo_monoid.py b/src/sage/knots/free_knotinfo_monoid.py index d1cedbc6d8c..47429712851 100644 --- a/src/sage/knots/free_knotinfo_monoid.py +++ b/src/sage/knots/free_knotinfo_monoid.py @@ -418,7 +418,7 @@ def from_knot(self, knot, unique=True): [KnotInfo['K4_1']*KnotInfo['K5_2'], KnotInfo['K9_12']] """ hp = knot.homfly_polynomial(normalization='vz') - num_summands = sum(e for f, e in hp.factor()) + num_summands = sum(e for _, e in hp.factor()) if num_summands == 1: return knot.get_knotinfo() @@ -427,14 +427,12 @@ def from_knot(self, knot, unique=True): if len(res) == 1: if unique: return res[0] - else: - return [res[0]] # to be consistent with get_knotinfo + return [res[0]] # to be consistent with get_knotinfo k = self._check_elements(knot, res) if k: if unique: return k - else: - return [k] # to be consistent with get_knotinfo + return [k] # to be consistent with get_knotinfo if res and not unique: return sorted(set(res)) From 4729f848c6d637b62b533de2722826a388810f8d Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 30 Sep 2024 10:02:55 +0200 Subject: [PATCH 030/108] allow ETuples as well --- .../polynomial/multi_polynomial_ring_base.pyx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 8b7845479cf..fb04c537702 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -26,7 +26,7 @@ from sage.rings.polynomial import polynomial_ring from sage.rings.polynomial.term_order import TermOrder from sage.rings.polynomial.polynomial_ring_constructor import (PolynomialRing, polynomial_default_category) - +from sage.rings.polynomial.polydict import ETuple def is_MPolynomialRing(x): from sage.misc.superseded import deprecation_cython @@ -617,7 +617,6 @@ cdef class MPolynomialRing_base(CommutativeRing): a dict with respect to ``self.variable_names()``. """ # This is probably horribly inefficient - from sage.rings.polynomial.polydict import ETuple other_vars = list(x.parent().variable_names()) name_mapping = [(other_vars.index(var) if var in other_vars else -1) for var in self.variable_names()] K = self.base_ring() @@ -1376,9 +1375,17 @@ cdef class MPolynomialRing_base(CommutativeRing): sage: R.monomial(e) x*y^2*z^3 + + TESTS: + + Check that ETuples also work:: + + sage: from sage.rings.polynomial.polydict import ETuple + sage: R.monomial(ETuple(e)) + x*y^2*z^3 """ - if len(exponents) == 1 and isinstance(exponents[0], tuple): - return self({exponents[0]: self.base_ring().one()}) + if len(exponents) == 1 and isinstance((e := exponents[0]), (tuple, ETuple)): + return self({e: self.base_ring().one()}) return self({exponents: self.base_ring().one()}) def monomials_of_degree(self, degree): From 9a37e277089c8f2e09fdf475f0a7583e300c55f1 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 30 Sep 2024 10:16:46 +0200 Subject: [PATCH 031/108] add line for linter --- src/sage/rings/polynomial/multi_polynomial_ring_base.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index fb04c537702..19a74c9d540 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -28,6 +28,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import (PolynomialRing, polynomial_default_category) from sage.rings.polynomial.polydict import ETuple + def is_MPolynomialRing(x): from sage.misc.superseded import deprecation_cython deprecation_cython(38266, From 1a94d8fb21a8274ec02cbf3cf605dfed54a400d7 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 30 Sep 2024 12:11:37 +0200 Subject: [PATCH 032/108] use cimport --- src/sage/rings/polynomial/multi_polynomial_ring_base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 19a74c9d540..fa9947b028e 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -26,7 +26,7 @@ from sage.rings.polynomial import polynomial_ring from sage.rings.polynomial.term_order import TermOrder from sage.rings.polynomial.polynomial_ring_constructor import (PolynomialRing, polynomial_default_category) -from sage.rings.polynomial.polydict import ETuple +from sage.rings.polynomial.polydict cimport ETuple def is_MPolynomialRing(x): From edfd03402a88134d451a29af78a78341f66ebc6c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 1 Oct 2024 14:38:09 +0900 Subject: [PATCH 033/108] Fix build.yml --- .ci/write-dockerfile.sh | 79 ++++++++++++++++++------------------- .github/workflows/build.yml | 42 ++++++++++++++++++-- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/.ci/write-dockerfile.sh b/.ci/write-dockerfile.sh index 68c19ca675e..6c74279fe9b 100755 --- a/.ci/write-dockerfile.sh +++ b/.ci/write-dockerfile.sh @@ -51,7 +51,11 @@ done echo "# Automatically generated by SAGE_ROOT/.ci/write-dockerfile.sh" echo "# the :comments: separate the generated file into sections" echo "# to simplify writing scripts that customize this file" -ADD="ADD $__CHOWN" +if [ -z "$__CHOWN" ]; then + ADD="ADD" +else + ADD="ADD $__CHOWN" +fi RUN=RUN cat < /dev/null; then \ - (yes | unminimize) || echo "(ignored)"; \ - rm -f "\$(command -v unminimize)"; \ - fi +RUN if command -v unminimize > /dev/null; then (yes | unminimize) || echo "(ignored)"; rm -f "\$(command -v unminimize)"; fi EOF if [ -n "$DIST_UPGRADE" ]; then cat <> /sage/.gitignore && \ - printf '/src/*\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /new/.gitignore && \ - if ! (cd /new && /.ci/retrofit-worktree.sh worktree-image /sage); then \ - echo "retrofit-worktree.sh failed, falling back to replacing /sage"; \ - for a in local logs; do \ - if [ -d /sage/\$a ]; then mv /sage/\$a /new/; fi; \ - done; \ - rm -rf /sage; \ - mv /new /sage; \ - fi; \ - else \ - mv /new /sage; \ +RUN if [ -d /sage ]; then \\ + echo "### Incremental build from \$(cat /sage/VERSION.txt)" && \\ + printf '/src/*\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /sage/.gitignore && \\ + printf '/src/*\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /new/.gitignore && \\ + if ! (cd /new && /.ci/retrofit-worktree.sh worktree-image /sage); then \\ + echo "retrofit-worktree.sh failed, falling back to replacing /sage"; \\ + for a in local logs; do \\ + if [ -d /sage/\$a ]; then mv /sage/\$a /new/; fi; \\ + done; \\ + rm -rf /sage; \\ + mv /new /sage; \\ + fi; \\ + else \\ + mv /new /sage; \\ fi WORKDIR /sage - ARG BOOTSTRAP="${BOOTSTRAP-./bootstrap}" -$RUN sh -x -c "\${BOOTSTRAP}" $ENDRUN $THEN_SAVE_STATUS +$RUN sh -x -c "\${BOOTSTRAP}"$ENDRUN$THEN_SAVE_STATUS FROM bootstrapped AS configured #:configuring: -RUN $CHECK_STATUS_THEN mkdir -p logs/pkgs; rm -f config.log; ln -s logs/pkgs/config.log config.log +RUN$CHECK_STATUS_THEN mkdir -p logs/pkgs; rm -f config.log; ln -s logs/pkgs/config.log config.log ARG CONFIGURE_ARGS="${CONFIGURE_ARGS:---enable-build-as-root}" EOF if [ ${WITH_SYSTEM_SPKG} = "force" ]; then cat <> $GITHUB_OUTPUT + echo "build_targets=$uninstall_targets reconfigure $build_targets ci-build-with-fallback" >> $GITHUB_OUTPUT else - echo "build_targets=$build_targets ci-build-with-fallback" >> $GITHUB_OUTPUT + echo "build_targets=$build_targets ci-build-with-fallback" >> $GITHUB_OUTPUT fi cat $GITHUB_OUTPUT + - uses: actions/checkout@v4 with: ref: ${{ github.base_ref }} path: worktree-base if: github.base_ref && steps.changed-files.outputs.pkgs_all_changed_files + - name: Compute metrics run: | export PATH=build/bin:$PATH @@ -140,6 +163,7 @@ jobs: else sage-package metrics :all: fi + - name: Install test prerequisites # From docker.yml run: | @@ -147,6 +171,7 @@ jobs: sudo DEBIAN_FRONTEND=noninteractive apt-get install tox sudo apt-get clean df -h + - name: Merge CI fixes from sagemath/sage # From docker.yml # This step needs to happen after the commit sha is put in DOCKER_TAG @@ -254,9 +279,11 @@ jobs: remove-haskell: true remove-codeql: true remove-docker-images: true + - name: Checkout id: checkout uses: actions/checkout@v4 + - name: Install test prerequisites # From docker.yml run: | @@ -264,6 +291,7 @@ jobs: sudo DEBIAN_FRONTEND=noninteractive apt-get install tox sudo apt-get clean df -h + - name: Merge CI fixes from sagemath/sage # From docker.yml # This step needs to happen after the commit sha is put in DOCKER_TAG @@ -352,9 +380,11 @@ jobs: remove-haskell: true remove-codeql: true remove-docker-images: true + - name: Checkout id: checkout uses: actions/checkout@v4 + - name: Install test prerequisites # From docker.yml run: | @@ -362,6 +392,7 @@ jobs: sudo DEBIAN_FRONTEND=noninteractive apt-get install tox sudo apt-get clean df -h + - name: Merge CI fixes from sagemath/sage # From docker.yml # This step needs to happen after the commit sha is put in DOCKER_TAG @@ -469,9 +500,11 @@ jobs: remove-haskell: true remove-codeql: true remove-docker-images: true + - name: Checkout id: checkout uses: actions/checkout@v4 + - name: Install test prerequisites # From docker.yml run: | @@ -479,6 +512,7 @@ jobs: sudo DEBIAN_FRONTEND=noninteractive apt-get install tox sudo apt-get clean df -h + - name: Merge CI fixes from sagemath/sage # From docker.yml # This step needs to happen after the commit sha is put in DOCKER_TAG From 45175252cd3b864266a2bdc2663977f5efe52d6b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 1 Oct 2024 09:44:20 +0200 Subject: [PATCH 034/108] provide monomial_coefficients for all kinds of polynomials --- src/sage/rings/polynomial/laurent_polynomial.pyx | 5 +++++ .../rings/polynomial/laurent_polynomial_mpair.pyx | 5 +++++ src/sage/rings/polynomial/multi_polynomial_element.py | 11 +++++++++++ .../rings/polynomial/multi_polynomial_libsingular.pyx | 7 ++++++- src/sage/rings/polynomial/ore_polynomial_element.pyx | 5 +++++ src/sage/rings/polynomial/plural.pyx | 3 +++ src/sage/rings/polynomial/polynomial_element.pyx | 3 +++ .../rings/polynomial/polynomial_element_generic.py | 5 +++++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 70cec491cae..8b1033f4fd5 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -850,10 +850,15 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): y^3*t^-9 + 3*x^3*y^2*t^-6 + 3*x^6*y*t^-3 + x^9 + t^2 sage: f.dict() {-9: y^3, -6: 3*x^3*y^2, -3: 3*x^6*y, 0: x^9, 2: 1} + + sage: f.monomial_coefficients() + {-9: y^3, -6: 3*x^3*y^2, -3: 3*x^6*y, 0: x^9, 2: 1} """ cdef dict d = self.__u.dict() return {k+self.__n: d[k] for k in d} + monomial_coefficients = dict + def coefficients(self): """ Return the nonzero coefficients of ``self``. diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index e6ea53e1756..4b14f79cdca 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -804,11 +804,16 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 sage: sorted(f.dict().items()) [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] + + sage: sorted(f.monomial_coefficients().items()) + [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] """ if self._prod is None: self._compute_polydict() return < dict > self._prod.dict() + monomial_coefficients = dict + def _fraction_pair(self): """ Return one representation of ``self`` as a pair diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 65ba655b114..e856fd9e46e 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -806,6 +806,17 @@ def dict(self): """ Return underlying dictionary with keys the exponents and values the coefficients of this polynomial. + + EXAMPLES:: + + sage: # needs sage.rings.number_field + sage: R. = PolynomialRing(QQbar, order='lex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: f.dict() + {(1, 5, 2): 1, (2, 0, 1): 1, (4, 1, 3): 1} + + sage: f.monomial_coefficients() # needs sage.rings.number_field + {(1, 5, 2): 1, (2, 0, 1): 1, (4, 1, 3): 1} """ return self.element().dict() diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index d177889bd6e..307735c46ba 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2992,9 +2992,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): EXAMPLES:: sage: R. = QQ[] - sage: f=2*x*y^3*z^2 + 1/7*x^2 + 2/3 + sage: f = 2*x*y^3*z^2 + 1/7*x^2 + 2/3 sage: f.dict() {(0, 0, 0): 2/3, (1, 3, 2): 2, (2, 0, 0): 1/7} + + sage: f.monomial_coefficients() + {(0, 0, 0): 2/3, (1, 3, 2): 2, (2, 0, 0): 1/7} """ cdef poly *p cdef ring *r = self._parent_ring @@ -3016,6 +3019,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): p = pNext(p) return pd + monomial_coefficients = dict + def iterator_exp_coeff(self, as_ETuples=True): """ Iterate over ``self`` as pairs of ((E)Tuple, coefficient). diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 8307bf9694a..1acc82dd583 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -2493,6 +2493,9 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: a = x^2012 + t*x^1006 + t^3 + 2*t sage: a.dict() {0: t^3 + 2*t, 1006: t, 2012: 1} + + sage: a.monomial_coefficients() + {0: t^3 + 2*t, 1006: t, 2012: 1} """ cdef dict X = {} cdef list Y = (self)._coeffs @@ -2503,6 +2506,8 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): X[i] = c return X + monomial_coefficients = dict + cpdef Integer degree(self): r""" Return the degree of ``self``. diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index eb6b091c683..8fb9592e0b7 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -2203,6 +2203,9 @@ cdef class NCPolynomial_plural(RingElement): sage: f = (2*x*y^3*z^2 + (7)*x^2 + (3)) sage: f.dict() {(0, 0, 0): 3, (1, 2, 3): 2, (2, 0, 0): 7} + + sage: f.monomial_coefficients() + {(0, 0, 0): 3, (1, 2, 3): 2, (2, 0, 0): 7} """ cdef poly *p cdef ring *r diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 3ce764d6f01..dbb7a6f0565 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4475,6 +4475,9 @@ cdef class Polynomial(CommutativePolynomial): sage: f = x^3 + -1/7*x + 13 sage: f.dict() {0: 13, 1: -1/7, 3: 1} + + sage: f.monomial_coefficients() + {0: 13, 1: -1/7, 3: 1} """ cdef dict X = {} cdef list Y = self.list(copy=False) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 3e8a6b45ee1..abfe216aae8 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -143,9 +143,14 @@ def dict(self): sage: d[0] = 10 sage: f.dict() {0: 5, 1997: 1, 10000: 7} + + sage: f.monomial_coefficients() + {0: 5, 1997: 1, 10000: 7} """ return dict(self.__coeffs) + monomial_coefficients = dict + def coefficients(self, sparse=True): """ Return the coefficients of the monomials appearing in ``self``. From 6cb889f833591252bcd5e3fb13216e7524ad1614 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 1 Oct 2024 16:53:56 +0900 Subject: [PATCH 035/108] Add dummy spkg-configure.m4 for _bootstrap --- .ci/write-dockerfile.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.ci/write-dockerfile.sh b/.ci/write-dockerfile.sh index 6c74279fe9b..75737acf106 100755 --- a/.ci/write-dockerfile.sh +++ b/.ci/write-dockerfile.sh @@ -35,7 +35,7 @@ STRIP_COMMENTS="sed s/#.*//;" SAGE_ROOT=. export PATH="$SAGE_ROOT"/build/bin:$PATH SYSTEM_PACKAGES=$EXTRA_SYSTEM_PACKAGES -SYSTEM_CONFIGURE_ARGS="--enable-option-checking " +SYSTEM_CONFIGURE_ARGS=" --enable-option-checking" for SPKG in $(sage-package list --has-file=spkg-configure.m4 $SAGE_PACKAGE_LIST_ARGS) $EXTRA_SAGE_PACKAGES; do SYSTEM_PACKAGE=$(sage-get-system-packages $SYSTEM $SPKG) if [ -n "${SYSTEM_PACKAGE}" ]; then @@ -45,7 +45,10 @@ for SPKG in $(sage-package list --has-file=spkg-configure.m4 $SAGE_PACKAGE_LIST_ # shell-quote package if necessary SYSTEM_PACKAGES+=$(printf " %q" "$a") done - SYSTEM_CONFIGURE_ARGS+="--with-system-${SPKG}=${WITH_SYSTEM_SPKG} " + # Check if SPKG is not a dummy package + if [[ $SPKG != _* ]]; then + SYSTEM_CONFIGURE_ARGS+=" --with-system-${SPKG}=${WITH_SYSTEM_SPKG}" + fi fi done echo "# Automatically generated by SAGE_ROOT/.ci/write-dockerfile.sh" From 08fca6710001269efeaa59c30929c28811a616ee Mon Sep 17 00:00:00 2001 From: Daniel Gordon Date: Tue, 1 Oct 2024 12:18:54 -0700 Subject: [PATCH 036/108] Added two missing difference sets, updated URLs --- src/sage/combinat/designs/covering_design.py | 4 +- src/sage/combinat/designs/database.py | 65 ++++++++++++++++---- src/sage/combinat/designs/design_catalog.py | 2 +- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/designs/covering_design.py b/src/sage/combinat/designs/covering_design.py index 30bbeafb708..7977de93d9d 100644 --- a/src/sage/combinat/designs/covering_design.py +++ b/src/sage/combinat/designs/covering_design.py @@ -21,7 +21,7 @@ REFERENCES: .. [1] La Jolla Covering Repository, - https://ljcr.dmgordon.org/cover.html + https://dmgordon.org/cover .. [2] Daniel M. Gordon and Douglas R. Stinson, *Coverings*, Chapter 1 in: Charles J. Colbourn and Jeffrey H. Dinitz, @@ -516,7 +516,7 @@ def best_known_covering_design_www(v, k, t, verbose=False): k = int(k) t = int(t) param = "?v=%s&k=%s&t=%s" % (v, k, t) - url = "https://ljcr.dmgordon.org/cover/get_cover.php" + param + url = "https://ljcr.dmgordon.org/get_cover.php" + param if verbose: print("Looking up the bounds at %s" % url) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index dc614bd7b25..4bda83eeab0 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -3143,15 +3143,58 @@ def QDM_57_9_1_1_8(): [0,2,13,18,28,30,44,48,50,51,57,61], [0,4,21,26,29,33,35,36,47,55,56,60]]}, -# a 133-cyclic set from Ken Smith database -# see https://math.ccrwest.org/diffsets/diff_sets/DS_133_33_8_133.html +# a 133-cyclic difference set +# see https://dmgordon.org/diffset (133,33, 8): - {(133,): [[0,4,7,8,15,17,19,22,24,25,29,30,38, - 47,49,50,55,58,61,62,71,73,76,77,78, - 82,95,111,113,114,121,123,127]]}, - -# a 901-cyclic -# see https://math.ccrwest.org/diffsets/diff_sets/DS_901_225_56_901.html + {(133,): [[1,5,14,22,25,27,29,32,34,38, + 46,64,65,66,76,78,81,82,84,89, + 92,93,99,103,104,106,107,112,113,122, + 126,128,129]]}, + +# a 144-noncyclic difference set, +# given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith +# see https://dmgordon.org/diffset +(144,66,30): + {(2,8,3,3): [[(0,1,0,0),(0,7,0,2),(0,5,0,1),(0,3,0,0),(0,6,0,1), + (0,1,0,2),(0,4,0,0),(0,2,0,2),(0,6,0,0),(0,1,0,1), + (0,4,0,2),(0,2,0,1),(1,2,2,0),(1,3,2,0),(1,4,2,0), + (1,5,2,0),(1,6,2,0),(1,7,2,0),(0,6,1,2),(0,1,1,0), + (0,4,1,1),(0,3,1,0),(0,1,1,2),(0,4,1,0),(0,7,1,1), + (0,2,1,2),(0,6,1,0),(0,1,1,1),(0,2,1,1),(0,5,1,2), + (1,0,0,0),(1,6,0,2),(1,1,0,0),(1,4,0,1),(1,7,0,2), + (1,2,0,0),(1,5,0,1),(1,0,0,2),(1,3,0,0),(1,1,0,2), + (1,0,0,1),(1,1,0,1),(0,0,2,0),(0,6,2,2),(0,4,2,1), + (0,0,2,2),(0,3,2,0),(0,6,2,1),(0,2,2,2),(0,5,2,0), + (0,0,2,1),(0,4,2,2),(0,7,2,0),(0,2,2,1),(1,0,1,0), + (1,1,1,0),(1,2,1,0),(1,0,1,2),(1,3,1,0),(1,6,1,1), + (1,1,1,2),(1,7,1,1),(1,0,1,1),(1,1,1,1),(1,4,1,2), + (1,5,1,2)]]}, + +# a 320-noncyclic difference set, +# given in Arasu and Chen, Designs, Codes and Cryptography 2001 +# see https://dmgordon.org/diffset +(320,88,24): + {(4,4,4,5): [[(3,3,3,0),(2,3,2,0),(3,1,3,0),(2,2,3,0),(1,3,3,0), + (3,2,1,0),(2,2,2,0),(2,2,1,0),(2,1,2,0),(0,3,2,0), + (2,0,3,0),(1,1,3,0),(0,2,3,0),(3,0,1,0),(1,2,1,0), + (2,0,2,0),(0,2,2,0),(2,0,1,0),(0,2,1,0),(0,1,2,0), + (0,0,3,0),(1,0,1,0),(0,0,2,0),(0,0,1,0),(3,3,3,1), + (3,3,1,1),(3,0,3,1),(0,3,3,1),(3,0,1,1),(0,3,1,1), + (1,1,2,1),(1,0,2,1),(0,1,2,1),(0,0,3,1),(1,1,0,1), + (0,0,2,1),(1,0,0,1),(0,1,0,1),(0,0,1,1),(0,0,0,1), + (1,1,3,2),(3,1,1,2),(2,3,3,2),(2,2,3,2),(0,3,2,2), + (0,3,1,2),(0,2,1,2),(3,2,2,2),(3,1,2,2),(3,0,3,2), + (2,3,0,2),(2,0,2,2),(1,2,0,2),(1,1,0,2),(1,0,1,2), + (0,0,0,2),(1,1,1,3),(1,3,3,3),(3,2,1,3),(2,2,3,3), + (3,0,0,3),(3,0,3,3),(1,3,0,3),(2,0,1,3),(3,2,2,3), + (2,3,2,3),(0,3,3,3),(1,1,2,3),(0,2,2,3),(2,1,0,3), + (0,1,1,3),(0,0,0,3),(2,0,3,4),(1,1,2,4),(0,2,1,4), + (0,1,3,4),(3,2,3,4),(3,2,2,4),(2,3,2,4),(3,1,3,4), + (3,3,0,4),(2,3,1,4),(1,0,1,4),(2,2,2,4),(1,3,1,4), + (1,0,0,4),(0,1,0,4),(0,0,0,4)]]}, + +# a 901-cyclic difference set +# see https://dmgordon.org/diffset (901,225,56): {(901,): [[ 0, 1, 5, 9, 12, 13, 14, 16, 22, 25, 41, 43, 45, 47, 53, 59, 60, 65, 69, 70, 71, 79, 80, 81, @@ -4283,7 +4326,7 @@ def BIBD_66_6_1(): Return a (66,6,1)-BIBD. This BIBD was obtained from La Jolla covering repository - (https://math.ccrwest.org/cover.html) where it is attributed to Colin Barker. + (https://dmgordon.org/cover) where it is attributed to Colin Barker. EXAMPLES:: @@ -4307,7 +4350,7 @@ def BIBD_76_6_1(): Return a (76,6,1)-BIBD. This BIBD was obtained from La Jolla covering repository - (https://math.ccrwest.org/cover.html) where it is attributed to Colin Barker. + (https://dmgordon.org/cover) where it is attributed to Colin Barker. EXAMPLES:: @@ -4331,7 +4374,7 @@ def BIBD_96_6_1(): Return a (96,6,1)-BIBD. This BIBD was obtained from La Jolla covering repository - (https://math.ccrwest.org/cover.html) where it is attributed to Colin Barker. + (https://dmgordon.org/cover) where it is attributed to Colin Barker. EXAMPLES:: diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index 8bf7f14fd0b..b5135151866 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -72,7 +72,7 @@ REFERENCES: .. [1] La Jolla Covering Repository, - https://math.ccrwest.org/cover.html + https://dmgordon.org/cover """ from sage.misc.lazy_import import lazy_import From e0d2e8d1c73772f6716b3eaecaa731c01f5141dd Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Tue, 1 Oct 2024 13:44:17 -0700 Subject: [PATCH 037/108] Address gh-15325 Exhibit A --- .../combinat/root_system/ambient_space.py | 34 +++++++++++++------ src/sage/combinat/root_system/root_space.py | 29 ++++++++++++---- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index 5fe5e161575..a4b6aa315d3 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -369,8 +369,7 @@ def _repr_(self): def inner_product(self, lambdacheck): """ - The scalar product with elements of the coroot lattice - embedded in the ambient space. + The scalar product with elements of the ambient space EXAMPLES:: @@ -379,16 +378,31 @@ def inner_product(self, lambdacheck): (-1, 0, 0) sage: a.inner_product(a) 2 + + TESTS:: + + sage: rt = RootSystem(['E',8]) # verify that error from issue gh-15325 Exhibit A is fixed + sage: lat = rt.root_lattice() + sage: spc = rt.ambient_space() + sage: spc.simple_root(1).scalar(lat.simple_coroot(2)) + 0 """ - self_mc = self._monomial_coefficients - lambdacheck_mc = lambdacheck._monomial_coefficients + if self.parent() == lambdacheck.parent(): + # self and lambdacheck both belong to the same ambient space, so use the inner product there + self_mc = self._monomial_coefficients + lambdacheck_mc = lambdacheck._monomial_coefficients + + result = self.parent().base_ring().zero() + for t,c in lambdacheck_mc.items(): + if t in self_mc: + result += c*self_mc[t] + return result + + if lambdacheck.parent() == self.parent().root_system.coroot_lattice(): + # for lambdacheck in the coroot lattice, need to map it to the ambient space first + return lambdacheck.to_ambient().scalar(self) - result = self.parent().base_ring().zero() - for t,c in lambdacheck_mc.items(): - if t not in self_mc: - continue - result += c*self_mc[t] - return result + raise TypeError(f"Don't know how to coerce {lambdacheck} into root or coroot space of {self}") scalar = inner_product dot_product = inner_product diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 96a68eacc0f..74c0dbc8adc 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -260,13 +260,30 @@ def scalar(self, lambdacheck): [-1 2 -1 0] [ 0 -1 2 -1] [ 0 0 -2 2] + + TESTS:: + + sage: rt = RootSystem(['E',8]) # verify that error from issue gh-15325 Exhibit A is fixed + sage: lat = rt.root_lattice() + sage: spc = rt.ambient_space() + sage: lat.simple_root(1).scalar(spc.simple_coroot(2)) + 0 + + sage: lat = RootSystem(['B', 3]).root_lattice() # verify that directionality is correct for roots of different lengths + sage: lat.simple_root(2).scalar(lat.simple_coroot(3)) + -2 """ - # Find some better test - if not (lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()): - raise TypeError("%s is not in a coroot lattice/space" % (lambdacheck)) - zero = self.parent().base_ring().zero() - cartan_matrix = self.parent().dynkin_diagram() - return sum( (sum( (lambdacheck[i]*s for i,s in cartan_matrix.column(j)), zero) * c for j,c in self), zero) + if (lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()): + # This is the mathematically canonical case, where we use the Cartan matrix to find the scalar product + zero = self.parent().base_ring().zero() + cartan_matrix = self.parent().dynkin_diagram() + return sum( (sum( (lambdacheck[i]*s for i,s in cartan_matrix.column(j)), zero) * c for j,c in self), zero) + + if (lambdacheck in self.parent().root_system.ambient_space()): + # lambdacheck lives in the ambient space of the root space, so we take the usual dot product in the ambient space + return self.to_ambient().dot_product(lambdacheck) + + raise TypeError(f"{lambdacheck} is not in a coroot lattice/space") def is_positive_root(self): """ From 8a21b778475f2401f69c8795d92c017fee847b3e Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:41:28 -0700 Subject: [PATCH 038/108] Update src/sage/combinat/root_system/root_system.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_system.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index c177fb8e965..40be7ff7cda 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -789,16 +789,17 @@ def coambient_space(self, base_ring=QQ): def coxeter_number(self): """ - For an irreducible finite root system, reports the Coxeter number. - This function is a wrapper for the corresponding function in CartanType. + Return the Coxeter number of an irreducible finite root system. + + .. SEEALSO:: + + :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.coxeter_number`. EXAMPLES:: sage: rt = RootSystem(['C', 5]) sage: rt.coxeter_number() 10 - - .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.coxeter_number` """ # Check if RootSystem is finite and irreducible if self.is_finite() and self.is_irreducible(): From cad203c53934ef71f8613b57421400834c5314b9 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:42:04 -0700 Subject: [PATCH 039/108] Update src/sage/combinat/root_system/root_system.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_system.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 40be7ff7cda..0e53d7d8a8e 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -802,11 +802,10 @@ def coxeter_number(self): 10 """ # Check if RootSystem is finite and irreducible - if self.is_finite() and self.is_irreducible(): - # Hand over to CartanType method - return self._cartan_type.coxeter_number() - else: - raise ValueError("Coxeter number is defined only for finite and irreducible root systems.") + if not (self.is_finite() and self.is_irreducible()): + raise ValueError("the Coxeter number is defined only for finite and irreducible root systems") + # Hand over to CartanType method + return self._cartan_type.coxeter_number() def dual_coxeter_number(self): """ From 7347dd7ae95bc7ae602e6b8a27691334ace1214d Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:42:24 -0700 Subject: [PATCH 040/108] Update src/sage/combinat/root_system/root_system.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_system.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 0e53d7d8a8e..f4f93671dfe 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -809,10 +809,10 @@ def coxeter_number(self): def dual_coxeter_number(self): """ - For an irreducible finite root system, reports the dual Coxeter number, - which is defined to be 1 plus the sum of the coefficients of simple roots - in the highest short root of the dual root system. This function is a - wrapper for the corresponding function in CartanType. + Return the dual Coxeter number of a irreducible finite root system. + + The dual Coxeter number is equal to 1 plus the sum of the coefficients + of simple roots in the highest short root of the dual root system. EXAMPLES:: From a190248d13e05585389234063aaeb76b68ea7297 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:43:25 -0700 Subject: [PATCH 041/108] Update src/sage/combinat/root_system/root_system.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_system.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index f4f93671dfe..b59dd1aea8f 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -831,11 +831,10 @@ def dual_coxeter_number(self): .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.dual_coxeter_number` """ # Check if RootSystem is finite and irreducible - if self.is_finite() and self.is_irreducible(): - # Hand over to CartanType method - return self._cartan_type.dual_coxeter_number() - else: - raise ValueError("Dual Coxeter number is defined only for finite and irreducible root systems.") + if not (self.is_finite() and self.is_irreducible()): + raise ValueError("the dual Coxeter number is defined only for finite and irreducible root systems") + # Hand over to CartanType method + return self._cartan_type.dual_coxeter_number() def WeylDim(ct, coeffs): From b4eeff6f22d5059b5d87425d1a73d7396d17c5f4 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:47:09 -0700 Subject: [PATCH 042/108] Move SEE ALSO before EXAMPLES --- src/sage/combinat/root_system/root_system.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index b59dd1aea8f..0cb2d26c91e 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -814,6 +814,8 @@ def dual_coxeter_number(self): The dual Coxeter number is equal to 1 plus the sum of the coefficients of simple roots in the highest short root of the dual root system. + .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.dual_coxeter_number` + EXAMPLES:: sage: rt = RootSystem(['C', 5]) @@ -827,8 +829,6 @@ def dual_coxeter_number(self): Dual of root system of type ['C', 5] sage: rt.dual.coxeter_number() 10 - - .. SEEALSO:: :meth:`~sage.combinat.root_system.cartan_type.CartanType_standard_finite.dual_coxeter_number` """ # Check if RootSystem is finite and irreducible if not (self.is_finite() and self.is_irreducible()): From 669626a773f92d8f2899b9b2a36b2a9c2682808c Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:51:43 -0700 Subject: [PATCH 043/108] Update src/sage/combinat/root_system/root_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_space.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 74c0dbc8adc..cc6afff7b42 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -279,7 +279,7 @@ def scalar(self, lambdacheck): cartan_matrix = self.parent().dynkin_diagram() return sum( (sum( (lambdacheck[i]*s for i,s in cartan_matrix.column(j)), zero) * c for j,c in self), zero) - if (lambdacheck in self.parent().root_system.ambient_space()): + if lambdacheck in self.parent().root_system.ambient_space(): # lambdacheck lives in the ambient space of the root space, so we take the usual dot product in the ambient space return self.to_ambient().dot_product(lambdacheck) From 5c247bc8435ce50bc405edc56b740c6e339016b2 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:51:59 -0700 Subject: [PATCH 044/108] Update src/sage/combinat/root_system/root_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_space.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index cc6afff7b42..f686c78e1c1 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -273,7 +273,7 @@ def scalar(self, lambdacheck): sage: lat.simple_root(2).scalar(lat.simple_coroot(3)) -2 """ - if (lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()): + if lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space(): # This is the mathematically canonical case, where we use the Cartan matrix to find the scalar product zero = self.parent().base_ring().zero() cartan_matrix = self.parent().dynkin_diagram() From 0a45efc57cb6c683bc3f6c645c8de4c1e54249c9 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:52:50 -0700 Subject: [PATCH 045/108] Update src/sage/combinat/root_system/ambient_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/ambient_space.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index a4b6aa315d3..b352e2a87b2 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -369,7 +369,7 @@ def _repr_(self): def inner_product(self, lambdacheck): """ - The scalar product with elements of the ambient space + The scalar product with elements of the ambient space. EXAMPLES:: From c265edb6b4f4cbd5f71cac8319f73dd1cdfa98b2 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:54:01 -0700 Subject: [PATCH 046/108] Update src/sage/combinat/root_system/root_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_space.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index f686c78e1c1..37be4d96cd4 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -269,7 +269,9 @@ def scalar(self, lambdacheck): sage: lat.simple_root(1).scalar(spc.simple_coroot(2)) 0 - sage: lat = RootSystem(['B', 3]).root_lattice() # verify that directionality is correct for roots of different lengths + Verify that directionality is correct for roots of different lengths:: + + sage: lat = RootSystem(['B', 3]).root_lattice() sage: lat.simple_root(2).scalar(lat.simple_coroot(3)) -2 """ From fdb1a1206a114f3ae80068d63cd6aec1effa2c84 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:54:16 -0700 Subject: [PATCH 047/108] Update src/sage/combinat/root_system/root_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/root_space.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 37be4d96cd4..5d1ee7f1260 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -261,9 +261,11 @@ def scalar(self, lambdacheck): [ 0 -1 2 -1] [ 0 0 -2 2] - TESTS:: + TESTS: - sage: rt = RootSystem(['E',8]) # verify that error from issue gh-15325 Exhibit A is fixed + Verify that :issue:`15325` (A) is fixed:: + + sage: rt = RootSystem(['E', 8]) sage: lat = rt.root_lattice() sage: spc = rt.ambient_space() sage: lat.simple_root(1).scalar(spc.simple_coroot(2)) From a2b730a3c95a65bd0c815d9283b5c143b2fe4224 Mon Sep 17 00:00:00 2001 From: Skip G <57930547+skipgaribaldi@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:54:30 -0700 Subject: [PATCH 048/108] Update src/sage/combinat/root_system/ambient_space.py Co-authored-by: Travis Scrimshaw --- src/sage/combinat/root_system/ambient_space.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index b352e2a87b2..98eaece1e59 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -379,9 +379,11 @@ def inner_product(self, lambdacheck): sage: a.inner_product(a) 2 - TESTS:: + TESTS: + + Verify that :issue:`15325` (A) is fixed:: - sage: rt = RootSystem(['E',8]) # verify that error from issue gh-15325 Exhibit A is fixed + sage: rt = RootSystem(['E', 8]) sage: lat = rt.root_lattice() sage: spc = rt.ambient_space() sage: spc.simple_root(1).scalar(lat.simple_coroot(2)) From 7da711f511d833efe427944b373939dd3e2a2a21 Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Tue, 1 Oct 2024 19:10:28 -0700 Subject: [PATCH 049/108] Delete trailing whitespace (W291) --- src/sage/combinat/root_system/root_system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 0cb2d26c91e..06210a749e7 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -834,7 +834,7 @@ def dual_coxeter_number(self): if not (self.is_finite() and self.is_irreducible()): raise ValueError("the dual Coxeter number is defined only for finite and irreducible root systems") # Hand over to CartanType method - return self._cartan_type.dual_coxeter_number() + return self._cartan_type.dual_coxeter_number() def WeylDim(ct, coeffs): From a24079e559fdecfb0f8b4f4dad41004b28c0871e Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Tue, 1 Oct 2024 19:31:39 -0700 Subject: [PATCH 050/108] Flop the order of presentation of AmbientSpaceElement.inner_product --- .../combinat/root_system/ambient_space.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index 98eaece1e59..0d00c45273f 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -389,22 +389,22 @@ def inner_product(self, lambdacheck): sage: spc.simple_root(1).scalar(lat.simple_coroot(2)) 0 """ - if self.parent() == lambdacheck.parent(): - # self and lambdacheck both belong to the same ambient space, so use the inner product there - self_mc = self._monomial_coefficients - lambdacheck_mc = lambdacheck._monomial_coefficients - - result = self.parent().base_ring().zero() - for t,c in lambdacheck_mc.items(): - if t in self_mc: - result += c*self_mc[t] - return result - - if lambdacheck.parent() == self.parent().root_system.coroot_lattice(): - # for lambdacheck in the coroot lattice, need to map it to the ambient space first - return lambdacheck.to_ambient().scalar(self) - - raise TypeError(f"Don't know how to coerce {lambdacheck} into root or coroot space of {self}") + if self.parent() is not lambdacheck.parent(): + try: + # see if lambdacheck can be converted to the ambient space + lambdacheck = self.parent()(lambdacheck) + except (TypeError, ValueError): + raise TypeError(f"unable to coerce {lambdacheck} into {self.parent()}") + + # self and lambdacheck both belong to the same ambient space, so use the inner product there + self_mc = self._monomial_coefficients + lambdacheck_mc = lambdacheck._monomial_coefficients + + result = self.parent().base_ring().zero() + for t,c in lambdacheck_mc.items(): + if t in self_mc: + result += c*self_mc[t] + return result scalar = inner_product dot_product = inner_product From c2aeebcd157671c6ca00f18864bb526f9d144e56 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Oct 2024 19:43:02 -0700 Subject: [PATCH 051/108] src/sage/sets/image_set.py: Modularization fix (import) --- src/sage/sets/image_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index 8691edbcd01..a518dc58f93 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -25,7 +25,6 @@ from sage.misc.cachefunc import cached_method from sage.rings.infinity import Infinity from sage.rings.integer import Integer -from sage.modules.free_module import FreeModule from sage.structure.element import Expression from sage.structure.parent import Parent @@ -91,6 +90,7 @@ def __init__(self, map, domain_subset, *, category=None, is_injective=None, inve if isinstance(map, Expression) and map.is_callable(): domain = map.parent().base() if len(map.arguments()) != 1: + from sage.modules.free_module import FreeModule domain = FreeModule(domain, len(map.arguments())) function = map From d7f2ab1ac00d89b3650d99ef5bfa0681a946309e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Oct 2024 17:52:52 -0700 Subject: [PATCH 052/108] src/sage/sets/disjoint_set.pyx: Use LazyImport --- src/sage/sets/disjoint_set.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index 7a832104295..ddd9a95a310 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -62,7 +62,10 @@ from sage.rings.integer cimport Integer from sage.structure.sage_object cimport SageObject from cpython.object cimport PyObject_RichCompare from sage.groups.perm_gps.partn_ref.data_structures cimport * -from sage.combinat.set_partition import SetPartition +from sage.misc.lazy_import import LazyImport + +SetPartition = LazyImport('sage.combinat.set_partition', 'SetPartition') + cpdef DisjointSet(arg): r""" From 02ee0636bbbdd4da9c911a557cb1b0bd3c12eb69 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 2 Oct 2024 08:09:13 -0400 Subject: [PATCH 053/108] build/pkgs/sagetex/dependencies: add $(PYTHON_TOOLCHAIN) Our sagetex package needs python_build, included as part of $(PYTHON_TOOLCHAIN), to build. Closes: https://github.com/sagemath/sage/issues/38657 --- build/pkgs/sagetex/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagetex/dependencies b/build/pkgs/sagetex/dependencies index af9b5f370fb..13610c4b390 100644 --- a/build/pkgs/sagetex/dependencies +++ b/build/pkgs/sagetex/dependencies @@ -1,4 +1,4 @@ - maxima scipy matplotlib pillow tachyon pyparsing | $(PYTHON) + maxima scipy matplotlib pillow tachyon pyparsing | $(PYTHON_TOOLCHAIN) $(PYTHON) To build SageTeX, you just need Python and pyparsing, but to test (SAGE_CHECK=yes) SageTeX, you actually need to run Sage, produce plots,... From 5beb162ac5823639d78e45adaabe44b705b65724 Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Wed, 2 Oct 2024 12:03:58 -0700 Subject: [PATCH 054/108] Fixed a space to improve appearance in docs --- src/sage/combinat/root_system/root_space.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 5d1ee7f1260..5255d7ec530 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -261,9 +261,9 @@ def scalar(self, lambdacheck): [ 0 -1 2 -1] [ 0 0 -2 2] - TESTS: + TESTS:: - Verify that :issue:`15325` (A) is fixed:: + Verify that :issue:`15325` (A) is fixed:: sage: rt = RootSystem(['E', 8]) sage: lat = rt.root_lattice() From 7b31e644c4a40b2974893b6b65d4ef012dbc406d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Sep 2024 15:14:00 -0400 Subject: [PATCH 055/108] src/sage/symbolic/integration: make libgiac integration optional We turn the libgiac integrator into a no-op if libgiac isn't available. That way, in the default integration routines, it is essentially skipped. If it were tried last, we could literally skip it; but currently it lives between maxima and sympy and cannot be rearanged without messing up some doctests. --- src/sage/symbolic/integration/external.py | 10 +++++++++- src/sage/symbolic/integration/integral.py | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 968d0e7e7c3..5f647228564 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -285,7 +285,15 @@ def libgiac_integrator(expression, v, a=None, b=None): sage: (F.derivative(x) - f).simplify_trig() 0 """ - from sage.libs.giac import libgiac + try: + from sage.libs.giac import libgiac + except ImportError: + # If libgiac isn't available, return a symbolic answer + # (without actually integrating anything). This is essentially + # the failure case of any integration: see below for what we + # do if libgiac is *available* but unable to do much. + return expression.integrate(v, a, b, hold=True) + from sage.libs.giac.giac import Pygen # We call Pygen on first argument because otherwise some expressions # involving derivatives result in doctest failures in interfaces/sympy.py diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 5c7e5db192f..6bb2592a668 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -83,6 +83,10 @@ def __init__(self): # in the given order. This is an attribute of the class instead of # a global variable in this module to enable customization by # creating a subclasses which define a different set of integrators + # + # The libgiac integrator may immediately return a symbolic + # (unevaluated) answer if libgiac is unavailable. This essentially + # causes it to be skipped. self.integrators = [external.maxima_integrator, external.libgiac_integrator, external.sympy_integrator] From 8e7f772a23aeaa23c94ea7e9dc1518aa61557c42 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 3 Oct 2024 18:01:49 +0200 Subject: [PATCH 056/108] fix bug in acyclic_orientations, see issue 38758 return a properly relabeld digraph, not just the arc labeling to describe the orientation. --- src/sage/graphs/orientations.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 2dac79b7146..aecf253b083 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -67,11 +67,12 @@ def acyclic_orientations(G): .. NOTE:: - The function assumes that the input graph is undirected and the edges are unlabelled. + The function assumes that the input graph is undirected and the edges + are unlabelled. EXAMPLES: - To count number acyclic orientations for a graph:: + To count the number of acyclic orientations for a graph:: sage: g = Graph([(0, 3), (0, 4), (3, 4), (1, 3), (1, 2), (2, 3), (2, 4)]) sage: it = g.acyclic_orientations() @@ -80,11 +81,21 @@ def acyclic_orientations(G): Test for arbitrary vertex labels:: - sage: g_str = Graph([('abc', 'def'), ('ghi', 'def'), ('xyz', 'abc'), ('xyz', 'uvw'), ('uvw', 'abc'), ('uvw', 'ghi')]) + sage: g_str = Graph([('abc', 'def'), ('ghi', 'def'), ('xyz', 'abc'), + ....: ('xyz', 'uvw'), ('uvw', 'abc'), ('uvw', 'ghi')]) sage: it = g_str.acyclic_orientations() sage: len(list(it)) 42 + Check that the method returns properly relabeled acyclic digraphs:: + + sage: g = Graph([(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)]) + sage: orientations = set([frozenset(d.edges(labels=false)) for d in g.acyclic_orientations()]) + sage: len(orientations) + 18 + sage: all(d.is_directed_acyclic() for d in g.acyclic_orientations()) + True + TESTS: To count the number of acyclic orientations for a graph with 0 vertices:: @@ -291,8 +302,9 @@ def helper(G, globO, m, k): # Iterate over acyclic orientations and create relabeled graphs for orientation in orientations: - relabeled_graph = DiGraph([(reverse_vertex_labels[u], reverse_vertex_labels[v], label) for (u, v), label in orientation.items()]) - yield relabeled_graph + D = DiGraph([(u, v) if label else (v, u) for (u, v), label in orientation.items()]) + D.relabel(perm=reverse_vertex_labels, inplace=True) + yield D def strong_orientations_iterator(G): From 92c4646457930aaac78b571e8cd1bade33924c8c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 3 Oct 2024 21:00:52 +0200 Subject: [PATCH 057/108] make dict an alias of monomial_coefficients, thoroughly --- src/sage/algebras/cluster_algebra.py | 7 +- src/sage/algebras/commutative_dga.py | 41 +++++---- src/sage/algebras/free_algebra.py | 2 +- .../fast_parallel_fmats_methods.pyx | 4 +- .../algebras/fusion_rings/poly_tup_engine.pyx | 2 +- .../hecke_algebras/cubic_hecke_base_ring.py | 2 +- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- .../free_algebra_element_letterplace.pyx | 2 +- src/sage/algebras/quantum_clifford.py | 4 +- .../algebras/rational_cherednik_algebra.py | 8 +- src/sage/algebras/splitting_algebra.py | 15 +++- src/sage/algebras/weyl_algebra.py | 2 +- src/sage/combinat/ncsf_qsym/qsym.py | 2 +- .../root_lattice_realization_algebras.py | 2 +- src/sage/combinat/sf/monomial.py | 23 +++-- src/sage/combinat/sf/sfa.py | 2 +- src/sage/combinat/triangles_FHM.py | 4 +- src/sage/databases/cubic_hecke_db.py | 4 +- .../polyhedron/generating_function.py | 6 +- src/sage/groups/braid.py | 2 +- src/sage/libs/singular/singular.pyx | 8 +- src/sage/rings/morphism.pyx | 2 +- .../rings/multi_power_series_ring_element.py | 20 +++-- src/sage/rings/polynomial/flatten.py | 10 +-- .../rings/polynomial/laurent_polynomial.pxd | 2 +- .../rings/polynomial/laurent_polynomial.pyx | 23 +++-- .../polynomial/laurent_polynomial_mpair.pyx | 33 +++---- .../polynomial/laurent_polynomial_ring.py | 15 ++-- .../rings/polynomial/multi_polynomial.pyx | 38 ++++---- .../polynomial/multi_polynomial_element.py | 24 +++--- .../multi_polynomial_libsingular.pyx | 29 ++++--- .../rings/polynomial/multi_polynomial_ring.py | 86 +++++++++++-------- .../polynomial/multi_polynomial_ring_base.pyx | 8 +- src/sage/rings/polynomial/omega.py | 9 +- .../polynomial/ore_polynomial_element.pxd | 3 +- .../polynomial/ore_polynomial_element.pyx | 5 +- .../polynomial_padic_capped_relative_dense.py | 2 +- .../rings/polynomial/polynomial_element.pyx | 22 ++--- .../polynomial/polynomial_element_generic.py | 28 +++--- .../polynomial_ring_homomorphism.pyx | 5 +- src/sage/rings/power_series_mpoly.pyx | 4 +- src/sage/rings/power_series_pari.pyx | 12 ++- src/sage/rings/power_series_poly.pyx | 12 ++- src/sage/rings/power_series_ring_element.pyx | 2 +- src/sage/rings/qqbar.py | 4 +- .../rings/semirings/tropical_mpolynomial.py | 11 ++- .../rings/semirings/tropical_polynomial.py | 12 +-- src/sage/rings/semirings/tropical_variety.py | 2 +- src/sage/rings/tate_algebra_element.pyx | 12 ++- src/sage/schemes/curves/projective_curve.py | 6 +- .../con_rational_function_field.py | 18 ++-- .../riemann_surfaces/riemann_surface.py | 4 +- src/sage/schemes/toric/ideal.py | 2 +- .../schemes/toric/weierstrass_covering.py | 6 +- src/sage/structure/parent.pyx | 2 +- src/sage/symbolic/expression.pyx | 2 +- 56 files changed, 358 insertions(+), 261 deletions(-) diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index a101064eb0e..6772673cbcb 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -462,7 +462,7 @@ def d_vector(self) -> tuple: sage: x.d_vector() (1, 1, 2, -2) """ - monomials = self.lift().dict() + monomials = self.lift().monomial_coefficients() minimal = map(min, zip(*monomials)) return tuple(-vector(minimal))[:self.parent().rank()] @@ -615,8 +615,9 @@ def theta_basis_decomposition(self): f_poly = components[g_vect].F_polynomial() g_vect = vector(g_vect) while f_poly != zero_U: - y_exp = min(f_poly.dict()) - coeff = f_poly.dict()[y_exp] + coeffs = f_poly.monomial_coefficients() + y_exp = min(coeffs) + coeff = coeffs[y_exp] g_theta = tuple(g_vect + B * vector(y_exp)) out[g_theta] = out.get(g_theta, zero_A) + A({zero_t + tuple(y_exp): coeff}) f_poly -= U({y_exp: coeff}) * A.theta_basis_F_polynomial(g_theta) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index d71f93a2600..fdcaeedaad8 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -222,7 +222,7 @@ def image_monomial(exponent): return A.zero() for g in I.gens(): - d = g.dict() + d = g.monomial_coefficients() res = A.sum(d[ex] * image_monomial(ex) for ex in d) if not res.is_zero(): raise ValueError("the differential does not preserve the ideal") @@ -303,7 +303,7 @@ def _call_(self, x): if x.is_zero(): return self.codomain().zero() res = self.codomain().zero() - dic = x.dict() + dic = x.monomial_coefficients() for key in dic: keyl = list(key) coef = dic[key] @@ -392,11 +392,11 @@ def differential_matrix(self, n): A = self.domain() dom = A.basis(n) cod = A.basis(n + 1) - cokeys = [next(iter(a.lift().dict().keys())) for a in cod] + cokeys = [next(iter(a.lift().monomial_coefficients().keys())) for a in cod] m = matrix(A.base_ring(), len(dom), len(cod)) for i, domi in enumerate(dom): im = self(domi) - dic = im.lift().dict() + dic = im.lift().monomial_coefficients() for j in dic.keys(): k = cokeys.index(j) m[i, k] = dic[j] @@ -670,11 +670,11 @@ def differential_matrix_multigraded(self, n, total=False): n = G(vector(n)) dom = A.basis(n) cod = A.basis(n + self._degree_of_differential) - cokeys = [next(iter(a.lift().dict().keys())) for a in cod] + cokeys = [next(iter(a.lift().monomial_coefficients().keys())) for a in cod] m = matrix(self.base_ring(), len(dom), len(cod)) for i, domi in enumerate(dom): im = self(domi) - dic = im.lift().dict() + dic = im.lift().monomial_coefficients() for j in dic.keys(): k = cokeys.index(j) m[i, k] = dic[j] @@ -1182,7 +1182,7 @@ def basis(self, n): basis = [] for v in free_basis: el = prod([self.gen(i)**v[i] for i in range(len(v))]) - di = el.dict() + di = el.monomial_coefficients() if len(di) == 1: k, = di.keys() if tuple(k) == v: @@ -1477,7 +1477,7 @@ def degree(self, total=False): """ if self.is_zero(): raise ValueError("the zero element does not have a well-defined degree") - exps = self.lift().dict().keys() + exps = self.monomial_coefficients().keys() degrees = self.parent()._degrees n = self.parent().ngens() l = [sum(e[i] * degrees[i] for i in range(n)) for e in exps] @@ -1548,7 +1548,7 @@ def homogeneous_parts(self): sage: a.homogeneous_parts() {1: -2*e3 + e5, 2: e1*e2, 3: e1*e3*e5 - 3*e2*e3*e5} """ - dic = self.dict() + dic = self.monomial_coefficients() terms = [self.parent()({t: dic[t]}) for t in dic.keys()] res = {} for term in terms: @@ -1559,7 +1559,7 @@ def homogeneous_parts(self): res[deg] = term return {i: res[i] for i in sorted(res.keys())} - def dict(self): + def monomial_coefficients(self): r""" A dictionary that determines the element. @@ -1569,11 +1569,18 @@ def dict(self): EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 2, 2, 3)) - sage: dic = (x*y - 5*y*z + 7*x*y^2*z^3*t).dict() - sage: sorted(dic.items()) + sage: elt = x*y - 5*y*z + 7*x*y^2*z^3*t + sage: sorted(elt.monomial_coefficients().items()) + [((0, 1, 1, 0), -5), ((1, 1, 0, 0), 1), ((1, 2, 3, 1), 7)] + + ``dict`` is an alias:: + + sage: sorted(elt.dict().items()) [((0, 1, 1, 0), -5), ((1, 1, 0, 0), 1), ((1, 2, 3, 1), 7)] """ - return self.lift().dict() + return self.lift().monomial_coefficients() + + dict = monomial_coefficients def __call__(self, *values, **kwargs): r""" @@ -1645,8 +1652,8 @@ def __call__(self, *values, **kwargs): if gstr in kwargs: images[i] = kwargs[gstr] res = 0 - for (m, c) in self.dict().items(): - term = prod((gen**y for (y, gen) in zip(m, images)), c) + for m, c in self.monomial_coefficients().items(): + term = prod((gen ** y for y, gen in zip(m, images)), c) res += term return res @@ -2000,7 +2007,7 @@ def degree(self, total=False): raise ValueError("the zero element does not have a well-defined degree") degrees = self.parent()._degrees_multi n = self.parent().ngens() - exps = self.lift().dict().keys() + exps = self.monomial_coefficients().keys() l = [sum(exp[i] * degrees[i] for i in range(n)) for exp in exps] if len(set(l)) == 1: return l[0] @@ -3861,7 +3868,7 @@ def _call_(self, x): """ codomain = self.codomain() result = codomain.zero() - for mono, coeff in x.dict().items(): + for mono, coeff in x.monomial_coefficients().items(): term = prod([gen**y for (y, gen) in zip(mono, self.im_gens())], codomain.one()) result += coeff * term diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 6080b82a396..8b73482e7bf 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -651,7 +651,7 @@ def exp_to_monomial(T): return M([(i % ngens, Ti) for i, Ti in enumerate(T) if Ti]) return self.element_class(self, {exp_to_monomial(T): c - for T, c in x.letterplace_polynomial().dict().items()}) + for T, c in x.letterplace_polynomial().monomial_coefficients().items()}) # ok, not a free algebra element (or should not be viewed as one). if isinstance(x, str): from sage.misc.sage_eval import sage_eval diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx index 2e04549ec7f..ba2a626c9f0 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx @@ -273,7 +273,7 @@ cdef get_reduced_hexagons(factory, tuple mp_params): if i % n_proc == child_id: he = req_cy(basis, r_matrix, fvars, _Nk_ij, id_anyon, sextuple) if he: - red = reduce_poly_dict(he.dict(), _nnz, _ks, one) + red = reduce_poly_dict(he.monomial_coefficients(), _nnz, _ks, one) # Avoid pickling cyclotomic coefficients red = _flatten_coeffs(red) @@ -341,7 +341,7 @@ cdef get_reduced_pentagons(factory, tuple mp_params): if i % n_proc == child_id: pe = feq_cy(basis, fvars, _Nk_ij, id_anyon, zero, nonuple, prune=True) if pe: - red = reduce_poly_dict(pe.dict(), _nnz, _ks, one) + red = reduce_poly_dict(pe.monomial_coefficients(), _nnz, _ks, one) # Avoid pickling cyclotomic coefficients red = _flatten_coeffs(red) diff --git a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx index 6c0b8d2ac27..8d6869bd484 100644 --- a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx +++ b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx @@ -26,7 +26,7 @@ cpdef inline tuple poly_to_tup(MPolynomial_libsingular poly): sage: poly_to_tup(x**2*y**4 - 4/5*x*y**2 + 1/3 * y) (((2, 4), 1), ((1, 2), -4/5), ((0, 1), 1/3)) """ - return tuple(poly.dict().items()) + return tuple(poly.monomial_coefficients().items()) cpdef inline MPolynomial_libsingular _tup_to_poly(tuple eq_tup, MPolynomialRing_libsingular parent): r""" diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 3521e9bd478..b980e2fa80c 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -148,7 +148,7 @@ def _act_(self, perm, pol): if not self.is_left(): perm, pol = pol, perm pol_dict = {} - for key, value in pol.dict().items(): + for key, value in pol.monomial_coefficients().items(): newkey = [0] * len(key) for pos, k in enumerate(key): newkey[perm(pos + 1) - 1] = k diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 48796fbd605..01390f1a5a4 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -83,7 +83,7 @@ def normalized_laurent_polynomial(R, p): u + v^-1 + u^-1 """ try: - return R({k: R._base(c) for k, c in p.dict().items()}) + return R({k: R._base(c) for k, c in p.monomial_coefficients().items()}) except (AttributeError, TypeError): return R(p) diff --git a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx index 5b99c87dd17..8eae3602f9d 100644 --- a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx @@ -139,7 +139,7 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: sorted(p) # indirect doctest [((0, 0, 0, 1, 0, 0, 0, 1), 2), ((0, 1, 0, 0, 0, 0, 1, 0), 1)] """ - cdef dict d = self._poly.dict() + cdef dict d = self._poly.monomial_coefficients() yield from d.iteritems() def _repr_(self): diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index ff888ba5aaa..99c0c1e226f 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -533,7 +533,7 @@ def product_on_basis(self, m1, m2): poly *= self._w_poly.monomial(*v) poly = poly.reduce([vp[i]**(4*k) - (1 + q**(-2*k)) * vp[i]**(2*k) + q**(-2*k) for i in range(self._n)]) - pdict = poly.dict() + pdict = poly.monomial_coefficients() ret = {(self._psi(p), tuple(e)): pdict[e] * q**q_power * sign for e in pdict} @@ -610,7 +610,7 @@ def inverse(self): for wi in wp}) poly = poly.reduce([wi**(4*k) - (1 + q**(-2*k)) * wi**(2*k) + q**(-2*k) for wi in wp]) - pdict = poly.dict() + pdict = poly.monomial_coefficients() coeff = coeff.inverse_of_unit() ret = {(p, tuple(e)): coeff * c for e, c in pdict.items()} return Cl.element_class(Cl, ret) diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index c3ff9ff25e6..1ded26a1112 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -328,11 +328,11 @@ def product_on_basis(self, left, right): def commute_w_hd(w, al): # al is given as a dictionary ret = P.one() for k in al: - x = sum(c * gens_dict[i] for i,c in alpha[k].weyl_action(w)) + x = sum(c * gens_dict[i] for i, c in alpha[k].weyl_action(w)) ret *= x**al[k] - ret = ret.dict() + ret = ret.monomial_coefficients() for k in ret: - yield (self._hd({I[i]: e for i,e in enumerate(k) if e != 0}), ret[k]) + yield (self._hd({I[i]: e for i, e in enumerate(k) if e != 0}), ret[k]) # Do Lac Ra if they are both non-trivial if dl and dr: @@ -374,7 +374,7 @@ def commute_w_hd(w, al): # al is given as a dictionary for i,c in alphacheck[k].weyl_action(right[1].reduced_word(), inverse=True)) ret *= x**dl[k] - ret = ret.dict() + ret = ret.monomial_coefficients() w = left[1]*right[1] return self._from_dict({(left[0], w, self._h({I[i]: e for i,e in enumerate(k) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index cfcb86e5c28..43d72ed7470 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -102,7 +102,7 @@ def is_unit(self): return super().is_unit() - def dict(self): + def monomial_coefficients(self): r""" Return the dictionary of ``self`` according to its lift to the cover. @@ -110,11 +110,18 @@ def dict(self): sage: from sage.algebras.splitting_algebra import SplittingAlgebra sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) - sage: (e3 + 42).dict() + sage: f = e3 + 42 + sage: f.monomial_coefficients() + {0: 42, 1: 1} + + ``dict`` is an alias:: + + sage: f.dict() {0: 42, 1: 1} """ - return self.lift().dict() + return self.lift().monomial_coefficients() + dict = monomial_coefficients # ------------------------------------------------------------------------------------------------------------------ # Parent class of the splitting algebra @@ -282,7 +289,7 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): root_names_reduces.remove(root_name) P = base_ring_step[root_names_reduces[0]] - p = P(monic_polynomial.dict()) + p = P(monic_polynomial.monomial_coefficients()) q, _ = p.quo_rem(P.gen() - first_root) verbose("Invoking recursion with: %s" % (q,)) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index ac554795cfd..8eae4797c7d 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -786,7 +786,7 @@ def _element_constructor_(self, x): return self.element_class(self, {i: R(c) for i, c in x if R(c) != zero}) x = self._poly_ring(x) return self.element_class(self, {(tuple(m), t): c - for m, c in x.dict().items()}) + for m, c in x.monomial_coefficients().items()}) def _coerce_map_from_(self, R): """ diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 39d1769f0b6..af82a1569f3 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -697,7 +697,7 @@ def from_polynomial(self, f, check=True): -F[1, 1] + F[2] """ assert self.base_ring() == f.base_ring() - exponent_coefficient = f.dict() + exponent_coefficient = f.monomial_coefficients() z = {} for e, c in exponent_coefficient.items(): I = Compositions()([ei for ei in e if ei]) diff --git a/src/sage/combinat/root_system/root_lattice_realization_algebras.py b/src/sage/combinat/root_system/root_lattice_realization_algebras.py index 030b108c774..970f134ba90 100644 --- a/src/sage/combinat/root_system/root_lattice_realization_algebras.py +++ b/src/sage/combinat/root_system/root_lattice_realization_algebras.py @@ -121,7 +121,7 @@ def from_polynomial(self, p): """ L = self.basis().keys() return self.sum_of_terms((L.from_vector(vector(t)), c) - for (t,c) in p.dict().items()) + for t, c in p.monomial_coefficients().items()) @cached_method def divided_difference_on_basis(self, weight, i): diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 0afecfa4b89..bb7b54bae4e 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -135,21 +135,25 @@ def product(self, left, right): return self._from_dict(z_elt) def from_polynomial(self, f, check=True): - """ - Return the symmetric function in the monomial basis corresponding to the polynomial ``f``. + r""" + Return the symmetric function in the monomial basis corresponding + to the polynomial ``f``. INPUT: - ``self`` -- a monomial symmetric function basis - - ``f`` -- a polynomial in finitely many variables over the same base ring as ``self``; - it is assumed that this polynomial is symmetric - - ``check`` -- boolean (default: ``True``); checks whether the polynomial is indeed symmetric + - ``f`` -- a polynomial in finitely many variables over the + same base ring as ``self``; it is assumed that this + polynomial is symmetric + - ``check`` -- boolean (default: ``True``); checks whether + the polynomial is indeed symmetric OUTPUT: - - This function converts a symmetric polynomial `f` in a polynomial ring in finitely - many variables to a symmetric function in the monomial - basis of the ring of symmetric functions over the same base ring. + - This function converts a symmetric polynomial `f` in a + polynomial ring in finitely many variables to a symmetric + function in the monomial basis of the ring of symmetric + functions over the same base ring. EXAMPLES:: @@ -173,12 +177,13 @@ def from_polynomial(self, f, check=True): sage: f = (2*m[2,1]+m[1,1]+3*m[3]).expand(3) sage: m.from_polynomial(f) m[1, 1] + 2*m[2, 1] + 3*m[3] + """ assert self.base_ring() == f.base_ring() if check and not f.is_symmetric(): raise ValueError("%s is not a symmetric polynomial" % f) out = self._from_dict({_Partitions.element_class(_Partitions, list(e)): c - for (e,c) in f.dict().items() + for e, c in f.monomial_coefficients().items() if all(e[i+1] <= e[i] for i in range(len(e)-1))}, remove_zeros=False) return out diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 47d5e0042c1..d44758ad1ff 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -6900,7 +6900,7 @@ def _from_polynomial(p, f): n = p.parent().ngens() if n == 1: d = {_Partitions.from_exp([e]): c - for e, c in p.dict().items()} + for e, c in p.monomial_coefficients().items()} else: d = {_Partitions.from_exp(e): c for e, c in p.iterator_exp_coeff(False)} diff --git a/src/sage/combinat/triangles_FHM.py b/src/sage/combinat/triangles_FHM.py index ebd457d7487..c8248bdc5f2 100644 --- a/src/sage/combinat/triangles_FHM.py +++ b/src/sage/combinat/triangles_FHM.py @@ -381,7 +381,7 @@ def dual(self): A = self._poly.parent() dict_dual = {(n - dy, n - dx): coeff - for (dx, dy), coeff in self._poly.dict().items()} + for (dx, dy), coeff in self._poly.monomial_coefficients().items()} return M_triangle(A(dict_dual), variables=(x, y)) def transmute(self): @@ -484,7 +484,7 @@ def transpose(self): A = self._poly.parent() dict_dual = {(n - dy, n - dx): coeff - for (dx, dy), coeff in self._poly.dict().items()} + for (dx, dy), coeff in self._poly.monomial_coefficients().items()} return H_triangle(A(dict_dual), variables=(x, y)) def m(self): diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index ef8d1f7f1c5..9e5ec47a40c 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -117,7 +117,9 @@ def simplify(mat): d = mat.dict() if isinstance(B, CubicHeckeExtensionRing): # Laurent polynomial cannot be reconstructed from string - res = {k: {tuple(j): u.dict() for j, u in v.dict().items()} for k, v in d.items()} + res = {k: {tuple(j): u.monomial_coefficients() + for j, u in v.monomial_coefficients().items()} + for k, v in d.items()} else: res = {k: str(v) for k, v in d.items()} return res diff --git a/src/sage/geometry/polyhedron/generating_function.py b/src/sage/geometry/polyhedron/generating_function.py index 16200bf6616..c4bece2af55 100644 --- a/src/sage/geometry/polyhedron/generating_function.py +++ b/src/sage/geometry/polyhedron/generating_function.py @@ -680,7 +680,7 @@ def __generating_function_of_integral_points__( if sort_factors: def key(t): - D = t.dict().popitem()[0] + D = t.monomial_coefficients().popitem()[0] return (-sum(abs(d) for d in D), D) terms = sorted(terms, key=key, reverse=True) return Factorization([(numerator, 1)] + @@ -748,7 +748,7 @@ def _generating_function_via_Omega_(inequalities, B, skip_indices=()): logger.debug('terms denominator %s', terms) def decode_factor(factor): - D = factor.dict() + D = factor.monomial_coefficients() assert len(D) == 1 exponent, coefficient = next(iter(D.items())) return coefficient, exponent @@ -764,7 +764,7 @@ def decode_factor(factor): lambda factor: factor[1] == 0) other_factors = tuple(factor[0] for factor in other_factors) numerator, factors_denominator = \ - _Omega_(numerator.dict(), tuple(decoded_factors)) + _Omega_(numerator.monomial_coefficients(), tuple(decoded_factors)) terms = other_factors + factors_denominator return _simplify_(numerator, terms) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 88aa11802de..8945175cf7a 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -888,7 +888,7 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): # Since the result of the calculation is known to be a Laurent polynomial # in t0 and t1 all exponents of ltemp must be divisable by 2 L = ltemp.parent() - lred = L({(k[0]/2, k[1]/2): v for k, v in ltemp.dict().items()}) + lred = L({(k[0]/2, k[1]/2): v for k, v in ltemp.monomial_coefficients().items()}) t0, t1 = R.gens() return lred(t0, t1) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index b51c08b8506..9c7b4078583 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -1188,8 +1188,8 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring) noexcept: if nMapFuncPtr is NULL: raise RuntimeError("Failed to determine nMapFuncPtr") - numerdic = elem.numerator().dict() - denomdic = elem.denominator().dict() + numerdic = elem.numerator().monomial_coefficients() + denomdic = elem.denominator().monomial_coefficients() if numerdic and not isinstance(list(numerdic)[0], (tuple, ETuple)): numerdic = {(k,):b for k,b in numerdic.items()} @@ -1303,8 +1303,8 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring) noexcept: if nMapFuncPtr is NULL: raise RuntimeError("Failed to determine nMapFuncPtr") - numerdic = elem.numerator().dict() - denomdic = elem.denominator().dict() + numerdic = elem.numerator().monomial_coefficients() + denomdic = elem.denominator().monomial_coefficients() if numerdic and not isinstance(list(numerdic)[0], (tuple, ETuple)): numerdic = {(k,):b for k,b in numerdic.items()} diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 68ee2d5ee8e..594e2ff0a3e 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -2277,7 +2277,7 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): """ P = self.codomain() try: - return P(dict([(a, self._underlying(b)) for a,b in x.dict().items()])) + return P({a: self._underlying(b) for a, b in x.monomial_coefficients().items()}) except Exception: pass try: diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index b7731d59f74..76d81db6997 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -567,7 +567,7 @@ def _subs_formal(self, *x, **kwds): base_map = kwds.get('base_map') if base_map is None: base_map = lambda t: t - for m, c in self.dict().items(): + for m, c in self.monomial_coefficients().items(): y += base_map(c)*prod([x[i]**m[i] for i in range(n) if m[i] != 0]) if self.prec() == infinity: return y @@ -1099,7 +1099,7 @@ def __mod__(self, other): return self.change_ring(Zmod(other)) raise NotImplementedError("Mod on multivariate power series ring elements not defined except modulo an integer.") - def dict(self): + def monomial_coefficients(self): """ Return underlying dictionary with keys the exponents and values the coefficients of this power series. @@ -1116,6 +1116,14 @@ def dict(self): sage: m = 2/3*t0*t1^15*t3^48 - t0^15*t1^21*t2^28*t3^5 sage: m2 = 1/2*t0^12*t1^29*t2^46*t3^6 - 1/4*t0^39*t1^5*t2^23*t3^30 + M.O(100) sage: s = m + m2 + sage: s.monomial_coefficients() + {(1, 15, 0, 48): 2/3, + (12, 29, 46, 6): 1/2, + (15, 21, 28, 5): -1, + (39, 5, 23, 30): -1/4} + + ``dict`` is an alias:: + sage: s.dict() {(1, 15, 0, 48): 2/3, (12, 29, 46, 6): 1/2, @@ -1124,9 +1132,11 @@ def dict(self): """ out_dict = {} for j in self._bg_value.coefficients(): - out_dict.update(j.dict()) + out_dict.update(j.monomial_coefficients()) return out_dict + dict = monomial_coefficients + def polynomial(self): """ Return the underlying polynomial of ``self`` as an element of @@ -1224,7 +1234,7 @@ def coefficients(self): True """ if self.is_sparse(): - return self.dict() + return self.monomial_coefficients() tmp = {} for j in self._bg_value.coefficients(): for m in j.monomials(): @@ -1727,7 +1737,7 @@ def _integral(self, xx): xxe = xx.exponents()[0] pos = [i for i, c in enumerate(xxe) if c != 0][0] # get the position of the variable res = {mon.eadd(xxe): R(co / (mon[pos]+1)) - for mon, co in self.dict().items()} + for mon, co in self.monomial_coefficients().items()} return P( res ).add_bigoh(self.prec()+1) def ogf(self): diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index ac0e594ab3c..6354bbcd382 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -224,13 +224,13 @@ def _call_(self, p): if isinstance(ring, PolynomialRing_general): for mon, pp in p.items(): assert pp.parent() is ring - for i, j in pp.dict().items(): - new_p[(i,)+(mon)] = j + for i, j in pp.monomial_coefficients().items(): + new_p[(i,) + (mon)] = j elif isinstance(ring, MPolynomialRing_base): for mon, pp in p.items(): assert pp.parent() is ring - for mmon, q in pp.dict().items(): - new_p[tuple(mmon)+mon] = q + for mmon, q in pp.monomial_coefficients().items(): + new_p[tuple(mmon) + mon] = q else: raise RuntimeError p = new_p @@ -642,7 +642,7 @@ def _call_(self, p): # apply _sub_specialization to each coefficient # in the flattened polynomial tmp = {} - for exponent, coefficient in flat.dict().items(): + for exponent, coefficient in flat.monomial_coefficients().items(): # Fix the type of exponent from (a,) to a # (necessary for R(tmp) later) if isinstance(exponent, ETuple) and len(exponent) == 1: diff --git a/src/sage/rings/polynomial/laurent_polynomial.pxd b/src/sage/rings/polynomial/laurent_polynomial.pxd index 8e9107aeb47..249e69b49e2 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pxd +++ b/src/sage/rings/polynomial/laurent_polynomial.pxd @@ -8,10 +8,10 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): cpdef _floordiv_(self, other) cpdef long number_of_terms(self) except -1 cpdef dict dict(self) + cpdef dict monomial_coefficients(self) cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef ModuleElement __u cdef long __n cpdef _normalize(self) cpdef _unsafe_mutate(self, i, value) - diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 8b1033f4fd5..4b6ad584cb0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -233,6 +233,9 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): """ raise NotImplementedError + cpdef dict monomial_coefficients(self): + raise NotImplementedError + def map_coefficients(self, f, new_base_ring=None): """ Apply ``f`` to the coefficients of ``self``. @@ -294,7 +297,8 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): R = R.change_ring(new_base_ring) elif isinstance(f, Map): R = R.change_ring(f.codomain()) - return R(dict([(k, f(v)) for (k, v) in self.dict().items()])) + return R(dict([(k, f(v)) + for k, v in self.monomial_coefficients().items()])) cdef class LaurentPolynomial_univariate(LaurentPolynomial): @@ -838,7 +842,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): d = {repr(g): R.var(g) for g in self._parent.gens()} return self.subs(**d) - cpdef dict dict(self): + cpdef dict monomial_coefficients(self): """ Return a dictionary representing ``self``. @@ -848,16 +852,19 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: Q. = LaurentPolynomialRing(R) sage: f = (x^3 + y/t^3)^3 + t^2; f y^3*t^-9 + 3*x^3*y^2*t^-6 + 3*x^6*y*t^-3 + x^9 + t^2 - sage: f.dict() + sage: f.monomial_coefficients() {-9: y^3, -6: 3*x^3*y^2, -3: 3*x^6*y, 0: x^9, 2: 1} - sage: f.monomial_coefficients() + ``dict`` is an alias:: + + sage: f.dict() {-9: y^3, -6: 3*x^3*y^2, -3: 3*x^6*y, 0: x^9, 2: 1} """ - cdef dict d = self.__u.dict() - return {k+self.__n: d[k] for k in d} + cdef dict d = self.__u.monomial_coefficients() + return {k + self.__n: d[k] for k in d} - monomial_coefficients = dict + cpdef dict dict(self): + return self.monomial_coefficients() def coefficients(self): """ @@ -2129,7 +2136,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Multivariate Polynomial Ring in t, tinv over Rational Field """ dres = {} - for (e, c) in self.dict().items(): + for e, c in self.monomial_coefficients().items(): if e > 0: dres[(e, 0)] = c else: diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 4b14f79cdca..5653459f106 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -281,7 +281,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): # self._parent.variable_names(), # self._parent.base_ring() # ) - cdef dict D = self._poly.dict() + cdef dict D = self._poly.monomial_coefficients() cdef ETuple e if i is None: @@ -309,12 +309,12 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: L. = LaurentPolynomialRing(QQ) sage: a = w^2*z^-1 +3 - sage: a.dict() # indirect doctest + sage: a.monomial_coefficients() # indirect doctest {(0, 0): 3, (2, -1): 1} """ # cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), # self._parent.base_ring()) - cdef dict D = self._poly.dict() + cdef dict D = self._poly.monomial_coefficients() cdef dict DD if self._mon.is_constant(): self._prod = PolyDict(D) @@ -448,7 +448,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): """ cdef ETuple e if self._poly.is_term(): - (e, c), = self.dict().items() + (e, c), = self.monomial_coefficients().items() e = e.emul(-1) P = self._parent try: @@ -574,7 +574,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): Multivariate Polynomial Ring in t1, t1inv, t2, t2inv over Rational Field """ dres = {} - for (e, c) in self.dict().items(): + for e, c in self.monomial_coefficients().items(): exps = [] for t in e: if t > 0: @@ -742,7 +742,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): self._compute_polydict() if m._prod is None: m._compute_polydict() - return self._parent(self._prod.coefficient(m.dict())) + return self._parent(self._prod.coefficient(m.monomial_coefficients())) def coefficients(self): """ @@ -781,7 +781,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: f.variables(sort=False) #random (y, z, x) """ - cdef dict d = self.dict() + cdef dict d = self.monomial_coefficients() cdef tuple g = self._parent.gens() cdef Py_ssize_t nvars = len(g) cdef set vars = set() @@ -794,7 +794,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): v.sort() return tuple(v) - cpdef dict dict(self): + cpdef dict monomial_coefficients(self): """ Return ``self`` represented as a ``dict``. @@ -802,17 +802,20 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: L. = LaurentPolynomialRing(QQ) sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: sorted(f.dict().items()) + sage: sorted(f.monomial_coefficients().items()) [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] - sage: sorted(f.monomial_coefficients().items()) + ``dict`` is an alias:: + + sage: sorted(f.dict().items()) [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] """ if self._prod is None: self._compute_polydict() return < dict > self._prod.dict() - monomial_coefficients = dict + cpdef dict dict(self): + return self.monomial_coefficients() def _fraction_pair(self): """ @@ -1563,11 +1566,11 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): except ValueError: # call _derivative() recursively on coefficients return P({m: c._derivative(var) - for (m, c) in self.dict().iteritems()}) + for m, c in self.monomial_coefficients().iteritems()}) # compute formal derivative with respect to generator cdef dict d = {} - for m, c in self.dict().iteritems(): + for m, c in self.monomial_coefficients().iteritems(): if m[index] != 0: new_m = [u for u in m] new_m[index] += -1 @@ -1648,7 +1651,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if R is None: R = LaurentPolynomialRing(self.base_ring(), x) - return R({m[i]: c for m, c in self.dict().iteritems()}) + return R({m[i]: c for m, c in self.monomial_coefficients().iteritems()}) def monomial_reduction(self): """ @@ -1718,7 +1721,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): cdef list f = [] cdef dict d for t in pf: - d = (t[0].dict()) + d = (t[0].monomial_coefficients()) if len(d) == 1: # monomials are units u *= self.parent(d) ** t[1] else: diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 680c4c0138c..c17819a1b2c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -388,7 +388,8 @@ def value(d, R): return {k: value(v, P.base_ring()) for k, v in D.items()} except (ValueError, TypeError): pass - return sum(P({k: 1}) * value(v, P) for k, v in D.items()).dict() + return sum(P({k: 1}) * value(v, P) + for k, v in D.items()).monomial_coefficients() def from_fraction_field(L, x): r""" @@ -535,9 +536,9 @@ def _element_constructor_(self, x): P = x.parent() if set(self.variable_names()) & set(P.variable_names()): if isinstance(x, LaurentPolynomial_univariate): - d = {(k,): v for k, v in x.dict().items()} + d = {(k,): v for k, v in x.monomial_coefficients().items()} else: - d = x.dict() + d = x.monomial_coefficients() x = _split_laurent_polynomial_dict_(self, P, d) x = {k[0]: v for k, v in x.items()} elif P is self.base_ring(): @@ -545,7 +546,7 @@ def _element_constructor_(self, x): elif x.is_constant() and self.has_coerce_map_from(x.parent().base_ring()): return self(x.constant_coefficient()) elif len(self.variable_names()) == len(P.variable_names()): - x = x.dict() + x = x.monomial_coefficients() elif isinstance(x, FractionFieldElement): # since the field of fraction of self is defined corresponding to @@ -762,9 +763,9 @@ def _element_constructor_(self, x, mon=None): pass elif set(self.variable_names()) & set(P.variable_names()): if isinstance(x, LaurentPolynomial_univariate): - d = {(k,): v for k, v in x.dict().items()} + d = {(k,): v for k, v in x.monomial_coefficients().items()} else: - d = x.dict() + d = x.monomial_coefficients() x = _split_laurent_polynomial_dict_(self, P, d) elif P is self.base_ring(): from sage.rings.polynomial.polydict import ETuple @@ -773,7 +774,7 @@ def _element_constructor_(self, x, mon=None): elif x.is_constant() and self.has_coerce_map_from(P.base_ring()): return self(x.constant_coefficient()) elif len(self.variable_names()) == len(P.variable_names()): - x = x.dict() + x = x.monomial_coefficients() elif isinstance(x, FractionFieldElement): # since the field of fraction of self is defined corresponding to diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index c1fcaba8187..a537334ba3f 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -243,7 +243,7 @@ cdef class MPolynomial(CommutativePolynomial): - Didier Deshommes """ - d = self.dict() + d = self.monomial_coefficients() return [d[i] for i in self.exponents()] def truncate(self, var, n): @@ -260,8 +260,8 @@ cdef class MPolynomial(CommutativePolynomial): ind = Z.index(var) except ValueError: raise ValueError("var must be one of the generators of the parent polynomial ring.") - d = self.dict() - return R(dict([(k, c) for k, c in d.iteritems() if k[ind] < n])) + return R({k: c for k, c in self.monomial_coefficients().iteritems() + if k[ind] < n}) def _fast_callable_(self, etb): r""" @@ -299,9 +299,9 @@ cdef class MPolynomial(CommutativePolynomial): n = len(x) expr = etb.constant(self.base_ring().zero()) - for (m, c) in self.dict().iteritems(): - monom = prod([ x[i]**m[i] for i in range(n) if m[i] != 0], - etb.constant(c)) + for m, c in self.monomial_coefficients().iteritems(): + monom = prod([x[i] ** m[i] for i in range(n) if m[i] != 0], + etb.constant(c)) expr = expr + monom return expr @@ -426,11 +426,11 @@ cdef class MPolynomial(CommutativePolynomial): d = self.degree(var) B = ring.base_ring() w = {remove_from_tuple(e, ind): val - for e, val in self.dict().iteritems() if not e[ind]} + for e, val in self.monomial_coefficients().iteritems() if not e[ind]} v = [B(w)] # coefficients that don't involve var z = var for i in range(1,d+1): - c = self.coefficient(z).dict() + c = self.coefficient(z).monomial_coefficients() w = {remove_from_tuple(e, ind): val for e, val in c.iteritems()} v.append(B(w)) z *= var @@ -483,7 +483,7 @@ cdef class MPolynomial(CommutativePolynomial): vars = self._parent.variable_names_recursive() cdef tuple my_vars = self._parent.variable_names() if vars == my_vars: - return self.dict() + return self.monomial_coefficients() elif my_vars[-1] not in vars: x = base_ring(self) if base_ring is not None else self const_ix = ETuple((0,)*len(vars)) @@ -511,13 +511,13 @@ cdef class MPolynomial(CommutativePolynomial): new_map[k] -= m tmp = [0] * (len(vars) - m) try: - for ix,a in self.dict().iteritems(): + for ix, a in self.monomial_coefficients().iteritems(): for k in range(len(my_vars)): tmp[new_map[k]] = ix[k] postfix = ETuple(tmp) mpoly = a._mpoly_dict_recursive(prev_vars, base_ring) - for prefix,b in mpoly.iteritems(): - D[prefix+postfix] = b + for prefix, b in mpoly.iteritems(): + D[prefix + postfix] = b return D except AttributeError: @@ -527,7 +527,7 @@ cdef class MPolynomial(CommutativePolynomial): base_ring = None tmp = [0] * len(vars) - for ix,a in self.dict().iteritems(): + for ix, a in self.monomial_coefficients().iteritems(): for k in range(len(my_vars)): tmp[mapping[k]] = ix[k] if base_ring is not None: @@ -578,7 +578,7 @@ cdef class MPolynomial(CommutativePolynomial): cdef long result_mon var_name_hash = [hash(v) for v in self._parent.variable_names()] cdef long c_hash - for m,c in self.dict().iteritems(): + for m, c in self.monomial_coefficients().iteritems(): # I'm assuming (incorrectly) that hashes of zero indicate that the element is 0. # This assumption is not true, but I think it is true enough for the purposes and it # it allows us to write fast code that omits terms with 0 coefficients. This is @@ -913,7 +913,7 @@ cdef class MPolynomial(CommutativePolynomial): """ if isinstance(R, Map): return self.map_coefficients(R) - return self.parent().change_ring(R)(self.dict()) + return self.parent().change_ring(R)(self.monomial_coefficients()) def is_symmetric(self, group=None): r""" @@ -997,7 +997,7 @@ cdef class MPolynomial(CommutativePolynomial): raise ValueError("argument must be a permutation group") gens = [S(g) for g in gens] - cdef dict coeffs = self.dict() + cdef dict coeffs = self.monomial_coefficients() zero = self.base_ring().zero() return all(coeffs.get(g._act_on_etuple_on_position(e), zero) == coeff for e, coeff in coeffs.items() for g in gens) @@ -1360,7 +1360,7 @@ cdef class MPolynomial(CommutativePolynomial): R = R.change_ring(new_base_ring) elif isinstance(f, Map): R = R.change_ring(f.codomain()) - return R(dict([(k,f(v)) for (k,v) in self.dict().items()])) + return R({k: f(v) for k, v in self.monomial_coefficients().items()}) def _norm_over_nonprime_finite_field(self): r""" @@ -2611,7 +2611,7 @@ cdef class MPolynomial(CommutativePolynomial): # K[x,y,...] as K[x][y]... if not self.constant_coefficient().is_unit(): return False - cdef dict d = self.dict() + cdef dict d = self.monomial_coefficients() cdef ETuple zero_key = ETuple({}, int(self.parent().ngens())) d.pop(zero_key, None) return all(d[k].is_nilpotent() for k in d) @@ -2646,7 +2646,7 @@ cdef class MPolynomial(CommutativePolynomial): # Section 7.3 Exercise 33). # This generalizes easily to the multivariate case, by considering # K[x,y,...] as K[x][y]... - d = self.dict() + d = self.monomial_coefficients() return all(c.is_nilpotent() for c in d.values()) def _test_subs(self, tester=None, **options): diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index e856fd9e46e..2f3310b3af9 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -74,7 +74,6 @@ from sage.rings.rational_field import QQ from sage.rings.fraction_field import FractionField - class MPolynomial_element(MPolynomial): r""" Generic multivariate polynomial. @@ -802,7 +801,7 @@ def monomial_coefficient(self, mon): zero = self.parent().base_ring().zero() return self.element().get(exp, zero) - def dict(self): + def monomial_coefficients(self): """ Return underlying dictionary with keys the exponents and values the coefficients of this polynomial. @@ -812,15 +811,17 @@ def dict(self): sage: # needs sage.rings.number_field sage: R. = PolynomialRing(QQbar, order='lex') sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: f.dict() + sage: f.monomial_coefficients() {(1, 5, 2): 1, (2, 0, 1): 1, (4, 1, 3): 1} - sage: f.monomial_coefficients() # needs sage.rings.number_field + ``dict`` is an alias:: + + sage: f.dict() # needs sage.rings.number_field {(1, 5, 2): 1, (2, 0, 1): 1, (4, 1, 3): 1} """ return self.element().dict() - monomial_coefficients = dict + dict = monomial_coefficients def __iter__(self): """ @@ -1867,12 +1868,12 @@ def _floordiv_(self, right): """ # handle division by monomials without using Singular - if len(right.dict()) == 1: + if len(right.monomial_coefficients()) == 1: P = self.parent() ret = P(0) - denC,denM = next(iter(right)) - for c,m in self: - t = c*m + denC, denM = next(iter(right)) + for c, m in self: + t = c * m if denC.divides(c) and P.monomial_divides(denM, m): ret += P.monomial_quotient(t, right, coeff=True) return ret @@ -1928,7 +1929,8 @@ def _derivative(self, var=None): if index == -1: # var is not a generator; do term-by-term differentiation recursively # var may be, for example, a generator of the base ring - d = dict([(e, x._derivative(var)) for (e, x) in self.dict().items()]) + d = dict([(e, x._derivative(var)) + for e, x in self.monomial_coefficients().items()]) d = polydict.PolyDict(d, check=False) d.remove_zeros() return MPolynomial_polydict(P, d) @@ -2025,7 +2027,7 @@ def integral(self, var=None): # var is not a generator; do term-by-term integration recursively # var may be, for example, a generator of the base ring d = {e: x.integral(var) - for e, x in self.dict().items()} + for e, x in self.monomial_coefficients().items()} d = polydict.PolyDict(d, check=False) d.remove_zeros() else: diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 307735c46ba..0f05f3a93d9 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2088,10 +2088,11 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): except TypeError: # give up, evaluate functional sage_res = parent.base_ring().zero() - for m, c in self.dict().iteritems(): + for m, c in self.monomial_coefficients().iteritems(): sage_res += c * mul([x[i] ** m[i] for i in m.nonzero_positions()]) else: - singular_polynomial_call(&res, self._poly, _ring, coerced_x, MPolynomial_libsingular_get_element) + singular_polynomial_call(&res, self._poly, _ring, coerced_x, + MPolynomial_libsingular_get_element) if res == NULL: return res_parent(0) @@ -2983,7 +2984,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): return self._parent._base._zero_element - def dict(self): + def monomial_coefficients(self): """ Return a dictionary representing ``self``. This dictionary is in the same format as the generic MPolynomial: The dictionary @@ -2993,10 +2994,12 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: R. = QQ[] sage: f = 2*x*y^3*z^2 + 1/7*x^2 + 2/3 - sage: f.dict() + sage: f.monomial_coefficients() {(0, 0, 0): 2/3, (1, 3, 2): 2, (2, 0, 0): 1/7} - sage: f.monomial_coefficients() + ``dict`` is an alias:: + + sage: f.dict() {(0, 0, 0): 2/3, (1, 3, 2): 2, (2, 0, 0): 1/7} """ cdef poly *p @@ -3019,7 +3022,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): p = pNext(p) return pd - monomial_coefficients = dict + def dict(self): + return self.monomial_coefficients() def iterator_exp_coeff(self, as_ETuples=True): """ @@ -3612,8 +3616,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): for m, v in items: gg[g.index(m)] = v y = parent.base_ring().zero() - for (m,c) in self.dict().items(): - y += c*mul([ gg[i]**m[i] for i in m.nonzero_positions()]) + for m, c in self.monomial_coefficients().items(): + y += c*mul([gg[i] ** m[i] for i in m.nonzero_positions()]) return y _f = ( v)._poly if p_IsConstant(_f, _ring): @@ -5227,7 +5231,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: parent(h(R.0,0)) Univariate Polynomial Ring in x over Rational Field """ - return unpickle_MPolynomial_libsingular, (self._parent, self.dict()) + return unpickle_MPolynomial_libsingular, (self._parent, + self.monomial_coefficients()) def _im_gens_(self, codomain, im_gens, base_map=None): """ @@ -5268,8 +5273,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): if base_map is None: # Just use conversion base_map = codomain - for (m,c) in self.dict().iteritems(): - y += base_map(c)*mul([ im_gens[i]**m[i] for i in range(n) if m[i]]) + for m, c in self.monomial_coefficients().iteritems(): + y += base_map(c) * mul([im_gens[i] ** m[i] for i in range(n) if m[i]]) return y def _derivative(self, MPolynomial_libsingular var): @@ -5396,7 +5401,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): v = ETuple({index: 1}, len(gens)) _p = p_ISet(0, _ring) - for (exp, coeff) in self.dict().iteritems(): + for exp, coeff in self.monomial_coefficients().iteritems(): nexp = exp.eadd(v) # new exponent mon = p_Init(_ring) p_SetCoeff(mon, sa2si(coeff / (1 + exp[index]), _ring), _ring) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index 588358ab3d9..41cc1fb7c87 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -430,13 +430,16 @@ def __call__(self, x=0, check=True): if P is self: return x - elif P == self: + + if P == self: return MPolynomial_polydict(self, x.element().dict()) - elif self.base_ring().has_coerce_map_from(P): + + if self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c}) - elif len(P.variable_names()) == len(self.variable_names()): + + if len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with @@ -446,63 +449,76 @@ def __call__(self, x=0, check=True): for i, a in D.items(): D[i] = K(a) return MPolynomial_polydict(self, D) - elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): + + if (set(P.variable_names()).issubset(set(self.variable_names())) + and self.base_ring().has_coerce_map_from(P.base_ring())): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) - else: - return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) + + return MPolynomial_polydict(self, + x._mpoly_dict_recursive(self.variable_names(), + self.base_ring())) elif isinstance(x, MPolynomial_libsingular): P = x.parent() if P == self: - return MPolynomial_polydict(self, x.dict()) - elif self.base_ring().has_coerce_map_from(P): + return MPolynomial_polydict(self, x.monomial_coefficients()) + + if self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c}) - elif len(P.variable_names()) == len(self.variable_names()): + + if len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() - D = x.dict() + D = x.monomial_coefficients() for i, a in D.items(): D[i] = K(a) return MPolynomial_polydict(self, D) - elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): + + if (set(P.variable_names()).issubset(set(self.variable_names())) + and self.base_ring().has_coerce_map_from(P.base_ring())): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) - else: - return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) - elif isinstance(x, polynomial_element.Polynomial): - return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) + return MPolynomial_polydict(self, + x._mpoly_dict_recursive(self.variable_names(), + self.base_ring())) - elif isinstance(x, PolyDict): + if isinstance(x, polynomial_element.Polynomial): + return MPolynomial_polydict(self, + x._mpoly_dict_recursive(self.variable_names(), + self.base_ring())) + + if isinstance(x, PolyDict): return MPolynomial_polydict(self, x) - elif isinstance(x, dict): + if isinstance(x, dict): K = self.base_ring() return MPolynomial_polydict(self, {i: K(a) for i, a in x.items()}) - elif isinstance(x, fraction_field_element.FractionFieldElement) and x.parent().ring() == self: + if (isinstance(x, fraction_field_element.FractionFieldElement) + and x.parent().ring() == self): if x.denominator() == 1: return x.numerator() - else: - raise TypeError("unable to coerce since the denominator is not 1") - elif isinstance(x, sage.interfaces.abc.SingularElement) and self._has_singular: + raise TypeError("unable to coerce since the denominator is not 1") + + if isinstance(x, sage.interfaces.abc.SingularElement) and self._has_singular: self._singular_().set_ring() try: return x.sage_poly(self) except TypeError: raise TypeError("unable to coerce singular object") - elif hasattr(x, '_polynomial_'): + if hasattr(x, '_polynomial_'): return x._polynomial_(self) - elif isinstance(x, str): + if isinstance(x, str): from sage.misc.sage_eval import sage_eval try: x = sage_eval(x, self.gens_dict_recursive()) @@ -510,7 +526,7 @@ def __call__(self, x=0, check=True): raise TypeError("unable to evaluate {!r} in {}".format(x, self)) return self(x) - elif isinstance(x, sage.interfaces.abc.Macaulay2Element): + if isinstance(x, sage.interfaces.abc.Macaulay2Element): try: s = x.sage_polystring() if len(s) == 0: @@ -524,7 +540,7 @@ def __call__(self, x=0, check=True): raise TypeError("Unable to coerce macaulay2 object") return MPolynomial_polydict(self, x) - elif isinstance(x, pari_gen) and x.type() == 't_POL': + if isinstance(x, pari_gen) and x.type() == 't_POL': # This recursive approach is needed because PARI # represents multivariate polynomials as iterated # univariate polynomials. Below, v is the variable @@ -538,9 +554,9 @@ def __call__(self, x=0, check=True): if isinstance(x, dict): return MPolynomial_polydict(self, x) - else: - c = self.base_ring()(x) - return MPolynomial_polydict(self, {self._zero_tuple: c}) + + c = self.base_ring()(x) + return MPolynomial_polydict(self, {self._zero_tuple: c}) # The following methods are handy for implementing Groebner # basis algorithms. They do only superficial type/sanity checks @@ -627,8 +643,8 @@ def monomial_quotient(self, f, g, coeff=False): if not g: raise ZeroDivisionError - fd = f.dict() - gd = g.dict() + fd = f.monomial_coefficients() + gd = g.monomial_coefficients() if not coeff: f = next(iter(fd)) @@ -682,8 +698,8 @@ def monomial_lcm(self, f, g): """ one = self.base_ring().one() - f, = f.dict() - g, = g.dict() + f, = f.monomial_coefficients() + g, = g.monomial_coefficients() length = len(f) @@ -785,8 +801,8 @@ def monomial_divides(self, a, b): if not a: raise ZeroDivisionError - a, = a.dict() - b, = b.dict() + a, = a.monomial_coefficients() + b, = b.monomial_coefficients() return all(b[i] >= a[i] for i in b.common_nonzero_positions(a)) @@ -879,7 +895,7 @@ def addwithcarry(tempvector, maxvector, pos): one = self.base_ring().one() M = list() - v, = t.dict() + v, = t.monomial_coefficients() maxvector = list(v) tempvector = [0] * len(maxvector) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index fa9947b028e..dffe6cb80c1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -619,12 +619,14 @@ cdef class MPolynomialRing_base(CommutativeRing): """ # This is probably horribly inefficient other_vars = list(x.parent().variable_names()) - name_mapping = [(other_vars.index(var) if var in other_vars else -1) for var in self.variable_names()] + name_mapping = [(other_vars.index(var) if var in other_vars else -1) + for var in self.variable_names()] K = self.base_ring() D = {} var_range = range(len(self.variable_names())) - for ix, a in x.dict().iteritems(): - ix = ETuple([0 if name_mapping[t] == -1 else ix[name_mapping[t]] for t in var_range]) + for ix, a in x.monomial_coefficients().iteritems(): + ix = ETuple([0 if name_mapping[t] == -1 else ix[name_mapping[t]] + for t in var_range]) D[ix] = K(a) return D diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 20a61096548..797200f4e40 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -311,7 +311,7 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, decoded_factors = [] for factor in factors_denominator: factor = L(factor) - D = factor.dict() + D = factor.monomial_coefficients() if not D: raise ZeroDivisionError('Denominator contains a factor 0.') elif len(D) == 1: @@ -331,7 +331,7 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, numerator = L(numerator) / prod(to_numerator) result_numerator, result_factors_denominator = \ - _Omega_(numerator.dict(), decoded_factors) + _Omega_(numerator.monomial_coefficients(), decoded_factors) if result_numerator == 0: return Factorization([], unit=result_numerator) @@ -589,7 +589,7 @@ def subs_power(expression, var, exponent): It is assumed that ``var`` only occurs with exponents divisible by ``exponent``. """ - p = tuple(var.dict().popitem()[0]).index(1) # var is the p-th generator + p = tuple(var.monomial_coefficients().popitem()[0]).index(1) # var is the p-th generator def subs_e(e): e = list(e) @@ -597,7 +597,8 @@ def subs_e(e): e[p] = e[p] // exponent return tuple(e) parent = expression.parent() - result = parent({subs_e(e): c for e, c in expression.dict().items()}) + result = parent({subs_e(e): c + for e, c in expression.monomial_coefficients().items()}) return result def de_power(expression): diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pxd b/src/sage/rings/polynomial/ore_polynomial_element.pxd index f38bcb0f0c5..73bc162a146 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pxd +++ b/src/sage/rings/polynomial/ore_polynomial_element.pxd @@ -17,7 +17,7 @@ cdef class OrePolynomial(AlgebraElement): cpdef bint is_zero(self) noexcept cpdef bint is_one(self) noexcept - + cdef _left_quo_rem(self, OrePolynomial other) cdef _right_quo_rem(self, OrePolynomial other) cdef OrePolynomial _left_lcm_cofactor(self, OrePolynomial other) @@ -39,6 +39,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cpdef _mul_(self, other) cpdef dict dict(self) + cpdef dict monomial_coefficients(self) cpdef list list(self, bint copy=*) diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 1acc82dd583..09146960c86 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -2481,7 +2481,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): else: return (self)._coeffs - cpdef dict dict(self): + cpdef dict monomial_coefficients(self): r""" Return a dictionary representation of ``self``. @@ -2506,7 +2506,8 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): X[i] = c return X - monomial_coefficients = dict + cpdef dict dict(self): + return self.monomial_coefficients() cpdef Integer degree(self): r""" diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index 604764eff35..668f66fe574 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -51,7 +51,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, ab Check that :issue:`13620` has been fixed:: sage: f = R.zero() - sage: R(f.dict()) + sage: R(f.monomial_coefficients()) 0 Check that :issue:`29829` has been fixed:: diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index dbb7a6f0565..04fb9518ab8 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -76,7 +76,6 @@ from sage.arith.power cimport generic_power from sage.arith.misc import crt from sage.arith.long cimport pyobject_to_long from sage.misc.mrange import cartesian_product_iterator -from sage.misc.superseded import deprecated_function_alias from sage.structure.factorization import Factorization from sage.structure.richcmp cimport (richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn) @@ -174,7 +173,6 @@ cpdef is_Polynomial(f): sage: is_Polynomial(f) False """ - from sage.misc.superseded import deprecation deprecation(32709, "the function is_Polynomial is deprecated; use isinstance(x, sage.rings.polynomial.polynomial_element.Polynomial) instead") return isinstance(f, Polynomial) @@ -862,7 +860,7 @@ cdef class Polynomial(CommutativePolynomial): return R(pol) if pol._parent.is_sparse(): coeff_sparse = {} - coeff_dict = pol.dict() + coeff_dict = pol.monomial_coefficients() for i in coeff_dict: coeff_sparse[i * d] = coeff_dict[i] return R(coeff_sparse, check=False) @@ -883,7 +881,7 @@ cdef class Polynomial(CommutativePolynomial): if a.is_monomial(): etup = ETuple(( a).degrees()) if pol._parent.is_sparse(): - coeff_dict = pol.dict() + coeff_dict = pol.monomial_coefficients() return R({etup.emul(key): coeff_dict[key] for key in coeff_dict}) # Dense version return R({etup.emul(i): c for i, c in enumerate(pol)}) @@ -2648,7 +2646,6 @@ cdef class Polynomial(CommutativePolynomial): # ensure that the degree is positive. degree = ZZ(degree) if degree < 0: - from sage.misc.superseded import deprecation deprecation(37170, "negative ``degree`` will be disallowed. Instead use the bool `assume_equal_deg`.") degree = -degree assume_equal_deg = True @@ -2931,7 +2928,7 @@ cdef class Polynomial(CommutativePolynomial): q = right sparse = self.parent().is_sparse() if sparse: - d = self.dict() + d = self.monomial_coefficients() else: c = self.list(copy=False) while q > 0: @@ -4464,7 +4461,7 @@ cdef class Polynomial(CommutativePolynomial): if self.get_unsafe(n) else zero for n in range(self.degree() + 1)] return S(p) - def dict(self): + def monomial_coefficients(self): """ Return a sparse dictionary representation of this univariate polynomial. @@ -4473,10 +4470,12 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = QQ[] sage: f = x^3 + -1/7*x + 13 - sage: f.dict() + sage: f.monomial_coefficients() {0: 13, 1: -1/7, 3: 1} - sage: f.monomial_coefficients() + ``dict`` is an alias:: + + sage: f.dict() {0: 13, 1: -1/7, 3: 1} """ cdef dict X = {} @@ -4488,7 +4487,8 @@ cdef class Polynomial(CommutativePolynomial): X[i] = c return X - monomial_coefficients = dict + def dict(self): + return self.monomial_coefficients() def factor(self, **kwargs): r""" @@ -10600,7 +10600,7 @@ cdef class Polynomial(CommutativePolynomial): R = R.change_ring(new_base_ring) elif isinstance(f, Map): R = R.change_ring(f.codomain()) - return R({k: f(v) for k, v in self.dict().items()}) + return R({k: f(v) for k, v in self.monomial_coefficients().items()}) def is_cyclotomic(self, certificate=False, algorithm='pari'): r""" diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index abfe216aae8..c3df26200e2 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -39,16 +39,16 @@ except ImportError: pari_gen = () -from sage.structure.richcmp import richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn from sage.structure.element import coerce_binop, parent +from sage.structure.factorization import Factorization +from sage.structure.richcmp import richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn from sage.rings.infinity import infinity, Infinity from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.structure.factorization import Factorization - from sage.rings.padics.precision_error import PrecisionError + class Polynomial_generic_sparse(Polynomial): """ A generic sparse polynomial. @@ -99,18 +99,18 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): R = parent.base_ring() if isinstance(x, Polynomial): if x.parent() == self.parent(): - x = dict(x.dict()) + x = x.monomial_coefficients() elif x.parent() == R: - x = {0:x} + x = {0: x} else: w = {} - for n, c in x.dict().items(): + for n, c in x.monomial_coefficients().items(): w[n] = R(c) # The following line has been added in github issue #9944. # Apparently, the "else" case has never occurred before. x = w elif isinstance(x, (list, tuple)): - x = dict((i, c) for (i, c) in enumerate(x) if c) + x = {i: c for i, c in enumerate(x) if c} elif isinstance(x, pari_gen): y = {} for i in range(len(x)): @@ -118,7 +118,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): x = y check = True elif not isinstance(x, dict): - x = {0:x} # constant polynomials + x = {0: x} # constant polynomials if check: self.__coeffs = {} for i, z in x.items(): @@ -128,7 +128,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): if check: self.__normalize() - def dict(self): + def monomial_coefficients(self): """ Return a new copy of the dict of the underlying elements of ``self``. @@ -138,18 +138,20 @@ def dict(self): sage: R. = PolynomialRing(Integers(8), sparse=True) sage: f = 5 + w^1997 - w^10000; f 7*w^10000 + w^1997 + 5 - sage: d = f.dict(); d + sage: d = f.monomial_coefficients(); d {0: 5, 1997: 1, 10000: 7} sage: d[0] = 10 - sage: f.dict() + sage: f.monomial_coefficients() {0: 5, 1997: 1, 10000: 7} - sage: f.monomial_coefficients() + ``dict`` is an alias:: + + sage: f.dict() {0: 5, 1997: 1, 10000: 7} """ return dict(self.__coeffs) - monomial_coefficients = dict + dict = monomial_coefficients def coefficients(self, sparse=True): """ diff --git a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx index b3ce1183e5e..01aca9fed01 100644 --- a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx +++ b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx @@ -58,7 +58,7 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): P = self.codomain() f = self.underlying_map() if P.is_sparse(): - return P({a: f(b) for a, b in x.dict().iteritems()}) + return P({a: f(b) for a, b in x.monomial_coefficients().iteritems()}) else: return P([f(b) for b in x]) @@ -88,7 +88,8 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): P = self.codomain() f = self.underlying_map() if P.is_sparse(): - return P({a: f(b) for a, b in x.dict().iteritems()}, *args, **kwds) + return P({a: f(b) for a, b in x.monomial_coefficients().iteritems()}, + *args, **kwds) else: return P([f(b) for b in x], *args, **kwds) diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index 42cf467912b..44c4be93423 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -58,11 +58,11 @@ cdef class PowerSeries_mpoly(PowerSeries): d = {} if isinstance(B, MPolynomialRing_base): for i in range(len(v)): - for n, c in v[i].dict().iteritems(): + for n, c in v[i].monomial_coefficients().iteritems(): d[tuple(n) + (i,)] = c else: for i in range(len(v)): - for n, c in v[i].dict().iteritems(): + for n, c in v[i].monomial_coefficients().iteritems(): d[(n,i)] = c self.__f = S(d) diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index 0e491cad78a..ca79b979228 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -734,7 +734,7 @@ cdef class PowerSeries_pari(PowerSeries): else: return [R(g)] + [R.zero()] * (n - 1) - def dict(self): + def monomial_coefficients(self): """ Return a dictionary of coefficients for ``self``. @@ -746,10 +746,18 @@ cdef class PowerSeries_pari(PowerSeries): sage: R. = PowerSeriesRing(ZZ, implementation='pari') sage: f = 1 + t^10 + O(t^12) + sage: f.monomial_coefficients() + {0: 1, 10: 1} + + ``dict`` is an alias:: + sage: f.dict() {0: 1, 10: 1} """ - return self.polynomial().dict() + return self.polynomial().monomial_coefficients() + + def dict(self): + return self.monomial_coefficients() def _derivative(self, var=None): """ diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 91f790ffa16..4f5e02df06c 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -794,7 +794,7 @@ cdef class PowerSeries_poly(PowerSeries): """ return self.__f.list() - def dict(self): + def monomial_coefficients(self): """ Return a dictionary of coefficients for ``self``. @@ -806,10 +806,18 @@ cdef class PowerSeries_poly(PowerSeries): sage: R. = ZZ[[]] sage: f = 1 + t^10 + O(t^12) + sage: f.monomial_coefficients() + {0: 1, 10: 1} + + ``dict`` is an alias:: + sage: f.dict() {0: 1, 10: 1} """ - return self.__f.dict() + return self.__f.monomial_coefficients() + + def dict(self): + return self.monomial_coefficients() def _derivative(self, var=None): """ diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 34e84ddbc5f..725927ba5ad 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1045,7 +1045,7 @@ cdef class PowerSeries(AlgebraElement): else: n = int(n) v = {} - for k, x in self.dict().iteritems(): + for k, x in self.monomial_coefficients().iteritems(): if k >= n: v[k-n] = x return self._parent(v, self.prec()-n) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 47365a9a8c6..300d64b8279 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -981,9 +981,9 @@ def _factor_multivariate_polynomial(self, f, proof=True): numfield_polynomial_flat = numfield.polynomial()(nf_gen) - polynomial_flat = sum(flat_ring({(0,)+tuple(k):1}) + polynomial_flat = sum(flat_ring({(0,) + tuple(k): 1}) * v.polynomial()(nf_gen) - for k,v in numfield_f.dict().items()) + for k, v in numfield_f.monomial_coefficients().items()) norm_flat = polynomial_flat.resultant(numfield_polynomial_flat, nf_gen) norm_f = norm_flat((0,)+norm_ring.gens()) diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py index 0fa89866a12..d8df667530b 100644 --- a/src/sage/rings/semirings/tropical_mpolynomial.py +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -401,7 +401,7 @@ def _repr_(self): sage: x + R(-1)*y + R(-3) 0*x + (-1)*y + (-3) """ - if not self.dict(): + if not self.monomial_coefficients(): return str(self.parent().base().zero()) s = super()._repr_() if self.monomials()[-1].is_constant(): @@ -425,7 +425,7 @@ def _latex_(self): sage: latex(R.zero()) \infty """ - if not self.dict(): + if not self.monomial_coefficients(): return self.parent().base().zero()._latex_() s = super()._latex_() if self.monomials()[-1].is_constant(): @@ -531,7 +531,7 @@ def _element_constructor_(self, x): raise ValueError(f"can not convert {x} to {self}") if isinstance(x, MPolynomial): if x.parent().variable_names() == self.variable_names(): - x = x.dict() + x = x.monomial_coefficients() else: raise ValueError(f"can not convert {x} to {self}") elif (x in self.base().base_ring()) or (x in self.base()): @@ -630,9 +630,8 @@ def random_element(self, degree=2, terms=None, choose_degree=False, R = PolynomialRing(self.base().base_ring(), self.variable_names()) f = R.random_element(degree=degree, terms=terms, choose_degree=choose_degree, *args, **kwargs) - new_dict = {} - for key, value in f.dict().items(): - new_dict[key] = self.base()(value) + new_dict = {key: self.base()(value) + for key, value in f.monomial_coefficients().items()} return self.element_class(self, new_dict) def gen(self, n=0): diff --git a/src/sage/rings/semirings/tropical_polynomial.py b/src/sage/rings/semirings/tropical_polynomial.py index b2d595e7e0a..74125633a22 100644 --- a/src/sage/rings/semirings/tropical_polynomial.py +++ b/src/sage/rings/semirings/tropical_polynomial.py @@ -207,7 +207,7 @@ def roots(self): """ from itertools import combinations tropical_roots = [] - data = self.dict() + data = self.monomial_coefficients() R = self.parent().base() if len(data) == 1: exponent = next(iter(data)) @@ -279,7 +279,7 @@ def split_form(self): """ roots = self.roots() R = self.parent() - poly = R(self.dict()[self.degree()].lift()) + poly = R(self.monomial_coefficients()[self.degree()].lift()) for root in roots: linear = R([root, 0]) poly *= linear @@ -321,7 +321,7 @@ def factor(self): (3) * 0 """ from sage.structure.factorization import Factorization - unit = self.dict()[self.degree()] + unit = self.monomial_coefficients()[self.degree()] if self != self.split_form() or not self.roots(): factor = [(self * self.parent(-unit.lift()), 1)] return Factorization(factor, unit=unit) @@ -374,7 +374,7 @@ def piecewise_function(self): from sage.sets.real_set import RealSet x = SR.var('x') - data = self.dict() + data = self.monomial_coefficients() R = self.parent().base() if not self.roots(): f = data[0].lift() @@ -537,7 +537,7 @@ def _repr_(self): (-1)*x^3 + 2*x^2 + (-1)*x + (-3) """ import re - if not self.dict(): + if not self.monomial_coefficients(): return str(self.parent().base().zero()) def replace_negatives(expr): @@ -844,7 +844,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self.base().base_ring(), self.variable_names()) f = R.random_element(degree=degree, monic=monic, *args, **kwds) - new_dict = f.dict() + new_dict = f.monomial_coefficients() if monic: new_dict[f.degree()] = 0 return self.element_class(self, new_dict) diff --git a/src/sage/rings/semirings/tropical_variety.py b/src/sage/rings/semirings/tropical_variety.py index e65b2408904..3eb04372d13 100644 --- a/src/sage/rings/semirings/tropical_variety.py +++ b/src/sage/rings/semirings/tropical_variety.py @@ -201,7 +201,7 @@ def __init__(self, poly): # Convert each term to its linear function linear_eq = {} - pd = poly.dict() + pd = poly.monomial_coefficients() for key in pd: eq = sum(variables[i] * e for i, e in enumerate(key)) eq += pd[key].lift() diff --git a/src/sage/rings/tate_algebra_element.pyx b/src/sage/rings/tate_algebra_element.pyx index 1c435a2ccec..d8aa8758b42 100644 --- a/src/sage/rings/tate_algebra_element.pyx +++ b/src/sage/rings/tate_algebra_element.pyx @@ -1074,7 +1074,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): else: try: poly = parent._polynomial_ring(x) - self._poly = PolyDict(poly.dict(), None) + self._poly = PolyDict(poly.monomial_coefficients(), None) except TypeError: # last chance: we first try to convert to the rational Tate series if parent._integral: @@ -2192,7 +2192,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): """ return [ t.monomial() for t in self.terms() ] - def dict(self): + def monomial_coefficients(self): """ Return a dictionary whose keys are the exponents and whose values are the corresponding coefficients of this series. @@ -2202,12 +2202,20 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): sage: R = Zp(2, prec=10, print_mode='digits') sage: A. = TateAlgebra(R) sage: f = 2*x^2 + x + sage: f.monomial_coefficients() + {(1, 0): ...0000000001, (2, 0): ...00000000010} + + ``dict`` is an alias:: + sage: f.dict() {(1, 0): ...0000000001, (2, 0): ...00000000010} """ self._normalize() return dict(self._poly.__repn) + def dict(self): + return self.monomial_coefficients() + def coefficient(self, exponent): r""" Return the coefficient corresponding to the given exponent. diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 7c8cf62c5ea..ed0da70e237 100755 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1105,7 +1105,7 @@ def quadratic_transform(self): for i in range(len(L)): degs[i] = min(F.degree(L[i]), degs[i]) T = [] - for item in G.dict().items(): + for item in G.monomial_coefficients().items(): tup = tuple([item[0][i] - degs[i] for i in range(len(L))]) T.append((tup, item[1])) G = R(dict(T)) @@ -1280,11 +1280,11 @@ def excellent_position(self, Q): if j == 0: div_pow = min(e[1] for e in npoly.exponents()) npoly = PP.coordinate_ring()({(v0, v1 - div_pow, v2): g - for (v0, v1, v2), g in npoly.dict().items()}) + for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) else: div_pow = min(e[0] for e in npoly.exponents()) npoly = PP.coordinate_ring()({(v0 - div_pow, v1, v2): g - for (v0, v1, v2), g in npoly.dict().items()}) + for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) # check the degree again if npoly.degree() != d - r: need_continue = True diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 6ac78706107..26522878918 100755 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -503,12 +503,12 @@ def find_point(self, supports, roots, case, solution=0): lastpoly = F(1) for n in range(B): lastpoly = (lastpoly * t) % p - phi_p[A + 2 + n] = vector(F, d, lastpoly.dict()) + phi_p[A + 2 + n] = vector(F, d, lastpoly.monomial_coefficients()) lastpoly = -alpha % p - phi_p[A + B + 2] = vector(F, d, lastpoly.dict()) + phi_p[A + B + 2] = vector(F, d, lastpoly.monomial_coefficients()) for n in range(C): lastpoly = (lastpoly * t) % p - phi_p[A + B + 3 + n] = vector(F, d, lastpoly.dict()) + phi_p[A + B + 3 + n] = vector(F, d, lastpoly.monomial_coefficients()) phi_p[A + B + C + 3] = vector(F, d) phi.append(matrix(phi_p).transpose()) for (i, p) in enumerate(supports[1]): @@ -525,12 +525,12 @@ def find_point(self, supports, roots, case, solution=0): lastpoly = F(1) for n in range(C): lastpoly = (lastpoly * t) % p - phi_p[A + B + 3 + n] = vector(F, d, lastpoly.dict()) + phi_p[A + B + 3 + n] = vector(F, d, lastpoly.monomial_coefficients()) lastpoly = -alpha % p - phi_p[0] = vector(F, d, lastpoly.dict()) + phi_p[0] = vector(F, d, lastpoly.monomial_coefficients()) for n in range(A): lastpoly = (lastpoly * t) % p - phi_p[1 + n] = vector(F, d, lastpoly.dict()) + phi_p[1 + n] = vector(F, d, lastpoly.monomial_coefficients()) phi_p[A + B + C + 3] = vector(F, d) phi.append(matrix(phi_p).transpose()) for (i, p) in enumerate(supports[2]): @@ -547,12 +547,12 @@ def find_point(self, supports, roots, case, solution=0): lastpoly = F(1) for n in range(A): lastpoly = (lastpoly * t) % p - phi_p[1 + n] = vector(F, d, lastpoly.dict()) + phi_p[1 + n] = vector(F, d, lastpoly.monomial_coefficients()) lastpoly = -alpha % p - phi_p[A + 1] = vector(F, d, lastpoly.dict()) + phi_p[A + 1] = vector(F, d, lastpoly.monomial_coefficients()) for n in range(B): lastpoly = (lastpoly * t) % p - phi_p[A + 2 + n] = vector(F, d, lastpoly.dict()) + phi_p[A + 2 + n] = vector(F, d, lastpoly.monomial_coefficients()) phi_p[A + B + C + 3] = vector(F, d) phi.append(matrix(phi_p).transpose()) if case == 0: diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 0c3e2724229..701f6523065 100755 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -358,7 +358,7 @@ def differential_basis_baker(f): return None from sage.geometry.polyhedron.constructor import Polyhedron - D = {(k[0], k[1]): v for k, v in f.dict().items()} + D = {(k[0], k[1]): v for k, v in f.monomial_coefficients().items()} P = Polyhedron(D) kT = k["t"] # here we check the additional genericity conditions: that the polynomials @@ -3044,7 +3044,7 @@ def initialise(z, i): A = PolynomialRing(self._CC, "xyz") aes = [] for mp in mp_list: - d = mp.dict() + d = mp.monomial_coefficients() mp = sum( [ d[k] * CCzg.gen(0)**k[0] * CCzg.gen(1)**k[1] diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index 93a28beafe8..4c171595e6a 100755 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -407,7 +407,7 @@ def subtract(e, power): return tuple([l[0] - power] + l[1:]) def divide_by_x_n(p): - d_old = p.dict() + d_old = p.monomial_coefficients() power = min(e[0] for e in d_old) d_new = {subtract(exponent, power): coefficient for exponent, coefficient in d_old.items()} diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 87d414d3464..82c300c1f7a 100755 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -255,9 +255,9 @@ def homogenize(inhomog, degree): result = vector(ZZ, result) result.set_immutable() return result - X_dict = {homogenize(e, 2): v for e, v in X.dict().items()} - Y_dict = {homogenize(e, 3): v for e, v in Y.dict().items()} - Z_dict = {homogenize(e, 1): v for e, v in Z.dict().items()} + X_dict = {homogenize(e, 2): v for e, v in X.monomial_coefficients().items()} + Y_dict = {homogenize(e, 3): v for e, v in Y.monomial_coefficients().items()} + Z_dict = {homogenize(e, 1): v for e, v in Z.monomial_coefficients().items()} # shift to nonnegative exponents if necessary min_deg = [0] * R.ngens() for var in variables: diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 44c23ff8fb0..8e8940b5846 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1680,7 +1680,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): ....: ....: def _act_(self, g, a): ....: D = {} - ....: for k, v in a.dict().items(): + ....: for k, v in a.monomial_coefficients().items(): ....: nk = [0]*len(k) ....: for i in range(len(k)): ....: nk[g(i+1)-1] = k[i] diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 1001cbda600..18d47b0da2c 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -7503,7 +7503,7 @@ cdef class Expression(Expression_abc): [[-5, 0], [6, 2]] sage: g.polynomial(QQ).list() [-5, 0, 6] - sage: g.polynomial(QQ).dict() + sage: g.polynomial(QQ).monomial_coefficients() {0: -5, 2: 6} :: From 36f1f79477d7445085973933174976ca91786adc Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 3 Oct 2024 22:47:03 +0100 Subject: [PATCH 058/108] use StructureDescrption() in tests This will fix #38760 --- src/sage/libs/gap/element.pyx | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 24db9c07cb8..9965b0aa4e4 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -2437,31 +2437,22 @@ cdef class GapElement_Function(GapElement): sage: b Sym( [ 1 .. 4 ] ) - sage: sorted(a(b)) - [Group(()), - Sym( [ 1 .. 4 ] ), - Alt( [ 1 .. 4 ] ), - Group([ (1,4)(2,3), (1,2)(3,4) ])] + sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups()) + ["1", "S4", "A4", "C2 x C2"] sage: libgap.eval("a := NormalSubgroups") sage: libgap.eval("b := SymmetricGroup(4)") Sym( [ 1 .. 4 ] ) sage: libgap.collect() - sage: sorted(libgap.eval('a') (libgap.eval('b'))) - [Group(()), - Sym( [ 1 .. 4 ] ), - Alt( [ 1 .. 4 ] ), - Group([ (1,4)(2,3), (1,2)(3,4) ])] + sage: [x.StructureDescription() for x in sorted(libgap.eval('a') (libgap.eval('b')))] + ["1", "S4", "A4", "C2 x C2"] sage: a = libgap.eval('a') sage: b = libgap.eval('b') sage: libgap.collect() - sage: sorted(a(b)) - [Group(()), - Sym( [ 1 .. 4 ] ), - Alt( [ 1 .. 4 ] ), - Group([ (1,4)(2,3), (1,2)(3,4) ])] + sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups()) + ["1", "S4", "A4", "C2 x C2"] Not every ``GapElement`` is callable:: From e08bb52f6322bb6ff852875270642eff6fabc00d Mon Sep 17 00:00:00 2001 From: Skip Garibaldi Date: Thu, 3 Oct 2024 20:43:36 -0700 Subject: [PATCH 059/108] Deleted : --- src/sage/combinat/root_system/root_space.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 5255d7ec530..14f5ed4ab23 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -261,7 +261,7 @@ def scalar(self, lambdacheck): [ 0 -1 2 -1] [ 0 0 -2 2] - TESTS:: + TESTS: Verify that :issue:`15325` (A) is fixed:: From fe7e86c534613678a70c3e81984bba2cda0d8255 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 4 Oct 2024 09:28:24 +0200 Subject: [PATCH 060/108] fix syntax --- src/sage/libs/gap/element.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 9965b0aa4e4..4dcb750ae59 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -2437,7 +2437,7 @@ cdef class GapElement_Function(GapElement): sage: b Sym( [ 1 .. 4 ] ) - sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups()) + sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups())] ["1", "S4", "A4", "C2 x C2"] sage: libgap.eval("a := NormalSubgroups") @@ -2451,7 +2451,7 @@ cdef class GapElement_Function(GapElement): sage: a = libgap.eval('a') sage: b = libgap.eval('b') sage: libgap.collect() - sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups()) + sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups())] ["1", "S4", "A4", "C2 x C2"] Not every ``GapElement`` is callable:: From 841298f9ae41c01c5d012c7ac48464e2b47654de Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 4 Oct 2024 18:24:58 +0900 Subject: [PATCH 061/108] Add pdf() --- src/sage/misc/latex.py | 84 ++++++++++++++++++++++++++++++++++++++--- src/sage/misc/viewer.py | 2 +- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 2d5c6ae7475..9d8fcd4a341 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -1683,7 +1683,9 @@ def _latex_file_(objects, title='SAGE', debug=False, s = LATEX_HEADER + '\n' + MACROS + s + '\n\\end{document}' if debug: + print('----') print(s) + print('----') return s @@ -1827,7 +1829,6 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, ... ValueError: Unsupported LaTeX engine. """ - if tightpage: if margin is None: margin_str = "" @@ -1870,16 +1871,16 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, tmp.cleanup() return output_file = os.path.join(tmp.name, "sage." + suffix) - # this should get changed if we switch the stuff in misc.viewer to - # producing lists + if debug: - print('viewer: "{}"'.format(viewer)) + print(f'temporary file: "{output_file}"') + print(f'viewer: "{viewer}"') # Return immediately but only clean up the temporary file after # the viewer has closed. This function is synchronous and waits # for the process to complete... def run_viewer(): - run([viewer, output_file], capture_output=True) + run([*viewer.split(), output_file], capture_output=True) tmp.cleanup() # ...but we execute it asynchronously so that view() completes @@ -1890,7 +1891,78 @@ def run_viewer(): t.daemon = True t.start() - return + +def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug=False): + """ + Create an image from the latex representation of ``x`` and save it as a pdf + file with the given filename. + + INPUT: + + - ``x`` -- a Sage object + + - ``filename`` -- the filename with which to save the image + + - ``tiny`` -- boolean (default: ``False``); if ``True``, use a tiny font + + - ``tightpage`` -- boolean (default: ``True``); use the LaTeX package + ``preview`` with the 'tightpage' option + + - ``margin`` -- float (default: no margin); width of border, only effective + with 'tight page' + + - ``engine`` -- (default: ``None``) ``'latex'``, ``'pdflatex'``, + ``'xelatex'`` or ``'lualatex'``; if ``None``, the value defined in the + LaTeX global preferences ``latex.engine()`` is used + + - ``debug`` -- boolean (default: ``False``); if ``True``, print verbose output + + EXAMPLES:: + + sage: # optional - latex + sage: from sage.misc.latex import pdf + sage: import tempfile + sage: with tempfile.NamedTemporaryFile(suffix=".pdf") as f: # random + ....: pdf(ZZ[x], f.name) + """ + from sage.plot.graphics import Graphics + if isinstance(x, Graphics): + x.save(filename) + return + + if tightpage: + if margin is None: + margin_str = "" + else: + margin_str = '\n\\setlength\\PreviewBorder{%fmm}' % margin + latex_options = {'extra_preamble': + '\\usepackage[tightpage,active]{preview}\n' + + '\\PreviewEnvironment{page}%s' % margin_str, + 'math_left': '\\begin{page}$', + 'math_right': '$\\end{page}'} + else: + latex_options = {} + + # create a string of latex code to write in a file + s = _latex_file_([x], title='', tiny=tiny, debug=debug, **latex_options) + if engine is None: + engine = _Latex_prefs._option["engine"] + # path name for permanent pdf output + abs_path_to_pdf = os.path.abspath(filename) + # temporary directory to store stuff + with TemporaryDirectory() as tmp: + tex_file = os.path.join(tmp, "sage.tex") + pdf_file = os.path.join(tmp, "sage.pdf") + # write latex string to file + with open(tex_file, 'w') as file: + file.write(s) + # run latex on the file + e = _run_latex_(tex_file, debug=debug, engine=engine) + if e == 'pdf': + # if no errors, copy pdf_file to the appropriate place + shutil.copy(pdf_file, abs_path_to_pdf) + else: + print("Latex error or no pdf was generated.") def png(x, filename, density=150, debug=False, diff --git a/src/sage/misc/viewer.py b/src/sage/misc/viewer.py index 4f62b1c5022..badc70a963a 100644 --- a/src/sage/misc/viewer.py +++ b/src/sage/misc/viewer.py @@ -69,7 +69,7 @@ def default_viewer(viewer=None): elif os.uname()[0] == 'Darwin': # Simple on OS X, since there is an open command that opens # anything, using the user's preferences. - BROWSER = 'open' + BROWSER = 'open -W' DVI_VIEWER = BROWSER PDF_VIEWER = BROWSER PNG_VIEWER = BROWSER From e6717eff1e31fddca40d5df9f326e7d1710d788e Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 4 Oct 2024 11:50:08 +0100 Subject: [PATCH 062/108] use a(b), not b.NormalSubgroups() Co-authored-by: Martin Rubey --- src/sage/libs/gap/element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 4dcb750ae59..ffab3697999 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -2437,7 +2437,7 @@ cdef class GapElement_Function(GapElement): sage: b Sym( [ 1 .. 4 ] ) - sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups())] + sage: [x.StructureDescription() for x in sorted(a(b))] ["1", "S4", "A4", "C2 x C2"] sage: libgap.eval("a := NormalSubgroups") From 08f203e353b62c1427554461e78d2e49e9552725 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 4 Oct 2024 11:50:37 +0100 Subject: [PATCH 063/108] use a(b), not b.NormalSubgroups() Co-authored-by: Martin Rubey --- src/sage/libs/gap/element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index ffab3697999..c24408f401a 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -2451,7 +2451,7 @@ cdef class GapElement_Function(GapElement): sage: a = libgap.eval('a') sage: b = libgap.eval('b') sage: libgap.collect() - sage: [x.StructureDescription() for x in sorted(b.NormalSubgroups())] + sage: [x.StructureDescription() for x in sorted(a(b))] ["1", "S4", "A4", "C2 x C2"] Not every ``GapElement`` is callable:: From 64068552cec9409a2f1d9db2504a81ca812e5f8b Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Fri, 4 Oct 2024 16:37:33 +0200 Subject: [PATCH 064/108] Fix time limitation in magma_free docstring --- src/sage/interfaces/magma_free.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 34d5b70f29a..5c747774aab 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -26,7 +26,7 @@ def magma_free_eval(code, strip=True, columns=0): Use the free online MAGMA calculator to evaluate the given input code and return the answer as a string. - LIMITATIONS: The code must evaluate in at most 20 seconds + LIMITATIONS: The code must evaluate in at most 120 seconds and there is a limitation on the amount of RAM. EXAMPLES:: From 2d46bc1fbca8b9cced8e3b4e1e1637c402a199f4 Mon Sep 17 00:00:00 2001 From: Daniel Gordon Date: Fri, 4 Oct 2024 07:57:04 -0700 Subject: [PATCH 065/108] Fixed a doctest to reflect the new (144,66,30)-difference family. --- src/sage/combinat/designs/difference_family.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 2ec008f16db..49b25c12dd0 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -3690,7 +3690,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch 3 Turyn 1965 construction 4 McFarland 1973 construction 5 False - 6 Unknown + 6 The database contains a (144,66,30)-difference family 7 False 8 McFarland 1973 construction 9 Unknown From e00b0b99d686ab9fdf1356b942cf97d1adbf6b6f Mon Sep 17 00:00:00 2001 From: Daniel Gordon Date: Fri, 4 Oct 2024 08:33:43 -0700 Subject: [PATCH 066/108] Added group information to the comments about the new non-cyclic difference sets --- src/sage/combinat/designs/database.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 4bda83eeab0..37a649300eb 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -3143,7 +3143,7 @@ def QDM_57_9_1_1_8(): [0,2,13,18,28,30,44,48,50,51,57,61], [0,4,21,26,29,33,35,36,47,55,56,60]]}, -# a 133-cyclic difference set +# a (133,33,8)-cyclic difference set # see https://dmgordon.org/diffset (133,33, 8): {(133,): [[1,5,14,22,25,27,29,32,34,38, @@ -3151,7 +3151,7 @@ def QDM_57_9_1_1_8(): 92,93,99,103,104,106,107,112,113,122, 126,128,129]]}, -# a 144-noncyclic difference set, +# a (144,66,30)-noncyclic difference set in AbelianGroup([2,8,3,3]) # given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith # see https://dmgordon.org/diffset (144,66,30): @@ -3170,7 +3170,7 @@ def QDM_57_9_1_1_8(): (1,1,1,2),(1,7,1,1),(1,0,1,1),(1,1,1,1),(1,4,1,2), (1,5,1,2)]]}, -# a 320-noncyclic difference set, +# a (320,88,24)-noncyclic difference set in AbelianGroup([4,4,4,5]), # given in Arasu and Chen, Designs, Codes and Cryptography 2001 # see https://dmgordon.org/diffset (320,88,24): @@ -3193,7 +3193,7 @@ def QDM_57_9_1_1_8(): (3,3,0,4),(2,3,1,4),(1,0,1,4),(2,2,2,4),(1,3,1,4), (1,0,0,4),(0,1,0,4),(0,0,0,4)]]}, -# a 901-cyclic difference set +# a (901,225,56)-cyclic difference set # see https://dmgordon.org/diffset (901,225,56): {(901,): [[ 0, 1, 5, 9, 12, 13, 14, 16, 22, 25, 41, 43, From f711216e8c951dfaf75158b685e360e1482305fa Mon Sep 17 00:00:00 2001 From: Daniel Gordon Date: Fri, 4 Oct 2024 08:36:49 -0700 Subject: [PATCH 067/108] Added group information to the comments about the new non-cyclic difference sets --- src/sage/combinat/designs/database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 37a649300eb..19eb9d26165 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -3151,7 +3151,7 @@ def QDM_57_9_1_1_8(): 92,93,99,103,104,106,107,112,113,122, 126,128,129]]}, -# a (144,66,30)-noncyclic difference set in AbelianGroup([2,8,3,3]) +# a (144,66,30) non-cyclic difference set in AbelianGroup([2,8,3,3]) # given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith # see https://dmgordon.org/diffset (144,66,30): @@ -3170,7 +3170,7 @@ def QDM_57_9_1_1_8(): (1,1,1,2),(1,7,1,1),(1,0,1,1),(1,1,1,1),(1,4,1,2), (1,5,1,2)]]}, -# a (320,88,24)-noncyclic difference set in AbelianGroup([4,4,4,5]), +# a (320,88,24) non-cyclic difference set in AbelianGroup([4,4,4,5]), # given in Arasu and Chen, Designs, Codes and Cryptography 2001 # see https://dmgordon.org/diffset (320,88,24): From 6a5aece742c2c98897168c5720c1e5d07b4fac48 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 4 Oct 2024 18:10:20 +0200 Subject: [PATCH 068/108] polynomials are an algebra with basis --- src/sage/categories/additive_magmas.py | 4 +- src/sage/categories/algebra_functor.py | 1 - src/sage/categories/map.pyx | 8 ++-- src/sage/categories/modules.py | 2 +- src/sage/interfaces/tab_completion.py | 2 +- src/sage/rings/lazy_series_ring.py | 10 +++-- .../polynomial/laurent_polynomial_ring.py | 38 +++++++++++++++---- .../laurent_polynomial_ring_base.py | 2 + .../polynomial/multi_polynomial_ring_base.pxd | 1 + .../polynomial/multi_polynomial_ring_base.pyx | 2 + src/sage/rings/polynomial/polynomial_ring.py | 16 +++++++- .../polynomial/polynomial_ring_constructor.py | 35 ++++++++++------- src/sage/rings/ring.pyx | 24 ++++++++---- 13 files changed, 104 insertions(+), 41 deletions(-) diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index 691486e03d4..ccfda512014 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -971,8 +971,8 @@ def extra_super_categories(self): [Category of unital magmas] sage: C.super_categories() - [Category of unital algebras with basis over Rational Field, - Category of additive magma algebras over Rational Field] + [Category of additive magma algebras over Rational Field, + Category of unital algebras with basis over Rational Field] """ from sage.categories.magmas import Magmas return [Magmas().Unital()] diff --git a/src/sage/categories/algebra_functor.py b/src/sage/categories/algebra_functor.py index 0d6cb19b0e1..ae5ef793296 100644 --- a/src/sage/categories/algebra_functor.py +++ b/src/sage/categories/algebra_functor.py @@ -128,7 +128,6 @@ Category of semigroup algebras over Rational Field, ... Category of unital magma algebras over Rational Field, - ... Category of magma algebras over Rational Field, ... Category of set algebras over Rational Field, diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index aaa52b56ad1..43e476847d0 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -655,9 +655,11 @@ cdef class Map(Element): sage: f = R.hom([x+y, x-y], R) sage: f.category_for() Join of Category of unique factorization domains - and Category of commutative algebras - over (number fields and quotient fields and metric spaces) - and Category of infinite sets + and Category of algebras with basis over + (number fields and quotient fields and metric spaces) + and Category of commutative algebras over + (number fields and quotient fields and metric spaces) + and Category of infinite sets sage: f.category() Category of endsets of unital magmas and right modules over (number fields and quotient fields and metric spaces) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index d6d63b4df0a..f9bc036910f 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -893,7 +893,7 @@ def __init_extra__(self): (Vector space of dimension 2 over Rational Field, Univariate Polynomial Ring in x over Rational Field) sage: A.category() # needs sage.modules - Category of Cartesian products of vector spaces + Category of Cartesian products of vector spaces with basis over (number fields and quotient fields and metric spaces) sage: A.base_ring() # needs sage.modules Rational Field diff --git a/src/sage/interfaces/tab_completion.py b/src/sage/interfaces/tab_completion.py index fdbe51ffd8e..d0e8bc11309 100644 --- a/src/sage/interfaces/tab_completion.py +++ b/src/sage/interfaces/tab_completion.py @@ -71,7 +71,7 @@ def completions(s, globs): sage: import sage.interfaces.tab_completion as s sage: p = x**2 + 1 sage: s.completions('p.co',globals()) # indirect doctest - ['p.coefficients',...] + ['p.coefficient',...] sage: s.completions('dic',globals()) # indirect doctest ['dickman_rho', 'dict'] diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2e54ce22cd0..ee3e463e988 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1488,10 +1488,14 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: TestSuite(L).run() # needs sage.libs.singular sage: L.category() Category of infinite commutative no zero divisors algebras over - (unique factorization domains and commutative algebras over + (unique factorization domains and algebras with basis over (Dedekind domains and euclidean domains - and noetherian rings - and infinite enumerated sets and metric spaces) + and noetherian rings + and infinite enumerated sets and metric spaces) + and commutative algebras over + (Dedekind domains and euclidean domains + and noetherian rings + and infinite enumerated sets and metric spaces) and infinite sets) sage: L = LazyLaurentSeriesRing(GF(5), 't') diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index c17819a1b2c..40b09bbfb6e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -445,6 +445,8 @@ def __init__(self, R): if R.ngens() != 1: raise ValueError("must be 1 generator") LaurentPolynomialRing_generic.__init__(self, R) + from sage.rings.integer_ring import IntegerRing + self._indices = IntegerRing() Element = LaurentPolynomial_univariate @@ -561,6 +563,12 @@ def _element_constructor_(self, x): return self.element_class(self, x) + def monomial(self, arg): + r""" + Return the monomial with the given exponent. + """ + return self.element_class(self, {arg: self.base_ring().one()}) + def __reduce__(self): """ Used in pickling. @@ -591,6 +599,9 @@ def __init__(self, R): if not R.base_ring().is_integral_domain(): raise ValueError("base ring must be an integral domain") LaurentPolynomialRing_generic.__init__(self, R) + from sage.modules.free_module import FreeModule + from sage.rings.integer_ring import IntegerRing + self._indices = FreeModule(IntegerRing(), R.ngens()) Element = LazyImport('sage.rings.polynomial.laurent_polynomial_mpair', 'LaurentPolynomial_mpair') @@ -605,7 +616,7 @@ def _repr_(self): """ return "Multivariate Laurent Polynomial Ring in %s over %s" % (", ".join(self._R.variable_names()), self._R.base_ring()) - def monomial(self, *args): + def monomial(self, *exponents): r""" Return the monomial whose exponents are given in argument. @@ -629,14 +640,27 @@ def monomial(self, *args): sage: L.monomial(1, 2, 3) # needs sage.modules Traceback (most recent call last): ... - TypeError: tuple key must have same length as ngens - """ - if len(args) != self.ngens(): - raise TypeError("tuple key must have same length as ngens") + TypeError: tuple key (1, 2, 3) must have same length as ngens (= 2) + + We also allow to specify the exponents in a single tuple:: + + sage: L.monomial((-1, 2)) # needs sage.modules + x0^-1*x1^2 + sage: L.monomial((-1, 2, 3)) # needs sage.modules + Traceback (most recent call last): + ... + TypeError: tuple key (-1, 2, 3) must have same length as ngens (= 2) + """ from sage.rings.polynomial.polydict import ETuple - m = ETuple(args, int(self.ngens())) - return self.element_class(self, self.polynomial_ring().one(), m) + if len(exponents) == 1 and isinstance((e := exponents[0]), (tuple, ETuple)): + exponents = e + + if len(exponents) != self.ngens(): + raise TypeError(f"tuple key {exponents} must have same length as ngens (= {self.ngens()})") + + m = ETuple(exponents, int(self.ngens())) + return self.element_class(self, self.polynomial_ring().base_ring().one(), m) def _element_constructor_(self, x, mon=None): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 71eb20cd701..b4f4f13289e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -42,6 +42,8 @@ class LaurentPolynomialRing_generic(CommutativeRing, Parent): sage: R. = LaurentPolynomialRing(QQ) sage: R.category() Join of Category of unique factorization domains + and Category of algebras with basis + over (number fields and quotient fields and metric spaces) and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd index 4ce9033dadb..322e25e363b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd @@ -4,6 +4,7 @@ from sage.structure.parent cimport Parent cdef class MPolynomialRing_base(CommutativeRing): cdef object _ngens cdef object _term_order + cdef public object _indices cdef public object _has_singular cdef public object _magma_gens cdef public dict _magma_cache diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index dffe6cb80c1..dedacde49a6 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -99,6 +99,8 @@ cdef class MPolynomialRing_base(CommutativeRing): else: category = polynomial_default_category(base_ring.category(), n) Ring.__init__(self, base_ring, names, category=category) + from sage.combinat.integer_vector import IntegerVectors + self._indices = IntegerVectors(self._ngens) def is_integral_domain(self, proof=True): """ diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 165c7fb72a4..2bda9f6f9c3 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -256,15 +256,25 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: category(ZZ['x']) Join of Category of unique factorization domains + and Category of algebras with basis over + (Dedekind domains and euclidean domains + and noetherian rings and infinite enumerated sets + and metric spaces) and Category of commutative algebras over (Dedekind domains and euclidean domains and noetherian rings and infinite enumerated sets and metric spaces) and Category of infinite sets + sage: category(GF(7)['x']) Join of Category of euclidean domains - and Category of commutative algebras over - (finite enumerated fields and subquotients of monoids and quotients of semigroups) and Category of infinite sets + and Category of algebras with basis over + (finite enumerated fields and subquotients of monoids + and quotients of semigroups) + and Category of commutative algebras over + (finite enumerated fields and subquotients of monoids + and quotients of semigroups) + and Category of infinite sets TESTS: @@ -314,6 +324,8 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, self.__cyclopoly_cache = {} self._has_singular = False Ring.__init__(self, base_ring, names=name, normalize=True, category=category) + from sage.rings.semirings.non_negative_integer_semiring import NonNegativeIntegerSemiring + self._indices = NonNegativeIntegerSemiring() self._populate_coercion_lists_(convert_method_name='_polynomial_') def __reduce__(self): diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index a135fe8de6c..5cbc74dd1d5 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -916,23 +916,30 @@ def polynomial_default_category(base_ring_category, n_variables): EXAMPLES:: sage: from sage.rings.polynomial.polynomial_ring_constructor import polynomial_default_category - sage: polynomial_default_category(Rings(),1) is Algebras(Rings()).Infinite() + sage: polynomial_default_category(Rings(), 1) + Category of infinite algebras with basis over rings + sage: polynomial_default_category(Rings().Commutative(), 1) + Category of infinite commutative algebras with basis + over commutative rings + sage: polynomial_default_category(Fields(), 1) + Join of Category of euclidean domains + and Category of algebras with basis over fields + and Category of commutative algebras over fields + and Category of infinite sets + sage: polynomial_default_category(Fields(), 2) + Join of Category of unique factorization domains + and Category of algebras with basis over fields + and Category of commutative algebras over fields + and Category of infinite sets + + sage: QQ['t'].category() is EuclideanDomains() & CommutativeAlgebras(QQ.category()).WithBasis().Infinite() True - sage: polynomial_default_category(Rings().Commutative(),1) is Algebras(Rings().Commutative()).Commutative().Infinite() + sage: QQ['s','t'].category() is UniqueFactorizationDomains() & CommutativeAlgebras(QQ.category()).WithBasis().Infinite() True - sage: polynomial_default_category(Fields(),1) is EuclideanDomains() & Algebras(Fields()).Infinite() - True - sage: polynomial_default_category(Fields(),2) is UniqueFactorizationDomains() & CommutativeAlgebras(Fields()).Infinite() - True - - sage: QQ['t'].category() is EuclideanDomains() & CommutativeAlgebras(QQ.category()).Infinite() - True - sage: QQ['s','t'].category() is UniqueFactorizationDomains() & CommutativeAlgebras(QQ.category()).Infinite() - True - sage: QQ['s']['t'].category() is UniqueFactorizationDomains() & CommutativeAlgebras(QQ['s'].category()).Infinite() + sage: QQ['s']['t'].category() is UniqueFactorizationDomains() & CommutativeAlgebras(QQ['s'].category()).WithBasis().Infinite() True """ - category = Algebras(base_ring_category) + category = Algebras(base_ring_category).WithBasis() if n_variables: # here we assume the base ring to be nonzero @@ -1034,4 +1041,4 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order='lex'): ############################################################################ # END (Factory function for making polynomial rings) -############################################################################ \ No newline at end of file +############################################################################ diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 59cf58e3513..d139c1449c5 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -155,6 +155,7 @@ cdef class Ring(ParentWithGens): Running the test suite of self.an_element() running ._test_category() . . . pass running ._test_eq() . . . pass + running ._test_monomial_coefficients() . . . pass running ._test_new() . . . pass running ._test_nonzero_equal() . . . pass running ._test_not_implemented_methods() . . . pass @@ -184,20 +185,29 @@ cdef class Ring(ParentWithGens): Test against another bug fixed in :issue:`9944`:: sage: QQ['x'].category() - Join of Category of euclidean domains and Category of commutative algebras over - (number fields and quotient fields and metric spaces) and Category of infinite sets + Join of Category of euclidean domains + and Category of algebras with basis + over (number fields and quotient fields and metric spaces) + and Category of commutative algebras + over (number fields and quotient fields and metric spaces) + and Category of infinite sets sage: QQ['x','y'].category() Join of Category of unique factorization domains + and Category of algebras with basis + over (number fields and quotient fields and metric spaces) and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets sage: PolynomialRing(MatrixSpace(QQ, 2),'x').category() # needs sage.modules - Category of infinite algebras over (finite dimensional algebras with basis over - (number fields and quotient fields and metric spaces) and infinite sets) + Category of infinite algebras with basis + over (finite dimensional algebras with basis + over (number fields and quotient fields and metric spaces) + and infinite sets) sage: PolynomialRing(SteenrodAlgebra(2),'x').category() # needs sage.combinat sage.modules - Category of infinite algebras over (super Hopf algebras with basis - over Finite Field of size 2 and supercocommutative super coalgebras - over Finite Field of size 2) + Category of infinite algebras with basis + over (super Hopf algebras with basis over Finite Field of size 2 + and supercocommutative super coalgebras + over Finite Field of size 2) TESTS:: From ddbc3ce8ff6ade84a03993d70f1f1ec8c22fd81b Mon Sep 17 00:00:00 2001 From: Kyle Hofmann Date: Fri, 4 Oct 2024 18:59:38 -0700 Subject: [PATCH 069/108] PEP8 Co-authored-by: Travis Scrimshaw --- src/sage/libs/flint/nmod_poly_linkage.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index 61b647fd1e4..6b6c06715fb 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -606,7 +606,7 @@ cdef inline int celement_gcd(nmod_poly_t res, nmod_poly_t a, nmod_poly_t b, unsi cdef unsigned long leadcoeff = nmod_poly_get_coeff_ui(res, nmod_poly_degree(res)) cdef unsigned long modulus = nmod_poly_modulus(res) - if n_gcd(modulus,leadcoeff) == 1: + if n_gcd(modulus, leadcoeff) == 1: nmod_poly_make_monic(res, res) cdef inline int celement_xgcd(nmod_poly_t res, nmod_poly_t s, nmod_poly_t t, nmod_poly_t a, nmod_poly_t b, unsigned long n) except -2: From 673cb1d1aaf7b1934252c66a060fdf11ab53c67a Mon Sep 17 00:00:00 2001 From: Kyle Hofmann Date: Fri, 4 Oct 2024 22:17:02 -0700 Subject: [PATCH 070/108] Don't suppress FLINT abort exception Co-authored-by: Travis Scrimshaw --- src/sage/libs/flint/nmod_poly_linkage.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index 6b6c06715fb..b1be0216a2e 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -602,7 +602,7 @@ cdef inline int celement_gcd(nmod_poly_t res, nmod_poly_t a, nmod_poly_t b, unsi finally: sig_off() except RuntimeError: - raise RuntimeError("FLINT gcd calculation failed") from None + raise RuntimeError("FLINT gcd calculation failed") cdef unsigned long leadcoeff = nmod_poly_get_coeff_ui(res, nmod_poly_degree(res)) cdef unsigned long modulus = nmod_poly_modulus(res) From 88edf1a00931e17d663ce8f57834b718e76af41f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 4 Oct 2024 18:25:58 +0900 Subject: [PATCH 071/108] Fix crystals latex --- src/sage/graphs/graph_latex.py | 62 ++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 4606c56b4f9..3e42f1b6648 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1938,48 +1938,66 @@ def translate(p): s += [str(round(el_color[edge][2], 4)), '}\n'] s += ['%\n'] - # Create each vertex + # Create vertices + v = [] + box = '' + used = False for u in vertex_list: - s += ['\\Vertex['] + t = [r'\Vertex['] # colors, shapes, sizes, labels/placement for 'Custom' style if customized: - s += ['style={'] # begin style list - s += ['minimum size=', str(round(float(scale * v_size[u]), 4)), + t += ['style={'] # begin style list + t += ['minimum size=', str(round(float(scale * v_size[u]), 4)), units, ','] - s += ['draw=', vertex_color_names[u], ','] - s += ['fill=', vertex_fill_color_names[u], ','] + t += ['draw=', vertex_color_names[u], ','] + t += ['fill=', vertex_fill_color_names[u], ','] if vertex_labels: - s += ['text=', vertex_label_color_names[u], ','] + t += ['text=', vertex_label_color_names[u], ','] if v_shape[u] == 'sphere': - s += ['shape=circle,shading=ball,line width=0pt,ball color=', vertex_color_names[u], ','] + t += ['shape=circle,shading=ball,line width=0pt,ball color=', vertex_color_names[u], ','] else: - s += ['shape=', v_shape[u]] - s += ['},'] # end style list + t += ['shape=', v_shape[u]] + t += ['},'] # end style list if vertex_labels: if vl_placement[u] == 'center': - s += ['LabelOut=false,'] + t += ['LabelOut=false,'] else: - s += ['LabelOut=true,'] - s += ['Ldist=', str(round(float(scale * vl_placement[u][0]), 4)), units, ','] - s += ['Lpos=', str(round(float(vl_placement[u][1]), 4)), ','] # degrees, no units + t += ['LabelOut=true,'] + t += ['Ldist=', str(round(float(scale * vl_placement[u][0]), 4)), units, ','] + t += ['Lpos=', str(round(float(vl_placement[u][1]), 4)), ','] # degrees, no units else: - s += ['NoLabel,'] + t += ['NoLabel,'] # vertex label information is available to all pre-built styles # but may be ignored by the style, so not apparent if vertex_labels or not customized: if vertex_labels_math and not (isinstance(u, str) and u[0] == '$' and u[-1] == '$'): - lab = r'\hbox{$%s$}' % latex(u) + ltx = str(latex(u)) + if '\\' in ltx: # complicated case; use \sbox + box = r'\sbox{\vertex}{$' + ltx + '$}' + lab = r'\usebox{\vertex}' + else: + lab = r'\hbox{$%s$}' % ltx else: lab = r'\hbox{%s}' % u - s += ['L=', lab, ','] + t += ['L=', lab, ','] scaled_pos = translate(pos[u]) - s += ['x=', str(round(float(scale * scaled_pos[0]), 4)), units, ','] - s += ['y=', str(round(float(scale * scaled_pos[1]), 4)), units] - s += [']'] - s += ['{', prefix, str(index_of_vertex[u]), '}\n'] + t += ['x=', str(round(float(scale * scaled_pos[0]), 4)), units, ','] + t += ['y=', str(round(float(scale * scaled_pos[1]), 4)), units] + t += [']'] + t += ['{', prefix, str(index_of_vertex[u]), '}\n'] + if box: + v += [box] + t + box = '' + used = True + else: + v += t + if used: + s += [r'\newsavebox{\vertex}' + '\n'] + v + else: + s += v s += ['%\n'] - # Create each edge or loop + # Create edges and loops for e in self._graph.edges(sort=False): edge = (e[0], e[1]) loop = e[0] == e[1] From d2e479924cef0953f6f2ad03161da50175019140 Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Sat, 5 Oct 2024 10:14:00 +0200 Subject: [PATCH 072/108] Update src/sage/interfaces/magma_free.py Co-authored-by: Vincent Macri --- src/sage/interfaces/magma_free.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 5c747774aab..876487349b2 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -26,7 +26,9 @@ def magma_free_eval(code, strip=True, columns=0): Use the free online MAGMA calculator to evaluate the given input code and return the answer as a string. - LIMITATIONS: The code must evaluate in at most 120 seconds + .. WARNING:: + + The code must evaluate in at most 120 seconds and there is a limitation on the amount of RAM. EXAMPLES:: From 884570c6f86c88451ddc4599dd1a64defdef878f Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Sat, 5 Oct 2024 10:14:11 +0200 Subject: [PATCH 073/108] Update src/sage/interfaces/magma_free.py Co-authored-by: Vincent Macri --- src/sage/interfaces/magma_free.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 876487349b2..6301786bb80 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -29,7 +29,7 @@ def magma_free_eval(code, strip=True, columns=0): .. WARNING:: The code must evaluate in at most 120 seconds - and there is a limitation on the amount of RAM. + and there is a limitation on the amount of RAM. EXAMPLES:: From 81f9a96ddcae6681dfa6ddd5583c0800ba41d882 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 5 Oct 2024 12:06:43 +0200 Subject: [PATCH 074/108] make dict an alias to avoid duplicating docstrings --- src/sage/rings/polynomial/laurent_polynomial.pxd | 2 +- src/sage/rings/polynomial/laurent_polynomial.pyx | 10 ++++------ src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 3 +-- .../rings/polynomial/multi_polynomial_libsingular.pyx | 3 +-- src/sage/rings/polynomial/ore_polynomial_element.pxd | 1 - src/sage/rings/polynomial/ore_polynomial_element.pyx | 9 +++++---- src/sage/rings/polynomial/polynomial_element.pyx | 3 +-- src/sage/rings/power_series_pari.pyx | 3 +-- src/sage/rings/power_series_poly.pyx | 3 +-- src/sage/rings/tate_algebra_element.pyx | 3 +-- 10 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pxd b/src/sage/rings/polynomial/laurent_polynomial.pxd index 249e69b49e2..1937490caac 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pxd +++ b/src/sage/rings/polynomial/laurent_polynomial.pxd @@ -7,9 +7,9 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): cpdef _mul_(self, other) cpdef _floordiv_(self, other) cpdef long number_of_terms(self) except -1 - cpdef dict dict(self) cpdef dict monomial_coefficients(self) + cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef ModuleElement __u cdef long __n diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 4b6ad584cb0..d90ce333af1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -218,7 +218,7 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): """ return self.number_of_terms() - cpdef dict dict(self): + cpdef dict monomial_coefficients(self): """ Abstract ``dict`` method. @@ -226,15 +226,14 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): sage: R. = LaurentPolynomialRing(ZZ) sage: from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial - sage: LaurentPolynomial.dict(x) + sage: LaurentPolynomial.monomial_coefficients(x) Traceback (most recent call last): ... NotImplementedError """ raise NotImplementedError - cpdef dict monomial_coefficients(self): - raise NotImplementedError + dict = monomial_coefficients def map_coefficients(self, f, new_base_ring=None): """ @@ -863,8 +862,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef dict d = self.__u.monomial_coefficients() return {k + self.__n: d[k] for k in d} - cpdef dict dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def coefficients(self): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 5653459f106..3da9540d905 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -814,8 +814,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): self._compute_polydict() return < dict > self._prod.dict() - cpdef dict dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def _fraction_pair(self): """ diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 0f05f3a93d9..6f105277f5b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3022,8 +3022,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): p = pNext(p) return pd - def dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def iterator_exp_coeff(self, as_ETuples=True): """ diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pxd b/src/sage/rings/polynomial/ore_polynomial_element.pxd index 73bc162a146..771c4d6325a 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pxd +++ b/src/sage/rings/polynomial/ore_polynomial_element.pxd @@ -38,7 +38,6 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef list _mul_list(self, list A) cpdef _mul_(self, other) - cpdef dict dict(self) cpdef dict monomial_coefficients(self) cpdef list list(self, bint copy=*) diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 09146960c86..768565840f6 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -2491,10 +2491,12 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma] sage: a = x^2012 + t*x^1006 + t^3 + 2*t - sage: a.dict() + sage: a.monomial_coefficients() {0: t^3 + 2*t, 1006: t, 2012: 1} - sage: a.monomial_coefficients() + ``dict`` is an alias:: + + sage: a.dict() {0: t^3 + 2*t, 1006: t, 2012: 1} """ cdef dict X = {} @@ -2506,8 +2508,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): X[i] = c return X - cpdef dict dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients cpdef Integer degree(self): r""" diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 04fb9518ab8..85ab231395a 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4487,8 +4487,7 @@ cdef class Polynomial(CommutativePolynomial): X[i] = c return X - def dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def factor(self, **kwargs): r""" diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index ca79b979228..8f7ff769dd1 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -756,8 +756,7 @@ cdef class PowerSeries_pari(PowerSeries): """ return self.polynomial().monomial_coefficients() - def dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def _derivative(self, var=None): """ diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 4f5e02df06c..309d72c8f6a 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -816,8 +816,7 @@ cdef class PowerSeries_poly(PowerSeries): """ return self.__f.monomial_coefficients() - def dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def _derivative(self, var=None): """ diff --git a/src/sage/rings/tate_algebra_element.pyx b/src/sage/rings/tate_algebra_element.pyx index d8aa8758b42..c2fd9cbfc8d 100644 --- a/src/sage/rings/tate_algebra_element.pyx +++ b/src/sage/rings/tate_algebra_element.pyx @@ -2213,8 +2213,7 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): self._normalize() return dict(self._poly.__repn) - def dict(self): - return self.monomial_coefficients() + dict = monomial_coefficients def coefficient(self, exponent): r""" From 38904b6cfe8a1deaa33cac7e8a3c203b594443bc Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 5 Oct 2024 12:28:20 +0200 Subject: [PATCH 075/108] replace iteritems with items in modified files --- .../free_algebra_element_letterplace.pyx | 2 +- .../polynomial/laurent_polynomial_mpair.pyx | 10 +++++----- src/sage/rings/polynomial/multi_polynomial.pyx | 16 ++++++++-------- .../polynomial/multi_polynomial_libsingular.pyx | 16 ++++++++-------- .../polynomial/multi_polynomial_ring_base.pyx | 2 +- src/sage/rings/polynomial/plural.pyx | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 6 +++--- .../polynomial/polynomial_ring_homomorphism.pyx | 4 ++-- src/sage/rings/power_series_mpoly.pyx | 4 ++-- src/sage/rings/power_series_ring_element.pyx | 2 +- src/sage/rings/tate_algebra_element.pyx | 4 +++- src/sage/symbolic/expression.pyx | 6 +++--- 12 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx index 8eae3602f9d..2a977b1a513 100644 --- a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx @@ -140,7 +140,7 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): [((0, 0, 0, 1, 0, 0, 0, 1), 2), ((0, 1, 0, 0, 0, 0, 1, 0), 1)] """ cdef dict d = self._poly.monomial_coefficients() - yield from d.iteritems() + yield from d.items() def _repr_(self): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 3da9540d905..2384eaf5b12 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -108,7 +108,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if isinstance(x, dict): self._mon = ETuple({}, int(parent.ngens())) D = {} - for k, x_k in x.iteritems(): # ETuple-ize keys, set _mon + for k, x_k in x.items(): # ETuple-ize keys, set _mon if not isinstance(k, (tuple, ETuple)) or len(k) != parent.ngens(): self._mon = ETuple({}, int(parent.ngens())) break @@ -119,7 +119,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): else: x = D if not self._mon.is_constant(): # factor out _mon - x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} + x = {k.esub(self._mon): x_k for k, x_k in x.items()} elif (isinstance(x, LaurentPolynomial_mpair) and parent.variable_names() == x.parent().variable_names()): self._mon = ( < LaurentPolynomial_mpair > x)._mon @@ -1565,11 +1565,11 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): except ValueError: # call _derivative() recursively on coefficients return P({m: c._derivative(var) - for m, c in self.monomial_coefficients().iteritems()}) + for m, c in self.monomial_coefficients().items()}) # compute formal derivative with respect to generator cdef dict d = {} - for m, c in self.monomial_coefficients().iteritems(): + for m, c in self.monomial_coefficients().items(): if m[index] != 0: new_m = [u for u in m] new_m[index] += -1 @@ -1650,7 +1650,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if R is None: R = LaurentPolynomialRing(self.base_ring(), x) - return R({m[i]: c for m, c in self.monomial_coefficients().iteritems()}) + return R({m[i]: c for m, c in self.monomial_coefficients().items()}) def monomial_reduction(self): """ diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index a537334ba3f..e6cfbcec7cb 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -260,7 +260,7 @@ cdef class MPolynomial(CommutativePolynomial): ind = Z.index(var) except ValueError: raise ValueError("var must be one of the generators of the parent polynomial ring.") - return R({k: c for k, c in self.monomial_coefficients().iteritems() + return R({k: c for k, c in self.monomial_coefficients().items() if k[ind] < n}) def _fast_callable_(self, etb): @@ -299,7 +299,7 @@ cdef class MPolynomial(CommutativePolynomial): n = len(x) expr = etb.constant(self.base_ring().zero()) - for m, c in self.monomial_coefficients().iteritems(): + for m, c in self.monomial_coefficients().items(): monom = prod([x[i] ** m[i] for i in range(n) if m[i] != 0], etb.constant(c)) expr = expr + monom @@ -426,12 +426,12 @@ cdef class MPolynomial(CommutativePolynomial): d = self.degree(var) B = ring.base_ring() w = {remove_from_tuple(e, ind): val - for e, val in self.monomial_coefficients().iteritems() if not e[ind]} + for e, val in self.monomial_coefficients().items() if not e[ind]} v = [B(w)] # coefficients that don't involve var z = var for i in range(1,d+1): c = self.coefficient(z).monomial_coefficients() - w = {remove_from_tuple(e, ind): val for e, val in c.iteritems()} + w = {remove_from_tuple(e, ind): val for e, val in c.items()} v.append(B(w)) z *= var return ring(v) @@ -511,12 +511,12 @@ cdef class MPolynomial(CommutativePolynomial): new_map[k] -= m tmp = [0] * (len(vars) - m) try: - for ix, a in self.monomial_coefficients().iteritems(): + for ix, a in self.monomial_coefficients().items(): for k in range(len(my_vars)): tmp[new_map[k]] = ix[k] postfix = ETuple(tmp) mpoly = a._mpoly_dict_recursive(prev_vars, base_ring) - for prefix, b in mpoly.iteritems(): + for prefix, b in mpoly.items(): D[prefix + postfix] = b return D @@ -527,7 +527,7 @@ cdef class MPolynomial(CommutativePolynomial): base_ring = None tmp = [0] * len(vars) - for ix, a in self.monomial_coefficients().iteritems(): + for ix, a in self.monomial_coefficients().items(): for k in range(len(my_vars)): tmp[mapping[k]] = ix[k] if base_ring is not None: @@ -578,7 +578,7 @@ cdef class MPolynomial(CommutativePolynomial): cdef long result_mon var_name_hash = [hash(v) for v in self._parent.variable_names()] cdef long c_hash - for m, c in self.monomial_coefficients().iteritems(): + for m, c in self.monomial_coefficients().items(): # I'm assuming (incorrectly) that hashes of zero indicate that the element is 0. # This assumption is not true, but I think it is true enough for the purposes and it # it allows us to write fast code that omits terms with 0 coefficients. This is diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 6f105277f5b..6f489e75a5a 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -855,7 +855,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if element.parent() == self: bucket = sBucketCreate(_ring) try: - for (m,c) in element.element().dict().iteritems(): + for m, c in element.element().dict().items(): mon = p_Init(_ring) p_SetCoeff(mon, sa2si(c, _ring), _ring) for pos in m.nonzero_positions(): @@ -893,7 +893,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): if element.parent().ngens() <= self.ngens(): bucket = sBucketCreate(_ring) try: - for (m,c) in element.element().dict().iteritems(): + for m, c in element.element().dict().items(): if check: c = base_ring(c) if not c: @@ -923,7 +923,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): else: bucket = sBucketCreate(_ring) try: - for (m,c) in element.iteritems(): + for m, c in element.items(): if check: c = base_ring(c) if not c: @@ -2088,7 +2088,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): except TypeError: # give up, evaluate functional sage_res = parent.base_ring().zero() - for m, c in self.monomial_coefficients().iteritems(): + for m, c in self.monomial_coefficients().items(): sage_res += c * mul([x[i] ** m[i] for i in m.nonzero_positions()]) else: singular_polynomial_call(&res, self._poly, _ring, coerced_x, @@ -5272,7 +5272,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): if base_map is None: # Just use conversion base_map = codomain - for m, c in self.monomial_coefficients().iteritems(): + for m, c in self.monomial_coefficients().items(): y += base_map(c) * mul([im_gens[i] ** m[i] for i in range(n) if m[i]]) return y @@ -5400,7 +5400,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): v = ETuple({index: 1}, len(gens)) _p = p_ISet(0, _ring) - for exp, coeff in self.monomial_coefficients().iteritems(): + for exp, coeff in self.monomial_coefficients().items(): nexp = exp.eadd(v) # new exponent mon = p_Init(_ring) p_SetCoeff(mon, sa2si(coeff / (1 + exp[index]), _ring), _ring) @@ -5906,9 +5906,9 @@ def unpickle_MPolynomial_libsingular(MPolynomialRing_libsingular R, d): rChangeCurrRing(r) bucket = sBucketCreate(r) try: - for mon,c in d.iteritems(): + for mon, c in d.items(): m = p_Init(r) - for i,e in mon.sparse_iter(): + for i, e in mon.sparse_iter(): _i = i if _i >= r.N: p_Delete(&m, r) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index dffe6cb80c1..fd1be03bea5 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -624,7 +624,7 @@ cdef class MPolynomialRing_base(CommutativeRing): K = self.base_ring() D = {} var_range = range(len(self.variable_names())) - for ix, a in x.monomial_coefficients().iteritems(): + for ix, a in x.monomial_coefficients().items(): ix = ETuple([0 if name_mapping[t] == -1 else ix[name_mapping[t]] for t in var_range]) D[ix] = K(a) diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 8fb9592e0b7..735d7d98041 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1403,7 +1403,7 @@ def unpickle_NCPolynomial_plural(NCPolynomialRing_plural R, d): cdef int _i, _e p = p_ISet(0,r) rChangeCurrRing(r) - for mon,c in d.iteritems(): + for mon, c in d.items(): m = p_Init(r) for i,e in mon.sparse_iter(): _i = i diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 85ab231395a..2449b3208ae 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3880,7 +3880,7 @@ cdef class Polynomial(CommutativePolynomial): cdef dict D = {} cdef tuple leftovers = (0,) * (len(variables) - len(prev_variables) - 1) for k in range(len(mpolys)): - for i,a in mpolys[k].iteritems(): + for i, a in mpolys[k].items(): j = ETuple((k,) + leftovers) D[i + j] = a @@ -12687,11 +12687,11 @@ cpdef list _dict_to_list(dict x, zero): if isinstance(n, tuple): # a mpoly dict n = n[0] v = [zero] * (n+1) - for i, z in x.iteritems(): + for i, z in x.items(): v[i[0]] = z else: v = [zero] * (n+1) - for i, z in x.iteritems(): + for i, z in x.items(): v[i] = z return v diff --git a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx index 01aca9fed01..087e520dc23 100644 --- a/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx +++ b/src/sage/rings/polynomial/polynomial_ring_homomorphism.pyx @@ -58,7 +58,7 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): P = self.codomain() f = self.underlying_map() if P.is_sparse(): - return P({a: f(b) for a, b in x.monomial_coefficients().iteritems()}) + return P({a: f(b) for a, b in x.monomial_coefficients().items()}) else: return P([f(b) for b in x]) @@ -88,7 +88,7 @@ cdef class PolynomialRingHomomorphism_from_base(RingHomomorphism_from_base): P = self.codomain() f = self.underlying_map() if P.is_sparse(): - return P({a: f(b) for a, b in x.monomial_coefficients().iteritems()}, + return P({a: f(b) for a, b in x.monomial_coefficients().items()}, *args, **kwds) else: return P([f(b) for b in x], *args, **kwds) diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index 44c4be93423..741b0ad94e7 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -58,11 +58,11 @@ cdef class PowerSeries_mpoly(PowerSeries): d = {} if isinstance(B, MPolynomialRing_base): for i in range(len(v)): - for n, c in v[i].monomial_coefficients().iteritems(): + for n, c in v[i].monomial_coefficients().items(): d[tuple(n) + (i,)] = c else: for i in range(len(v)): - for n, c in v[i].monomial_coefficients().iteritems(): + for n, c in v[i].monomial_coefficients().items(): d[(n,i)] = c self.__f = S(d) diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 725927ba5ad..b1ca6ea4ab1 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1045,7 +1045,7 @@ cdef class PowerSeries(AlgebraElement): else: n = int(n) v = {} - for k, x in self.monomial_coefficients().iteritems(): + for k, x in self.monomial_coefficients().items(): if k >= n: v[k-n] = x return self._parent(v, self.prec()-n) diff --git a/src/sage/rings/tate_algebra_element.pyx b/src/sage/rings/tate_algebra_element.pyx index c2fd9cbfc8d..022b5d1c880 100644 --- a/src/sage/rings/tate_algebra_element.pyx +++ b/src/sage/rings/tate_algebra_element.pyx @@ -2371,7 +2371,9 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): return elt.lift_to_precision(prec) except PrecisionError: return elt.lift_to_precision() - ans._poly = PolyDict({ e: lift_without_error(c) for (e,c) in self._poly.__repn.iteritems() }, None) + ans._poly = PolyDict({e: lift_without_error(c) + for e, c in self._poly.__repn.items()}, + None) if prec is None: prec = self._parent.precision_cap() ans._prec = max(self._prec, prec) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 18d47b0da2c..ca523ee9a95 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -5846,12 +5846,12 @@ cdef class Expression(Expression_abc): if kwds: # Ensure that the keys are symbolic variables. - varkwds = {self._parent.var(k): v for k,v in kwds.iteritems()} + varkwds = {self._parent.var(k): v for k,v in kwds.items()} # Check for duplicate _dict_update_check_duplicate(sdict, varkwds) cdef GExMap smap - for k, v in sdict.iteritems(): + for k, v in sdict.items(): smap.insert(make_pair((self.coerce_in(k))._gobj, (self.coerce_in(v))._gobj)) res = self._gobj.subs_map(smap, 0) @@ -5999,7 +5999,7 @@ cdef class Expression(Expression_abc): if kwds: # Ensure that the keys are functions. - funkwds = {_find_func(k): v for k,v in kwds.iteritems()} + funkwds = {_find_func(k): v for k,v in kwds.items()} # Check for duplicate _dict_update_check_duplicate(sdict, funkwds) From 949f228647c46c672323e31a3c5ab9bda6b33492 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 5 Oct 2024 22:03:27 +0900 Subject: [PATCH 076/108] Add a doctest --- src/sage/graphs/graph_latex.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 3e42f1b6648..1bb4a3fc297 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1562,6 +1562,21 @@ def tkz_picture(self): % % \end{tikzpicture} + + For a complicated vertex, a tex box is used. :: + + sage: B = crystals.Tableaux(['B', 2], shape=[1]) + sage: latex(B) + \begin{tikzpicture} + ... + \newsavebox{\vertex} + \sbox{\vertex}{${\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1} + \lr{1}\\\cline{1-1} + \end{array}$} + }$}\Vertex[style={minimum size=1.0cm,draw=cv0,fill=cfv0,text=clv0,shape=circle},LabelOut=false,L=\usebox{\vertex},x=...,y=...]{v0} + ... + \end{tikzpicture} """ # This routine does not handle multiple edges # It will properly handle digraphs where a pair of vertices has an edge From cb6624dacb215bb1a6039145df64e28bc8635d0f Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+s-s-sawant@users.noreply.github.com> Date: Sat, 5 Oct 2024 21:18:33 +0530 Subject: [PATCH 077/108] Update changes accordingly --- src/sage/graphs/graph.py | 402 --------------------------------------- 1 file changed, 402 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 992c8ed96f1..c4a1d84f2c5 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4217,408 +4217,6 @@ def mono(pi): ret += prod(fact[i] for i in pa.to_exp()) * m[pa] * (1+t)**mono(pi) return ret - @doc_index("Leftovers") - def matching(self, value_only=False, algorithm='Edmonds', - use_edge_labels=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): - r""" - Return a maximum weighted matching of the graph represented by the list - of its edges. - - For more information, see the :wikipedia:`Matching_(graph_theory)`. - - Given a graph `G` such that each edge `e` has a weight `w_e`, a maximum - matching is a subset `S` of the edges of `G` of maximum weight such that - no two edges of `S` are incident with each other. - - As an optimization problem, it can be expressed as: - - .. MATH:: - - \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\ - \mbox{Such that : }&\forall v \in G, - \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\ - &\forall x\in G, b_x\mbox{ is a binary variable} - - INPUT: - - - ``value_only`` -- boolean (default: ``False``); when set to ``True``, - only the cardinal (or the weight) of the matching is returned - - - ``algorithm`` -- string (default: ``'Edmonds'``) - - - ``'Edmonds'`` selects Edmonds' algorithm as implemented in NetworkX - - - ``'LP'`` uses a Linear Program formulation of the matching problem - - - ``use_edge_labels`` -- boolean (default: ``False``) - - - when set to ``True``, computes a weighted matching where each edge - is weighted by its label (if an edge has no label, `1` is assumed) - - - when set to ``False``, each edge has weight `1` - - - ``solver`` -- string (default: ``None``); specifies a Mixed Integer - Linear Programming (MILP) solver to be used. If set to ``None``, the - default one is used. For more information on MILP solvers and which - default solver is used, see the method :meth:`solve - ` of the class - :class:`MixedIntegerLinearProgram - `. - - - ``verbose`` -- integer (default: 0); sets the level of verbosity: - set to 0 by default, which means quiet (only useful when ``algorithm - == "LP"``) - - - ``integrality_tolerance`` -- float; parameter for use with MILP - solvers over an inexact base ring; see - :meth:`MixedIntegerLinearProgram.get_values`. - - OUTPUT: - - - When ``value_only=False`` (default), this method returns an - :class:`EdgesView` containing the edges of a maximum matching of `G`. - - - When ``value_only=True``, this method returns the sum of the - weights (default: ``1``) of the edges of a maximum matching of `G`. - The type of the output may vary according to the type of the edge - labels and the algorithm used. - - ALGORITHM: - - The problem is solved using Edmond's algorithm implemented in NetworkX, - or using Linear Programming depending on the value of ``algorithm``. - - EXAMPLES: - - Maximum matching in a Pappus Graph:: - - sage: g = graphs.PappusGraph() - sage: g.matching(value_only=True) # needs sage.networkx - 9 - - Same test with the Linear Program formulation:: - - sage: g = graphs.PappusGraph() - sage: g.matching(algorithm='LP', value_only=True) # needs sage.numerical.mip - 9 - - .. PLOT:: - - g = graphs.PappusGraph() - sphinx_plot(g.plot(edge_colors={"red":g.matching()})) - - TESTS: - - When ``use_edge_labels`` is set to ``False``, with Edmonds' algorithm - and LP formulation:: - - sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: sorted(g.matching()) # needs sage.networkx - [(0, 1, 0), (2, 3, -5)] - sage: sorted(g.matching(algorithm='LP')) # needs sage.numerical.mip - [(0, 1, 0), (2, 3, -5)] - - When ``use_edge_labels`` is set to ``True``, with Edmonds' algorithm and - LP formulation:: - - sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: g.matching(use_edge_labels=True) # needs sage.networkx - [(1, 2, 999)] - sage: g.matching(algorithm='LP', use_edge_labels=True) # needs sage.numerical.mip - [(1, 2, 999)] - - With loops and multiedges:: - - sage: edge_list = [(0,0,5), (0,1,1), (0,2,2), (0,3,3), (1,2,6) - ....: , (1,2,3), (1,3,3), (2,3,3)] - sage: g = Graph(edge_list, loops=True, multiedges=True) - sage: m = g.matching(use_edge_labels=True) # needs sage.networkx - sage: type(m) # needs sage.networkx - - sage: sorted(m) # needs sage.networkx - [(0, 3, 3), (1, 2, 6)] - - TESTS: - - If ``algorithm`` is set to anything different from ``'Edmonds'`` or - ``'LP'``, an exception is raised:: - - sage: g = graphs.PappusGraph() - sage: g.matching(algorithm='somethingdifferent') - Traceback (most recent call last): - ... - ValueError: algorithm must be set to either "Edmonds" or "LP" - """ - from sage.rings.real_mpfr import RR - - def weight(x): - if x in RR: - return x - else: - return 1 - - W = {} - L = {} - for u, v, l in self.edge_iterator(): - if u is v: - continue - fuv = frozenset((u, v)) - if fuv not in L or (use_edge_labels and W[fuv] < weight(l)): - L[fuv] = l - if use_edge_labels: - W[fuv] = weight(l) - - if algorithm == "Edmonds": - import networkx - g = networkx.Graph() - if use_edge_labels: - for (u, v), w in W.items(): - g.add_edge(u, v, weight=w) - else: - for u, v in L: - g.add_edge(u, v) - d = networkx.max_weight_matching(g) - if value_only: - if use_edge_labels: - return sum(W[frozenset(e)] for e in d) - return Integer(len(d)) - - return EdgesView(Graph([(u, v, L[frozenset((u, v))]) for u, v in d], - format='list_of_edges')) - - elif algorithm == "LP": - g = self - from sage.numerical.mip import MixedIntegerLinearProgram - # returns the weight of an edge considering it may not be - # weighted ... - p = MixedIntegerLinearProgram(maximization=True, solver=solver) - b = p.new_variable(binary=True) - if use_edge_labels: - p.set_objective(p.sum(w * b[fe] for fe, w in W.items())) - else: - p.set_objective(p.sum(b[fe] for fe in L)) - # for any vertex v, there is at most one edge incident to v in - # the maximum matching - for v in g: - p.add_constraint(p.sum(b[frozenset(e)] for e in self.edge_iterator(vertices=[v], labels=False) - if e[0] != e[1]), max=1) - - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - if value_only: - if use_edge_labels: - return sum(w for fe, w in W.items() if b[fe]) - return Integer(sum(1 for fe in L if b[fe])) - - return EdgesView(Graph([(u, v, L[frozenset((u, v))]) - for u, v in L if b[frozenset((u, v))]], - format='list_of_edges')) - - raise ValueError('algorithm must be set to either "Edmonds" or "LP"') - - @doc_index("Leftovers") - def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, verbose=0, - *, integrality_tolerance=0.001): - r""" - Check whether this graph is factor-critical. - - A graph of order `n` is factor-critical if every subgraph of `n-1` - vertices have a perfect matching, hence `n` must be odd. See - :wikipedia:`Factor-critical_graph` for more details. - - This method implements the algorithm proposed in [LR2004]_ and we assume - that a graph of order one is factor-critical. The time complexity of the - algorithm is linear if a near perfect matching is given as input (i.e., - a matching such that all vertices but one are incident to an edge of the - matching). Otherwise, the time complexity is dominated by the time - needed to compute a maximum matching of the graph. - - INPUT: - - - ``matching`` -- (default: ``None``) a near perfect matching of the - graph, that is a matching such that all vertices of the graph but one - are incident to an edge of the matching. It can be given using any - valid input format of :class:`~sage.graphs.graph.Graph`. - - If set to ``None``, a matching is computed using the other parameters. - - - ``algorithm`` -- string (default: ``'Edmonds'``); the algorithm to use - to compute a maximum matching of the graph among - - - ``'Edmonds'`` selects Edmonds' algorithm as implemented in NetworkX - - - ``'LP'`` uses a Linear Program formulation of the matching problem - - - ``solver`` -- string (default: ``None``); specifies a Mixed Integer - Linear Programming (MILP) solver to be used. If set to ``None``, the - default one is used. For more information on MILP solvers and which - default solver is used, see the method :meth:`solve - ` of the class - :class:`MixedIntegerLinearProgram - `. - - - ``verbose`` -- integer (default: 0); sets the level of verbosity: - set to 0 by default, which means quiet (only useful when ``algorithm - == "LP"``) - - - ``integrality_tolerance`` -- float; parameter for use with MILP - solvers over an inexact base ring; see - :meth:`MixedIntegerLinearProgram.get_values`. - - EXAMPLES: - - Odd length cycles and odd cliques of order at least 3 are - factor-critical graphs:: - - sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx - [True, True, True, True, True] - sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx - [True, True, True, True, True] - - More generally, every Hamiltonian graph with an odd number of vertices - is factor-critical:: - - sage: G = graphs.RandomGNP(15, .2) - sage: G.add_path([0..14]) - sage: G.add_edge(14, 0) - sage: G.is_hamiltonian() - True - sage: G.is_factor_critical() # needs networkx - True - - Friendship graphs are non-Hamiltonian factor-critical graphs:: - - sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] # needs networkx - [True, True, True, True] - - Bipartite graphs are not factor-critical:: - - sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) # needs numpy - sage: G.is_factor_critical() # needs numpy - False - - Graphs with even order are not factor critical:: - - sage: G = graphs.RandomGNP(10, .5) - sage: G.is_factor_critical() - False - - One can specify a matching:: - - sage: F = graphs.FriendshipGraph(4) - sage: M = F.matching() # needs networkx - sage: F.is_factor_critical(matching=M) # needs networkx - True - sage: F.is_factor_critical(matching=Graph(M)) # needs networkx - True - - TESTS: - - Giving a wrong matching:: - - sage: G = graphs.RandomGNP(15, .3) - sage: while not G.is_biconnected(): - ....: G = graphs.RandomGNP(15, .3) - sage: M = G.matching() # needs networkx - sage: G.is_factor_critical(matching=M[:-1]) # needs networkx - Traceback (most recent call last): - ... - ValueError: the input is not a near perfect matching of the graph - sage: G.is_factor_critical(matching=G.edges(sort=True)) - Traceback (most recent call last): - ... - ValueError: the input is not a matching - sage: M = [(2*i, 2*i + 1) for i in range(9)] - sage: G.is_factor_critical(matching=M) - Traceback (most recent call last): - ... - ValueError: the input is not a matching of the graph - """ - if self.order() == 1: - return True - - # The graph must have an odd number of vertices, be 2-edge connected, so - # without bridges, and not bipartite - if (not self.order() % 2 or not self.is_connected() or - list(self.bridges()) or self.is_bipartite()): - return False - - if matching: - # We check that the input matching is a valid near perfect matching - # of the graph. - M = Graph(matching) - if any(d != 1 for d in M.degree()): - raise ValueError("the input is not a matching") - if not M.is_subgraph(self, induced=False): - raise ValueError("the input is not a matching of the graph") - if (self.order() != M.order() + 1) or (self.order() != 2*M.size() + 1): - raise ValueError("the input is not a near perfect matching of the graph") - else: - # We compute a maximum matching of the graph - M = Graph(self.matching(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) - - # It must be a near-perfect matching - if self.order() != M.order() + 1: - return False - - # We find the unsaturated vertex u, i.e., the only vertex of the graph - # not in M - for u in self: - if u not in M: - break - - # We virtually build an M-alternating tree T - from queue import Queue - Q = Queue() - Q.put(u) - even = set([u]) - odd = set() - pred = {u: u} - rank = {u: 0} - - while not Q.empty(): - x = Q.get() - for y in self.neighbor_iterator(x): - if y in odd: - continue - elif y in even: - # Search for the nearest common ancestor t of x and y - P = [x] - R = [y] - while P[-1] != R[-1]: - if rank[P[-1]] > rank[R[-1]]: - P.append(pred[P[-1]]) - elif rank[P[-1]] < rank[R[-1]]: - R.append(pred[R[-1]]) - else: - P.append(pred[P[-1]]) - R.append(pred[R[-1]]) - t = P.pop() - R.pop() - # Set t as pred of all vertices of the chains and add - # vertices marked odd to the queue - for a in itertools.chain(P, R): - pred[a] = t - rank[a] = rank[t] + 1 - if a in odd: - even.add(a) - odd.discard(a) - Q.put(a) - else: # y has not been visited yet - z = next(M.neighbor_iterator(y)) - odd.add(y) - even.add(z) - Q.put(z) - pred[y] = x - pred[z] = y - rank[y] = rank[x] + 1 - rank[z] = rank[y] + 1 - - # The graph is factor critical if all vertices are marked even - return len(even) == self.order() - @doc_index("Algorithmically hard stuff") def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): From 72085e25ef8429c62ba443b5f4a1643d5f95d269 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 5 Oct 2024 13:49:52 -0700 Subject: [PATCH 078/108] Do not allow Pari 2.17 or later: see #38769. --- build/pkgs/pari/spkg-configure.m4 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/pari/spkg-configure.m4 b/build/pkgs/pari/spkg-configure.m4 index 5ece8b4891e..207487119a6 100644 --- a/build/pkgs/pari/spkg-configure.m4 +++ b/build/pkgs/pari/spkg-configure.m4 @@ -1,7 +1,8 @@ SAGE_SPKG_CONFIGURE([pari], [ dnl See gp_version below on how the version is computed from MAJV.MINV.PATCHV m4_pushdef([SAGE_PARI_MINVER],["134916"])dnl this version and higher allowed - m4_pushdef([SAGE_PARI_MAXVER],["999999"])dnl this version and higher not allowed + dnl Do not allow Pari 2.17 or later, see #38769: + m4_pushdef([SAGE_PARI_MAXVER],["135424"])dnl this version and higher not allowed SAGE_SPKG_DEPCHECK([gmp readline], [ AC_PATH_PROG([GP], [gp]) if test x$GP = x; then dnl GP test From a89334f08657bbead8131d81750d55eea99b7a0e Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 6 Oct 2024 00:43:24 +0200 Subject: [PATCH 079/108] rpy2 (standard) cannot depend on r (optional) "make download-for-sdist" tries to download all standard sources and fails if we depend on a dummy package. Presumably fine since the r dummy package should only used at configure time. --- build/pkgs/rpy2/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/rpy2/dependencies b/build/pkgs/rpy2/dependencies index b88615716d4..60e624cf7ff 100644 --- a/build/pkgs/rpy2/dependencies +++ b/build/pkgs/rpy2/dependencies @@ -1,4 +1,4 @@ - r cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) + cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) ---------- All lines of this file are ignored except the first. From 53f03710edc1bf631b3733f7713f0f1a63795dcf Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 6 Oct 2024 14:56:06 +0900 Subject: [PATCH 080/108] It is a TeX box --- src/sage/graphs/graph_latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 1bb4a3fc297..86b3c3bc7a7 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1563,7 +1563,7 @@ def tkz_picture(self): % \end{tikzpicture} - For a complicated vertex, a tex box is used. :: + For a complicated vertex, a TeX box is used. :: sage: B = crystals.Tableaux(['B', 2], shape=[1]) sage: latex(B) From 790b04e05632c9adbd83678aae6ea50fa594c51e Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 6 Oct 2024 12:26:36 +0200 Subject: [PATCH 081/108] Set explicit install name path on macOS Without this cvxopt fails to start --- build/pkgs/suitesparse/spkg-install.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/pkgs/suitesparse/spkg-install.in b/build/pkgs/suitesparse/spkg-install.in index ab5253d2e77..f7ef16bb48b 100644 --- a/build/pkgs/suitesparse/spkg-install.in +++ b/build/pkgs/suitesparse/spkg-install.in @@ -9,7 +9,10 @@ echo "Configuring suitesparse" # gcc and gfortran version are not matching. # * SUITESPARSE_ENABLE_PROJECTS semi column separated list of the desired packages. Default is # all the packages in the suitesparse tarball. +# On macOS ARM cvxopt does not start if suitesparse uses @rpath, set explicit install name dir instead sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCMAKE_INSTALL_NAME_DIR="$SAGE_LOCAL/lib" \ + -DCMAKE_MACOSX_RPATH=OFF \ -DNSTATIC=ON \ -DSUITESPARSE_USE_FORTRAN=OFF \ -DSUITESPARSE_INCLUDEDIR_POSTFIX="" \ From ddbae0e86c0db5704d70840a1341c7be639f37e8 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Oct 2024 08:21:11 -0400 Subject: [PATCH 082/108] src/sage/functions/orthogonal_polys.py: avoid global state in doctests We have an mpmath test in this file that sets the global precision (decimal places) and "pretty" variable for all of mpmath. Instead it is safer to use a context manager for the precision, and to call print(foo) to obtain the string representation of foo. This fixes the following two test failures: Failed example: gegenbauer_mp(-7,0.5,0.3) Expected: 0.1291811875 Got: mpf('0.1291811874999999999999999952') and Failed example: gegenbauer_mp(2+3j, -0.75, -1000j) Expected: (-5038991.358609026523401901 + 9414549.285447104177860806j) Got: mpc(real='-5038991.358609026523401901035', imag='9414549.285447104177860806274') --- src/sage/functions/orthogonal_polys.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 78f4c6bc712..4bf17b6c049 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -2343,10 +2343,10 @@ class Func_ultraspherical(GinacFunction): sage: # needs mpmath sage: from mpmath import gegenbauer as gegenbauer_mp sage: from mpmath import mp - sage: mp.pretty = True; mp.dps=25 - sage: gegenbauer_mp(-7,0.5,0.3) + sage: print(gegenbauer_mp(-7,0.5,0.3)) 0.1291811875 - sage: gegenbauer_mp(2+3j, -0.75, -1000j) + sage: with mp.workdps(25): + ....: print(gegenbauer_mp(2+3j, -0.75, -1000j)) (-5038991.358609026523401901 + 9414549.285447104177860806j) TESTS: From 980411cd3dd51b6e4b353ab4704f5c2563482871 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Oct 2024 08:38:38 -0400 Subject: [PATCH 083/108] src/sage/libs/mpmath/ext_main.pyx: disable pretty printing for a test One test in this file sets mp.pretty=True but is failing for me, most likely due to the shared state inherent to mp.pretty. Since this test is inside a TESTS block and not visible to end users, the simplest way to fix it is to delete the mp.pretty=True and to look for the ugly output. --- src/sage/libs/mpmath/ext_main.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 11ccfc701d2..5226811b55c 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -1056,7 +1056,6 @@ cdef class Context: TESTS:: sage: from mpmath import * - sage: mp.pretty = True sage: mag(10), mag(10.0), mag(mpf(10)), int(ceil(log(10,2))) (4, 4, 4, 4) sage: mag(10j), mag(10+10j) @@ -1064,7 +1063,7 @@ cdef class Context: sage: mag(0.01), int(ceil(log(0.01,2))) (-6, -6) sage: mag(0), mag(inf), mag(-inf), mag(nan) - (-inf, +inf, +inf, nan) + (mpf('-inf'), mpf('+inf'), mpf('+inf'), mpf('nan')) :: From b918a1c08c4fd8e31615418df19a7030dbdbdedb Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Oct 2024 08:45:22 -0400 Subject: [PATCH 084/108] src/sage/libs/mpmath/ext_main.pyx: handle ugly mpmath output There's a test in this file that is trying to use the global property mp.pretty=True but is failing on my machine. Since the test is inside a TESTS block and not visible to end users, the simplest way to fix it is to expect the ugly output from mpmath; although in one instance we do call str() on an mpmath real number to obtain '2.3' instead of some 2.999... thing that would require a tolerance. --- src/sage/libs/mpmath/ext_main.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 5226811b55c..0ac92485aba 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -983,7 +983,6 @@ cdef class Context: TESTS:: sage: from mpmath import mp - sage: mp.pretty = True sage: (x, T) = mp._convert_param(3) sage: (x, type(x).__name__, T) (3, 'int', 'Z') @@ -991,11 +990,11 @@ cdef class Context: sage: (x, type(x).__name__, T) (mpq(5,2), 'mpq', 'Q') sage: (x, T) = mp._convert_param(2.3) - sage: (x, type(x).__name__, T) - (2.3, 'mpf', 'R') + sage: (str(x), type(x).__name__, T) + ('2.3', 'mpf', 'R') sage: (x, T) = mp._convert_param(2+3j) sage: (x, type(x).__name__, T) - ((2.0 + 3.0j), 'mpc', 'C') + (mpc(real='2.0', imag='3.0'), 'mpc', 'C') sage: mp.pretty = False """ cdef MPF v From 441ee05163a9071ad119d7b4eed9c8a35d371668 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Oct 2024 08:48:12 -0400 Subject: [PATCH 085/108] src/sage/libs/mpmath/ext_main.pyx: fix two repr tests with clone() There are two tests in this file that are attempting to test the repr() of an mpmath number with mp.pretty=True set globally. The shared state is causing test failures, but we can't simply leave it off, because that's the point of the test. Instead we can clone() the "mp" object to obtain a new one (whose state is not so global) and then work with that instead. --- src/sage/libs/mpmath/ext_main.pyx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 0ac92485aba..96111f7b942 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -2201,12 +2201,13 @@ cdef class constant(mpf_base): Represent ``self`` as a string. With mp.pretty=False, the representation differs from that of an ordinary mpf:: - sage: from mpmath import mp, pi - sage: mp.pretty = True - sage: repr(pi) + sage: from mpmath import mp + sage: mp2 = mp.clone() + sage: mp2.pretty = True + sage: repr(mp2.pi) '3.14159265358979' - sage: mp.pretty = False - sage: repr(pi) + sage: mp2.pretty = False + sage: repr(mp2.pi) '' """ if global_context.pretty: @@ -2372,11 +2373,12 @@ cdef class mpc(mpnumber): TESTS:: sage: from mpmath import mp - sage: mp.pretty = True - sage: repr(mp.mpc(2,3)) + sage: mp2 = mp.clone() + sage: mp2.pretty = True + sage: repr(mp2.mpc(2,3)) '(2.0 + 3.0j)' - sage: mp.pretty = False - sage: repr(mp.mpc(2,3)) + sage: mp2.pretty = False + sage: repr(mp2.mpc(2,3)) "mpc(real='2.0', imag='3.0')" """ if global_context.pretty: From 9051042b4f4a468bc51efe3498a9411b4ea5eb02 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 6 Oct 2024 22:42:35 +0900 Subject: [PATCH 086/108] Check R in rpy2 --- build/pkgs/r/spkg-configure.m4 | 14 ----------- build/pkgs/r_jupyter/dependencies | 6 ++++- build/pkgs/rpy2/spkg-configure.m4 | 42 +++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 25 deletions(-) delete mode 100644 build/pkgs/r/spkg-configure.m4 diff --git a/build/pkgs/r/spkg-configure.m4 b/build/pkgs/r/spkg-configure.m4 deleted file mode 100644 index 0552d0c56ce..00000000000 --- a/build/pkgs/r/spkg-configure.m4 +++ /dev/null @@ -1,14 +0,0 @@ -SAGE_SPKG_CONFIGURE([r], [dnl - dnl https://rpy2.github.io/doc/v3.4.x/html/overview.html#requirements - m4_pushdef([SAGE_R_MINVER], ["3.5"]) - PKG_CHECK_MODULES([R], [libR >= SAGE_R_MINVER], [dnl - AC_PATH_PROG([R], [R]) - AS_IF([test "x$R" = x], [dnl - AC_MSG_NOTICE([R is not found]) - sage_spkg_install_r=yes - ], [dnl TODO: check that versions of R and libR match - sage_spkg_install_r=no - ]) - ], [sage_spkg_install_r=yes]) - m4_popdef([SAGE_R_MINVER]) -]) diff --git a/build/pkgs/r_jupyter/dependencies b/build/pkgs/r_jupyter/dependencies index 44078fe297e..c9895da2b6d 100644 --- a/build/pkgs/r_jupyter/dependencies +++ b/build/pkgs/r_jupyter/dependencies @@ -1 +1,5 @@ -notebook r +notebook rpy2 + +---------- +R is the real dependency. But SPKG r is a dummy package, and does not install R. +Since SPKG rpy2 checks for the system R, we put rpy2 as a dependency instead. diff --git a/build/pkgs/rpy2/spkg-configure.m4 b/build/pkgs/rpy2/spkg-configure.m4 index 0cb3784ea9c..e19713c5775 100644 --- a/build/pkgs/rpy2/spkg-configure.m4 +++ b/build/pkgs/rpy2/spkg-configure.m4 @@ -1,14 +1,36 @@ SAGE_SPKG_CONFIGURE([rpy2], [ - SAGE_PYTHON_PACKAGE_CHECK([rpy2]) + SAGE_PYTHON_PACKAGE_CHECK([rpy2]) ], [dnl REQUIRED-CHECK - AC_REQUIRE([SAGE_SPKG_CONFIGURE_R]) - dnl rpy2 is only needed when there is a usable system R - AS_VAR_IF([sage_spkg_install_r], [yes], [dnl - AS_VAR_IF([sage_use_system_r], [installed], [dnl - dnl Legacy SPKG installation of r - AS_VAR_SET([SPKG_REQUIRE], [yes]) - ], [dnl No system package, no legacy SPKG installation - AS_VAR_SET([SPKG_REQUIRE], [no]) - ]) + dnl rpy2 is only needed when there is a usable system R + dnl Check for the R installation and version + dnl https://rpy2.github.io/doc/v3.4.x/html/overview.html#requirements + m4_pushdef([SAGE_R_MINVER], ["3.5"]) + PKG_CHECK_MODULES([R], [libR >= SAGE_R_MINVER], [dnl + AC_PATH_PROG([R_EXECUTABLE], [R]) + AS_IF([test "x$R_EXECUTABLE" = x], [dnl + AC_MSG_NOTICE([R is not found]) + dnl No R found, so do not require rpy2 package + AS_VAR_SET([SPKG_REQUIRE], [no]) + ], [dnl Extract R version + AC_MSG_CHECKING([for version of R executable]) + R_VERSION=$($R_EXECUTABLE --version | sed -n 's/^R version \([[0-9.]]*\).*/\1/p') + AC_MSG_RESULT([$R_VERSION]) + dnl Extract libR version + AC_MSG_CHECKING([for version of libR]) + LIBR_VERSION=$(pkg-config --modversion libR) + AC_MSG_RESULT([$LIBR_VERSION]) + dnl Compare R and libR versions + AS_IF([test "x$R_VERSION" = "x$LIBR_VERSION"], [dnl + AC_MSG_NOTICE([R and libR versions match ($R_VERSION)]) + dnl Good system R is found, require rpy2 package + AS_VAR_SET([SPKG_REQUIRE], [yes]) + ], [dnl R and libR versions do not match + AC_MSG_NOTICE([R version ($R_VERSION) does not match libR version ($LIBR_VERSION)]) + AS_VAR_SET([SPKG_REQUIRE], [no]) + ]) ]) + ], [dnl libR not found or outdated + AS_VAR_SET([SPKG_REQUIRE], [no]) + ]) + m4_popdef([SAGE_R_MINVER]) ]) From b2cdaa0567fd2764e45f66bd5ea9fb42e20180a7 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 19 Jan 2024 15:05:59 +0100 Subject: [PATCH 087/108] allow supplying a value of q for special_supersingular_curve() --- .../elliptic_curves/ell_finite_field.py | 174 ++++++++++++------ 1 file changed, 120 insertions(+), 54 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 65b49cfe1bd..50106558570 100755 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -2565,10 +2565,12 @@ def is_j_supersingular(j, proof=True): return E.trace_of_frobenius() % p == 0 -def special_supersingular_curve(F, *, endomorphism=False): +def special_supersingular_curve(F, q=None, *, endomorphism=False): r""" - Given a finite field ``F``, construct a "special" supersingular - elliptic curve `E` defined over ``F``. + Given a finite field ``F`` of characteristic `p`, and optionally + a positive integer `q` such that the Hilbert conductor of `-q` + and `-p` equals `p`, construct a "special" supersingular elliptic + curve `E` defined over ``F``. Such a curve @@ -2577,21 +2579,32 @@ def special_supersingular_curve(F, *, endomorphism=False): - has group structure `E(\mathbb F_p) \cong \ZZ/(p+1)` and `E(\mathbb F_{p^2}) \cong \ZZ/(p+1) \times \ZZ/(p+1)`; - - has an endomorphism `\vartheta` of small degree `q` that + - has an endomorphism `\vartheta` of degree `q` that anticommutes with the `\mathbb F_p`-Frobenius on `E`. (The significance of `\vartheta` is that any such endomorphism, together with the `\mathbb F_p`-Frobenius, generates the endomorphism algebra `\mathrm{End}(E) \otimes \QQ`.) + The complexity grows exponentially in `\log(q)`. Automatically + chosen values of `q` lie in `O((\log p)^2)` assuming GRH. + INPUT: - - ``F`` -- finite field `\mathbb F_{p^r}`; + - ``F`` -- finite field `\mathbb F_{p^r}` + + - ``q`` -- positive integer (optional, default ``None``) - ``endomorphism`` -- boolean (default: ``False``); when set to ``True``, it is required that `2 \mid r`, and the function then additionally returns `\vartheta` + .. WARNING:: + + Due to :issue:`38481`, calling this function with a value of `q` + larger than approximately `p/4` may currently fail. This failure + will not occur for automatically chosen values of `q`. + EXAMPLES:: sage: special_supersingular_curve(GF(1013^2), endomorphism=True) @@ -2604,8 +2617,8 @@ def special_supersingular_curve(F, *, endomorphism=False): Via: (u,r,s,t) = (389*z2 + 241, 0, 0, 0)) sage: special_supersingular_curve(GF(1021^2), endomorphism=True) - (Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2, - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2 to Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2) + (Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2, + Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2 to Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2) sage: special_supersingular_curve(GF(1031^2), endomorphism=True) (Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2, @@ -2630,6 +2643,20 @@ def special_supersingular_curve(F, *, endomorphism=False): Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2 Via: (u,r,s,t) = (922*z2 + 129, 0, 0, 0)) + We can also supply a suitable value of `q` ourselves:: + + sage: special_supersingular_curve(GF(1019), q=99) + Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field of size 1019 + + sage: special_supersingular_curve(GF(1019^2), q=99, endomorphism=True) + (Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2, + Isogeny of degree 99 from Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2 to Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2) + + sage: special_supersingular_curve(GF(1013), q=99) + Traceback (most recent call last): + ... + ValueError: invalid choice of q + TESTS:: sage: p = random_prime(1000) @@ -2678,6 +2705,35 @@ def special_supersingular_curve(F, *, endomorphism=False): sage: pi * endo == -endo * pi True + Also try it when `q` is given: + + sage: p = random_prime(300, lbound=10) + sage: k = ZZ(randrange(1, 5)) + sage: while True: + ....: q = randrange(1, p//4) # upper bound p//4 is a workaround for #38481 + ....: if QuaternionAlgebra(-q, -p).discriminant() == p: + ....: break + sage: E = special_supersingular_curve(GF((p, k)), q) + sage: E.is_supersingular() + True + sage: F. = GF((p, 2*k)) + sage: E, endo = special_supersingular_curve(F, q, endomorphism=True) + sage: E.is_supersingular() + True + sage: E.j_invariant() in GF(p) + True + sage: endo.domain() is endo.codomain() is E + True + sage: endo.degree() == q + True + sage: endo.trace() + 0 + sage: pi = E.frobenius_isogeny() + sage: pi.codomain() is pi.domain() is E + True + sage: pi * endo == -endo * pi + True + .. NOTE:: This function makes no guarantees about the distribution of @@ -2694,42 +2750,49 @@ def special_supersingular_curve(F, *, endomorphism=False): if endomorphism and deg % 2: raise ValueError('endomorphism was requested but is not defined over given field') - E = None + if q is not None: + from sage.arith.misc import hilbert_conductor + if p.divides(q) or hilbert_conductor(-q, -p) != p: + raise ValueError('invalid choice of q') # first find the degree q of our special endomorphism - if p == 2: - q = 3 - E = EllipticCurve(F, [0,0,1,0,0]) - - elif p % 4 == 3: - q = 1 - E = EllipticCurve(F, [1,0]) - - elif p % 3 == 2: - q = 3 - E = EllipticCurve(F, [0,1]) - - elif p % 8 == 5: - q = 2 - E = EllipticCurve(F, [-4320, 96768]) - - else: - from sage.arith.misc import legendre_symbol - for q in map(ZZ, range(3,p,4)): - if not q.is_prime(): - continue - if legendre_symbol(-q, p) == -1: - break + if q is None: + if p == 2: + q = 3 + elif p % 4 == 3: + q = 1 + elif p % 3 == 2: + q = 3 + elif p % 8 == 5: + q = 2 else: - assert False # should never happen + from sage.arith.misc import legendre_symbol + for q in map(ZZ, range(3,p,4)): + if not q.is_prime(): + continue + if legendre_symbol(-q, p) == -1: + break + else: # should never happen + assert False, 'bug in special_supersingular_curve()' + q = ZZ(q) - if E is None: - from sage.arith.misc import fundamental_discriminant - from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial - H = hilbert_class_polynomial(fundamental_discriminant(-q)) - j = H.change_ring(GF(p)).any_root() + from sage.arith.misc import fundamental_discriminant + from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial + H = hilbert_class_polynomial(fundamental_discriminant(-q)) + j = H.change_ring(GF(p)).any_root() + if j.is_zero(): + if p == 2: + ainvs = [0,0,1,0,0] + elif p == 3: + ainvs = [1,0] + else: + ainvs = [0,1] + elif j == 1728: + ainvs = [1,0] + else: a = 27 * j / (4 * (1728-j)) - E = EllipticCurve(F, [a,-a]) + ainvs = [a,-a] + E = EllipticCurve(F, ainvs) if ZZ(2).divides(deg): k = deg//2 @@ -2740,23 +2803,26 @@ def special_supersingular_curve(F, *, endomorphism=False): if not endomorphism: return E - if q == 1 or p <= 13: - if q == 1: - endos = E.automorphisms() - else: - endos = (iso*phi for phi in E.isogenies_prime_degree(q) - for iso in phi.codomain().isomorphisms(E)) - endo = next(endo for endo in endos if endo.trace().is_zero()) - + if q.is_one(): + endo = next(auto for auto in E.automorphisms() if auto.trace().is_zero()) else: - from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - iso = WeierstrassIsomorphism(None, (F(-q).sqrt(),0,0,0), E) - if q == 3 and E.a_invariants() == (0,0,0,0,1): - # workaround for #21883 - endo = E.isogeny(E(0,1)) - else: - endo = E.isogeny(None, iso.domain(), degree=q) - endo = iso * endo + iso = E.isomorphism(F(-q).sqrt(), is_codomain=True) + try: + endo = iso * E.isogeny(None, iso.domain(), degree=q) + except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481 + #FIXME this code could be simplified/optimized after #37388 and/or #35949 + def _isogs(E, d): + if d.is_one(): + yield E.identity_morphism() + return + l = d.prime_factors()[-1] + for phi in E.isogenies_prime_degree(l): + for psi in _isogs(phi.codomain(), d//l): + yield psi * phi + endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E)) +# endos = (iso*phi for phi in E.isogenies_degree(q) +# for iso in phi.codomain().isomorphisms(E)) + endo = next(endo for endo in endos if endo.trace().is_zero()) endo._degree = ZZ(q) endo.trace.set_cache(ZZ.zero()) From 736d4b0dc07220715b8705793d1435b05efee88c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 6 Oct 2024 23:10:22 +0900 Subject: [PATCH 088/108] Remove r from rpy2 dependencies list --- build/pkgs/rpy2/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/rpy2/dependencies b/build/pkgs/rpy2/dependencies index b88615716d4..271ec08a7f9 100644 --- a/build/pkgs/rpy2/dependencies +++ b/build/pkgs/rpy2/dependencies @@ -1,4 +1,4 @@ - r cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) +cffi tzlocal pytz jinja2 | $(PYTHON_TOOLCHAIN) pycparser $(PYTHON) ---------- All lines of this file are ignored except the first. From 6537374e5c02d6f39a71090a150df9cdc87e5bad Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 6 Oct 2024 18:49:18 +0200 Subject: [PATCH 089/108] add method orient to Graph --- src/sage/graphs/graph.py | 6 +- src/sage/graphs/orientations.py | 170 +++++++++++++++++++++++++++++++- 2 files changed, 174 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 976b629d49a..1d21d326104 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -9596,7 +9596,10 @@ def bipartite_double(self, extended=False): from sage.graphs.tutte_polynomial import tutte_polynomial from sage.graphs.lovasz_theta import lovasz_theta from sage.graphs.partial_cube import is_partial_cube - from sage.graphs.orientations import strong_orientations_iterator, random_orientation, acyclic_orientations + from sage.graphs.orientations import orient + from sage.graphs.orientations import strong_orientations_iterator + from sage.graphs.orientations import random_orientation + from sage.graphs.orientations import acyclic_orientations from sage.graphs.connectivity import bridges, cleave, spqr_tree from sage.graphs.connectivity import is_triconnected from sage.graphs.comparability import is_comparability @@ -9646,6 +9649,7 @@ def bipartite_double(self, extended=False): "is_permutation" : "Graph properties", "tutte_polynomial" : "Algorithmically hard stuff", "lovasz_theta" : "Leftovers", + "orient" : "Connectivity, orientations, trees", "strong_orientations_iterator" : "Connectivity, orientations, trees", "random_orientation" : "Connectivity, orientations, trees", "acyclic_orientations" : "Connectivity, orientations, trees", diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 2dac79b7146..1dce9456de7 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -12,6 +12,8 @@ :widths: 30, 70 :delim: | + :meth:`orient` | Return an oriented version of `G` according the input function `f`. + :meth:`acyclic_orientations` | Return an iterator over all acyclic orientations of an undirected graph `G`. :meth:`strong_orientations_iterator` | Return an iterator over all strong orientations of a graph `G` :meth:`random_orientation` | Return a random orientation of a graph `G` @@ -28,7 +30,7 @@ # **************************************************************************** # Copyright (C) 2017 Kolja Knauer # 2017 Petru Valicov -# 2017-2023 David Coudert +# 2017-2024 David Coudert # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,6 +43,172 @@ from sage.graphs.digraph import DiGraph +def orient(G, f, weighted=None, data_structure=None, sparse=None, + immutable=None, hash_labels=None): + r""" + Return an oriented version of `G` according the input function `f`. + + INPUT: + + - ``f`` -- a function that inputs an edge and outputs an orientation of this + edge + + - ``weighted`` -- boolean (default: ``None``); weightedness for the oriented + digraph. By default (``None``), the graph and its orientation will behave + the same. + + - ``sparse`` -- boolean (default: ``None``); ``sparse=True`` is an alias for + ``data_structure="sparse"``, and ``sparse=False`` is an alias for + ``data_structure="dense"``. Only used when ``data_structure=None``. + + - ``data_structure`` -- string (default: ``None``); one of ``'sparse'``, + ``'static_sparse'``, or ``'dense'``. See the documentation of + :class:`DiGraph`. + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable digraph. Only used when ``data_structure=None``. + + * ``immutable=None`` (default) means that the graph and its orientation + will behave the same way. + + * ``immutable=True`` is a shortcut for ``data_structure='static_sparse'`` + + * ``immutable=False`` means that the created digraph is mutable. When used + to orient an immutable graph, the data structure used is ``'sparse'`` + unless anything else is specified. + + - ``hash_labels`` -- boolean (default: ``None``); whether to include edge + labels during hashing of the oriented digraph. This parameter defaults to + ``True`` if the graph is weighted. This parameter is ignored when + parameter ``immutable`` is not ``True``. Beware that trying to hash + unhashable labels will raise an error. + + OUTPUT: a :class:`DiGraph` object + + .. NOTE:: + + This method behaves similarly to method + :meth:`~sage.graphs.generic_graph.GenericGraph.copy`. That is, the + returned digraph uses the same data structure by default, unless the + user asks to use another data structure, and the attributes of the input + graph are copied. + + EXAMPLES:: + + sage: G = graphs.CycleGraph(4); G + Cycle graph: Graph on 4 vertices + sage: D = G.orient(lambda e:e if e[0] < e[1] else (e[1], e[0], e[2])); D + Orientation of Cycle graph: Digraph on 4 vertices + sage: sorted(D.edges(labels=False)) + [(0, 1), (0, 3), (1, 2), (2, 3)] + + TESTS: + + We make sure that one can get an immutable orientation by providing the + ``data_structure`` optional argument:: + + sage: def foo(e): + ....: return e if e[0] < e[1] else (e[1], e[0], e[2]) + sage: G = graphs.CycleGraph(4) + sage: D = G.orient(foo, data_structure='static_sparse') + sage: D.is_immutable() + True + sage: D = G.orient(foo, immutable=True) + sage: D.is_immutable() + True + + Bad input:: + + sage: G.orient(foo, data_structure='sparse', sparse=False) + Traceback (most recent call last): + ... + ValueError: you cannot define 'immutable' or 'sparse' when 'data_structure' has a value + sage: G.orient(foo, data_structure='sparse', immutable=True) + Traceback (most recent call last): + ... + ValueError: you cannot define 'immutable' or 'sparse' when 'data_structure' has a value + sage: G.orient(foo, immutable=True, sparse=False) + Traceback (most recent call last): + ... + ValueError: there is no dense immutable backend at the moment + + Which backend? :: + + sage: G.orient(foo, data_structure='sparse')._backend + + sage: G.orient(foo, data_structure='dense')._backend + + sage: G.orient(foo, data_structure='static_sparse')._backend + + sage: G.orient(foo, immutable=True)._backend + + sage: G.orient(foo, immutable=True, sparse=True)._backend + + sage: G.orient(foo, immutable=False, sparse=True)._backend + + sage: G.orient(foo, immutable=False, sparse=False)._backend + + """ + # Which data structure should be used ? + if data_structure is not None: + # data_structure is already defined so there is nothing left to do + # here. Did the user try to define too much ? + if immutable is not None or sparse is not None: + raise ValueError("you cannot define 'immutable' or 'sparse' " + "when 'data_structure' has a value") + # At this point, data_structure is None. + elif immutable is True: + data_structure = 'static_sparse' + if sparse is False: + raise ValueError("there is no dense immutable backend at the moment") + elif immutable is False: + # If the user requests a mutable digraph and input is immutable, we + # choose the 'sparse' cgraph backend. Unless the user explicitly + # asked for something different. + if G.is_immutable(): + data_structure = 'dense' if sparse is False else 'sparse' + elif sparse is True: + data_structure = "sparse" + elif sparse is False: + data_structure = "dense" + + if data_structure is None: + from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(G._backend, DenseGraphBackend): + data_structure = "dense" + else: + data_structure = "sparse" + + if weighted is None: + weighted = G.weighted() + + edges = (f(e) for e in G.edge_iterator()) + D = DiGraph([G, edges], format='vertices_and_edges', + data_structure=data_structure, + loops=G.allows_loops(), + multiedges=G.allows_multiple_edges(), + name=f"Orientation of {G.name()}", + pos=copy(G._pos), weighted=weighted, + hash_labels=hash_labels) + + attributes_to_copy = ('_assoc', '_embedding') + for attr in attributes_to_copy: + if hasattr(G, attr): + copy_attr = {} + old_attr = getattr(G, attr) + if isinstance(old_attr, dict): + for v, value in old_attr.items(): + try: + copy_attr[v] = value.copy() + except AttributeError: + copy_attr[v] = copy(value) + setattr(D, attr, copy_attr) + else: + setattr(D, attr, copy(old_attr)) + + return D + + def acyclic_orientations(G): r""" Return an iterator over all acyclic orientations of an undirected graph `G`. From 5ac2ba4451d4bb7bfbab5aec764b968223cdad9e Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 6 Oct 2024 19:46:08 +0200 Subject: [PATCH 090/108] add missing description of input G --- src/sage/graphs/orientations.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 1dce9456de7..038ee1ebe81 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -50,6 +50,8 @@ def orient(G, f, weighted=None, data_structure=None, sparse=None, INPUT: + - ``G`` -- an undirected graph + - ``f`` -- a function that inputs an edge and outputs an orientation of this edge From 81e6a22c04d74573817d166d937ba004473b7894 Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Mon, 7 Oct 2024 09:32:43 +0200 Subject: [PATCH 091/108] Update src/sage/interfaces/magma_free.py Co-authored-by: Travis Scrimshaw --- src/sage/interfaces/magma_free.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 6301786bb80..87a02bade02 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -27,7 +27,6 @@ def magma_free_eval(code, strip=True, columns=0): input code and return the answer as a string. .. WARNING:: - The code must evaluate in at most 120 seconds and there is a limitation on the amount of RAM. From 0d9a010039f64c0edcf50d8e8418b16a20eb6b53 Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Mon, 7 Oct 2024 18:11:29 +0200 Subject: [PATCH 092/108] Update src/sage/interfaces/magma_free.py Co-authored-by: Vincent Macri --- src/sage/interfaces/magma_free.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 87a02bade02..5938e9fa4af 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -27,6 +27,7 @@ def magma_free_eval(code, strip=True, columns=0): input code and return the answer as a string. .. WARNING:: + The code must evaluate in at most 120 seconds and there is a limitation on the amount of RAM. From 4892701318e18a7122714f5ce8cf5c7433746813 Mon Sep 17 00:00:00 2001 From: Sagar Sawant <141299968+s-s-sawant@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:03:13 +0530 Subject: [PATCH 093/108] removed factorial, corrected edge_iterator --- src/sage/graphs/graph.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c4a1d84f2c5..3b4fa52e30c 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4191,7 +4191,6 @@ def tutte_symmetric_function(self, R=None, t=None): from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.set_partition import SetPartitions from sage.misc.misc_c import prod - from sage.arith.misc import factorial from collections import Counter if t is None: @@ -4201,7 +4200,7 @@ def tutte_symmetric_function(self, R=None, t=None): m = SymmetricFunctions(R).m() ret = m.zero() V = self.vertices() - M = Counter(list(self.edges(labels=False))) + M = Counter(self.edge_iterator(labels=False)) fact = [1] fact.extend(fact[-1] * i for i in range(1, len(V)+1)) From 5a9499963bcaf3fa4e6c06cb569be1423f929ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Oct 2024 09:51:09 +0200 Subject: [PATCH 094/108] slightly enhanced convolution of piecewise functions --- src/sage/functions/piecewise.py | 92 +++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 4e0274f810e..830526a0ed8 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -602,6 +602,8 @@ def unextend_zero(self, parameters, variable): """ result = [(domain, func) for domain, func in parameters if func != 0] + if len(result) == len(self): + return self return piecewise(result, var=variable) def pieces(self, parameters, variable): @@ -980,6 +982,17 @@ def convolution(self, parameters, variable, other): x|-->-x + 6 on (3, 4], x|-->-2*x + 10 on (4, 5]; x) + Some unbounded but convergent cases now work:: + + sage: p = piecewise([[(2,oo),exp(-x)]]) + sage: q = piecewise([[[2,3],x]]) + sage: p.convolution(q) + piecewise(x|-->(x - 3)*e^(-2) - e^(-x + 2) on (4, 5]; x) + sage: q.convolution(p) + piecewise(x|-->(x - 3)*e^(-2) - e^(-x + 2) on (4, 5]; x) + + TESTS:: + Check that the bugs raised in :issue:`12123` are fixed:: sage: f = piecewise([[(-2, 2), 2]]) @@ -1003,45 +1016,56 @@ def convolution(self, parameters, variable, other): fd, f0 = parameters[0] gd, g0 = next(other.items()) if len(f) == 1 == len(g): - f = f.unextend_zero() - g = g.unextend_zero() a1 = fd[0].lower() a2 = fd[0].upper() b1 = gd[0].lower() b2 = gd[0].upper() - with SR.temp_var() as tt: - with SR.temp_var() as uu: - i1 = f0.subs({variable: uu}) - i2 = g0.subs({variable: tt-uu}) - fg1 = definite_integral(i1*i2, uu, a1, tt-b1).subs({tt: variable}) - fg2 = definite_integral(i1*i2, uu, tt-b2, tt-b1).subs({tt: variable}) - fg3 = definite_integral(i1*i2, uu, tt-b2, a2).subs({tt: variable}) - fg4 = definite_integral(i1*i2, uu, a1, a2).subs({tt: variable}) - if a1-b1 < a2-b2: - if a2+b1 != a1+b2: - h = piecewise([[(a1+b1, a1+b2), fg1], - [(a1+b2, a2+b1), fg2], - [(a2+b1, a2+b2), fg3]]) - else: - h = piecewise([[(a1+b1, a1+b2), fg1], - [(a1+b2, a2+b2), fg3]]) + a1b1 = a1 + b1 + a2b2 = a2 + b2 + delta_a = a2 - a1 + delta_b = b2 - b1 + + # this fails in some unbounded cases: + a1b2 = a1 + b2 + a2b1 = a2 + b1 + + todo = [] + if delta_a > delta_b: + if a1b2 is not minus_infinity: + todo.append((a1b1, a1b2, a1, variable - b1)) + todo.append((a1b2, a2b1, variable - b2, variable - b1)) + if a2b1 is not infinity: + todo.append((a2b1, a2b2, variable - b2, a2)) + elif delta_a < delta_b: + if a2b1 is not minus_infinity: + todo.append((a1b1, a2b1, a1, variable - b1)) + todo.append((a2b1, a1b2, a1, a2)) + if a1b2 is not infinity: + todo.append((a1b2, a2b2, variable - b2, a2)) else: - if a1+b2 != a2+b1: - h = piecewise([[(a1+b1, a2+b1), fg1], - [(a2+b1, a1+b2), fg4], - [(a1+b2, a2+b2), fg3]]) - else: - h = piecewise([[(a1+b1, a2+b1), fg1], - [(a2+b1, a2+b2), fg3]]) - return (piecewise([[(minus_infinity, infinity), 0]]).piecewise_add(h)).unextend_zero() - - if len(f) > 1 or len(g) > 1: - z = piecewise([[(0, 0), 0]]) - for fpiece in f.pieces(): - for gpiece in g.pieces(): - h = gpiece.convolution(fpiece) - z = z.piecewise_add(h) - return z.unextend_zero() + if a2b1 is not minus_infinity: + todo.append((a1b1, a2b1, a1, variable - b1)) + todo.append((a2b1, a2b2, variable - b2, a2)) + + if not todo: + raise ValueError("no domain of integration") + + with SR.temp_var() as uu: + i1 = f0.subs({variable: uu}) + i2 = g0.subs({variable: variable - uu}) + expr = i1 * i2 + h = piecewise([[(start, stop), + definite_integral(expr, uu, mini, maxi)] + for start, stop, mini, maxi in todo]) + flat_zero = piecewise([[(minus_infinity, infinity), 0]]) + return (flat_zero.piecewise_add(h)).unextend_zero() # why ? + + z = piecewise([[(0, 0), 0]]) + for fpiece in f.pieces(): + for gpiece in g.pieces(): + h = gpiece.convolution(fpiece) + z = z.piecewise_add(h) + return z.unextend_zero() def trapezoid(self, parameters, variable, N): """ From 5d3d5365e8359538da2976046fa7d4deae156e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Oct 2024 10:48:15 +0200 Subject: [PATCH 095/108] fix doc formatting --- src/sage/functions/piecewise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 830526a0ed8..8a9dbb63c4f 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -991,7 +991,7 @@ def convolution(self, parameters, variable, other): sage: q.convolution(p) piecewise(x|-->(x - 3)*e^(-2) - e^(-x + 2) on (4, 5]; x) - TESTS:: + TESTS: Check that the bugs raised in :issue:`12123` are fixed:: From b1f4293a8216d45d9271a9906a954eba75091c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Oct 2024 10:54:02 +0200 Subject: [PATCH 096/108] fix typo --- src/sage/functions/piecewise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 8a9dbb63c4f..d7370a5cd30 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -274,7 +274,7 @@ def simplify(ex): OUTPUT: - A piecewise function whose operands are not piecewiese if + A piecewise function whose operands are not piecewise if possible, that is, as long as the piecewise variable is the same. EXAMPLES:: From 7b0e9661900c40fdb2135afdf374c3b6ab9421b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Oct 2024 20:06:24 +0200 Subject: [PATCH 097/108] using ruff to fix more E713 --- .github/sync_labels.py | 4 ++-- src/sage/coding/gabidulin_code.py | 2 +- .../arithmetic_dynamics/endPN_minimal_model.py | 2 +- .../dynamics/arithmetic_dynamics/projective_ds.py | 12 ++++++------ src/sage/functions/bessel.py | 2 +- src/sage/games/hexad.py | 6 +++--- src/sage/geometry/hyperplane_arrangement/plot.py | 6 +++--- src/sage/geometry/polyhedron/base5.py | 2 +- src/sage/graphs/digraph_generators.py | 2 +- src/sage/graphs/generators/classical_geometries.py | 2 +- src/sage/graphs/generic_graph.py | 4 ++-- src/sage/graphs/graph_latex.py | 2 +- src/sage/graphs/orientations.py | 4 ++-- src/sage/interfaces/maxima_lib.py | 2 +- src/sage/knots/knotinfo.py | 4 ++-- src/sage/knots/link.py | 4 ++-- src/sage/manifolds/point.py | 2 +- src/sage/quadratic_forms/genera/genus.py | 9 +++++---- src/sage/repl/rich_output/display_manager.py | 4 ++-- src/sage/rings/function_field/order_basis.py | 6 +++--- src/sage/rings/function_field/order_polymod.py | 2 +- src/sage/rings/function_field/order_rational.py | 2 +- src/sage/rings/number_field/number_field_ideal.py | 2 +- src/sage/rings/number_field/order.py | 4 ++-- src/sage/rings/pari_ring.py | 2 +- src/sage/rings/polynomial/pbori/ll.py | 2 +- src/sage/rings/valuation/augmented_valuation.py | 4 ++-- src/sage/rings/valuation/inductive_valuation.py | 2 +- src/sage/schemes/curves/affine_curve.py | 6 +++--- src/sage/schemes/curves/projective_curve.py | 12 ++++++------ src/sage/schemes/curves/zariski_vankampen.py | 6 +++--- src/sage/symbolic/callable.py | 4 ++-- src/sage/topology/simplicial_complex.py | 2 +- 33 files changed, 66 insertions(+), 65 deletions(-) diff --git a/.github/sync_labels.py b/.github/sync_labels.py index dbd8566c517..751a81543e8 100755 --- a/.github/sync_labels.py +++ b/.github/sync_labels.py @@ -609,7 +609,7 @@ def actor_valid(self): for com in coms: for auth in com['authors']: login = auth['login'] - if not login in authors: + if login not in authors: if not self.is_this_bot(login) and login != author: debug('PR %s has recent commit by %s' % (self._issue, login)) authors.append(login) @@ -746,7 +746,7 @@ def add_label(self, label): r""" Add the given label to the issue or PR. """ - if not label in self.get_labels(): + if label not in self.get_labels(): self.edit(label, '--add-label') info('Add label to %s: %s' % (self._issue, label)) diff --git a/src/sage/coding/gabidulin_code.py b/src/sage/coding/gabidulin_code.py index cce8fcfc7d5..3db66e4af7b 100644 --- a/src/sage/coding/gabidulin_code.py +++ b/src/sage/coding/gabidulin_code.py @@ -207,7 +207,7 @@ def __init__(self, base_field, length, dimension, sub_field=None, if not len(evaluation_points) == length: raise ValueError("the number of evaluation points should be equal to the length of the code") for i in range(length): - if not evaluation_points[i] in base_field: + if evaluation_points[i] not in base_field: raise ValueError("evaluation point does not belong to the 'base field'") basis = self.matrix_form_of_vector(vector(evaluation_points)) if basis.rank() != length: diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index f6ffb67d832..c8528c4821f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -590,7 +590,7 @@ def BM_all_minimal(vp, return_transformation=False, D=None): for M in all_M: new_map = mp.conjugate(M) new_map.normalize_coordinates() - if not [new_map, M] in all_maps: + if [new_map, M] not in all_maps: all_maps.append([new_map, M]) #Split into conjugacy classes diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 262c063a35d..a74efd9129a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2935,7 +2935,7 @@ def parallel_function(morphism): # Calling possible_periods for each prime in parallel parallel_data = [] for q in primes(primebound[0], primebound[1] + 1): - if not (q in badprimes): + if q not in badprimes: F = self.change_ring(GF(q)) parallel_data.append(((F,), {})) @@ -6768,7 +6768,7 @@ def is_Lattes(self): (crit_set, post_crit_set) = crit, list(post_crit) # All Lattes maps have 3 or 4 post critical values - if not len(post_crit_set) in [3, 4]: + if len(post_crit_set) not in [3, 4]: return False f = F_crit.dehomogenize(1)[0] @@ -7228,7 +7228,7 @@ def lift_to_rational_periodic(self, points_modp, B=None): while not done and k <= n: newP = self(newP) if newP == P: - if not ([P, k] in good_points): + if [P, k] not in good_points: good_points.append([newP, k]) done = True k += 1 @@ -7499,7 +7499,7 @@ def all_periodic_points(self, **kwds): pos_points = [] # check period, remove duplicates for i in range(len(all_points)): - if all_points[i][1] in periods and not (all_points[i] in pos_points): + if all_points[i][1] in periods and all_points[i] not in pos_points: pos_points.append(all_points[i]) periodic_points = DS.lift_to_rational_periodic(pos_points,B) for p,n in periodic_points: @@ -7594,7 +7594,7 @@ def all_rational_preimages(self, points): P = points.pop() preimages = self.rational_preimages(P) for i in range(len(preimages)): - if not preimages[i] in preperiodic: + if preimages[i] not in preperiodic: points.append(preimages[i]) preperiodic.add(preimages[i]) return list(preperiodic) @@ -9073,7 +9073,7 @@ def is_newton(self, return_conjugation=False): """ if self.degree() == 1: raise NotImplementedError("degree one Newton maps are trivial") - if not self.base_ring() in NumberFields(): + if self.base_ring() not in NumberFields(): raise NotImplementedError("only implemented over number fields") # check if Newton map sigma_1 = self.sigma_invariants(1) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 2eced09d619..1cd132b3a45 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -1228,7 +1228,7 @@ def Bessel(*args, **kwds): _type = kwds['typ'] else: _type = 'J' - if not (_type in ['I', 'J', 'K', 'Y']): + if _type not in ['I', 'J', 'K', 'Y']: raise ValueError("type must be one of I, J, K, Y") # return the function diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index 5d3e2785900..6a8b5e178e5 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -466,15 +466,15 @@ def find_hexad3(self, pts, x0, x1): L = set(pts) H = {x0, x1} for i in range(18): - if (not (MINIMOG[0][2] in H) and L <= picture_set(self.picture21, self.square[i])): + if (MINIMOG[0][2] not in H and L <= picture_set(self.picture21, self.square[i])): WHAT = ["square " + str(i), "picture " + str(MINIMOG[0][2])] H = H | picture_set(self.picture21, self.square[i]) return list(H), WHAT - if (not (MINIMOG[2][1] in H) and L <= picture_set(self.picture02, self.square[i])): + if (MINIMOG[2][1] not in H and L <= picture_set(self.picture02, self.square[i])): WHAT = ["square " + str(i), "picture " + str(MINIMOG[2][1])] H = H | picture_set(self.picture02, self.square[i]) return list(H), WHAT - if (not (MINIMOG[0][0] in H) and L <= picture_set(self.picture00, self.square[i])): + if (MINIMOG[0][0] not in H and L <= picture_set(self.picture00, self.square[i])): WHAT = ["square " + str(i), "picture " + str(MINIMOG[0][0])] H = H | picture_set(self.picture00, self.square[i]) return list(H), WHAT diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index 190bef9982f..7e550bfd472 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -212,14 +212,14 @@ def plot(hyperplane_arrangement, **kwds): if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') - if not type(ranges) in [list,tuple]: # ranges is a single number + if type(ranges) not in [list,tuple]: # ranges is a single number ranges = [ranges] * N # So ranges is some type of list. elif dim == 2: # arrangement of lines in the plane - if not type(ranges[0]) in [list,tuple]: # a single interval + if type(ranges[0]) not in [list,tuple]: # a single interval ranges = [ranges] * N elif dim == 3: # arrangement of planes in 3-space - if not type(ranges[0][0]) in [list,tuple]: + if type(ranges[0][0]) not in [list,tuple]: ranges = [ranges] * N elif dim not in [2,3]: # ranges is not an option unless dim is 2 or 3 ranges_set = False diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index d683955b53a..21a463f1234 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -2452,7 +2452,7 @@ def _test_lawrence(self, tester=None, **options): if tester is None: tester = self._tester(**options) - if self.backend() == 'normaliz' and not self.base_ring() in (ZZ, QQ): + if self.backend() == 'normaliz' and self.base_ring() not in (ZZ, QQ): # Speeds up the doctest for significantly. self = self.change_ring(self._internal_base_ring) diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index ed0c5c82c81..b374392163e 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -1657,7 +1657,7 @@ def RandomDirectedGNM(self, n, m, loops=False): if is_dense: for u in range(n): for v in range(n): - if ((u != v) or loops) and (not (v in adj[u])): + if ((u != v) or loops) and (v not in adj[u]): D.add_edge(u, v) return D diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index f5dbad17169..8cd60e5862e 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1107,7 +1107,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, raise RuntimeError("incorrect hyperoval size") for L in Theta.blocks(): if set(L).issubset(Pi): - if not len(HO.intersection(L)) in [0, 2]: + if len(HO.intersection(L)) not in [0, 2]: raise RuntimeError("incorrect hyperoval") L = [[y for y in z if y not in HO] diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c55dfc08f92..a86e936022e 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -18926,7 +18926,7 @@ def breadth_first_search(self, start, ignore_direction=False, # Non-existing start vertex is detected later if distance > 0. if not distance: for v in queue: - if not v[0] in self: + if v[0] not in self: raise LookupError("start vertex ({0}) is not a vertex of the graph".format(v[0])) for v, d in queue: @@ -22676,7 +22676,7 @@ def graphviz_string(self, **options): for f in edge_option_functions: edge_options.update(f((u, v, label))) - if not edge_options['edge_string'] in ['--', '->']: + if edge_options['edge_string'] not in ['--', '->']: raise ValueError("edge_string(='{}') in edge_options dict for " "the edge ({}, {}) should be '--' or '->'" .format(edge_options['edge_string'], u, v)) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 4606c56b4f9..a008b6f6718 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1170,7 +1170,7 @@ def set_option(self, option_name, option_value=None): raise TypeError('%s option must be a dictionary, not %s' % (name, value)) else: for key, x in value.items(): - if not type(x) in [int, Integer, float, RealLiteral] or not x >= 0.0: + if type(x) not in [int, Integer, float, RealLiteral] or not x >= 0.0: raise ValueError('%s option for %s needs to be a positive number, not %s' % (name, key, x)) elif name in boolean_dicts: if not isinstance(value, dict): diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 2dac79b7146..e9be5ea0b29 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -467,7 +467,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): while i < length: u, v = E[i] Dg.delete_edge(u, v) - if not (v in Dg.depth_first_search(u)): + if v not in Dg.depth_first_search(u): # del E[i] in constant time E[i] = E[-1] E.pop() @@ -478,7 +478,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): else: Dg.add_edge(u, v) Dg.delete_edge(v, u) - if not (u in Dg.depth_first_search(v)): + if u not in Dg.depth_first_search(v): # del E[i] in constant time E[i] = E[-1] E.pop() diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 1e6f85cfae0..499b2565236 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -1657,7 +1657,7 @@ def sr_to_max(expr): return EclObject(special_sage_to_max[op](*[sr_to_max(o) for o in expr.operands()])) elif op == tuple: return EclObject(([mlist], list(sr_to_max(op) for op in expr.operands()))) - elif not (op in sage_op_dict): + elif op not in sage_op_dict: # Maxima does some simplifications automatically by default # so calling maxima(expr) can change the structure of expr # op_max=caar(maxima(expr).ecl()) diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 6001f7abeff..235ba1fddef 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -2658,7 +2658,7 @@ def __getitem__(self, item): [, , ] """ from sage.rings.integer import Integer - if not type(item) in (int, Integer): + if type(item) not in (int, Integer): raise ValueError('item must be an integer') l = self.list() max_item = len(l) @@ -2701,7 +2701,7 @@ def __call__(self, item): return self[item] from sage.rings.integer import Integer - if not type(item) in (int, Integer): + if type(item) not in (int, Integer): raise ValueError('item must be an integer') l = self.list() max_item = len(l) + 1 diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index dbaca5662c8..fdcc9fc00ab 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -1201,7 +1201,7 @@ def _khovanov_homology_cached(self, height, ring=ZZ): else: m = matrix(ring, len(bases[(i,j)]), 0) complexes[i] = m.transpose() - if not (i-1, j) in bases: + if (i-1, j) not in bases: complexes[i-1] = matrix(ring, len(bases[(i,j)]), 0) homologies = ChainComplex(complexes).homology() return tuple(sorted(homologies.items())) @@ -2313,7 +2313,7 @@ def seifert_circles(self): while a not in par: par.append(a) posnext = C[(C.index(a) - 1) % 4] - if tails[posnext] == C and not [posnext] in result: + if tails[posnext] == C and [posnext] not in result: a = posnext else: a = C[(C.index(a) + 1) % 4] diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index 3971a85c776..f50ae75f553 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -689,7 +689,7 @@ def __eq__(self, other): diff = xs - xo period = periods[ind] if period is not None: - if not (diff/period in ZZ): + if diff/period not in ZZ: return False else: if isinstance(diff, Expression) and not diff.is_trivial_zero(): diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 62b5c98f90b..0227fa8319a 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -509,12 +509,12 @@ def is_2_adic_genus(genus_symbol_quintuple_list) -> bool: return False if s[1] == 2 and s[3] == 1: if s[2] % 8 in (1, 7): - if not s[4] in (0, 2, 6): + if s[4] not in (0, 2, 6): return False if s[2] % 8 in (3, 5): - if not s[4] in (2, 4, 6): + if s[4] not in (2, 4, 6): return False - if (s[1] - s[4]) % 2 == 1: + if (s[1] - s[4]) % 2: return False if s[3] == 0 and s[4] != 0: return False @@ -2802,7 +2802,8 @@ def direct_sum(self, other): signature_pair = (p1 + p2, n1 + n2) primes = [s.prime() for s in self.local_symbols()] - primes += [s.prime() for s in other.local_symbols() if not s.prime() in primes] + primes.extend(s.prime() for s in other.local_symbols() + if s.prime() not in primes) primes.sort() local_symbols = [] for p in primes: diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index 473e860ba42..31bc1db3ffd 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -634,10 +634,10 @@ def _rich_output_formatter(self, obj, rich_repr_kwds): rich_output = self._promote_output(rich_output) # check that the output container types are valid for the backend supported = self._backend.supported_output() - if not (type(plain_text) in supported): + if type(plain_text) not in supported: raise OutputTypeException( 'text output container not supported: {0}'.format(type(plain_text))) - if not (type(rich_output) in supported): + if type(rich_output) not in supported: raise OutputTypeException( 'output container not supported: {0}'.format(type(rich_output))) return plain_text, rich_output diff --git a/src/sage/rings/function_field/order_basis.py b/src/sage/rings/function_field/order_basis.py index e4fa3dfe39e..1cf89e3f966 100644 --- a/src/sage/rings/function_field/order_basis.py +++ b/src/sage/rings/function_field/order_basis.py @@ -102,7 +102,7 @@ def __init__(self, basis, check=True): if check: if self._module.rank() != field.degree(): raise ValueError("basis {} is not linearly independent".format(basis)) - if not to_V(field(1)) in self._module: + if to_V(field(1)) not in self._module: raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) if not all(to_V(a*b) in self._module for a in basis for b in basis): raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) @@ -399,7 +399,7 @@ def __init__(self, basis, check=True): if check: if self._module.rank() != field.degree(): raise ValueError("basis {} is not linearly independent".format(basis)) - if not W.coordinate_vector(to(field(1))) in self._module: + if W.coordinate_vector(to(field(1))) not in self._module: raise ValueError("the identity element must be in the module spanned by basis {}".format(basis)) if not all(W.coordinate_vector(to(a*b)) in self._module for a in basis for b in basis): raise ValueError("the module generated by basis {} must be closed under multiplication".format(basis)) @@ -431,7 +431,7 @@ def _element_constructor_(self, f): V, fr_V, to_V = F.vector_space() W = self._ambient_space - if not W.coordinate_vector(to_V(f)) in self._module: + if W.coordinate_vector(to_V(f)) not in self._module: raise TypeError("{} is not an element of {}".format(f, self)) return f diff --git a/src/sage/rings/function_field/order_polymod.py b/src/sage/rings/function_field/order_polymod.py index 2ebb062a432..16ff2d8f2ae 100644 --- a/src/sage/rings/function_field/order_polymod.py +++ b/src/sage/rings/function_field/order_polymod.py @@ -888,7 +888,7 @@ def ideal(self, *gens): """ if len(gens) == 1: gens = gens[0] - if not type(gens) in (list,tuple): + if type(gens) not in (list,tuple): gens = (gens,) mgens = [g * b for g in gens for b in self._basis] return self.ideal_with_gens_over_base(mgens) diff --git a/src/sage/rings/function_field/order_rational.py b/src/sage/rings/function_field/order_rational.py index 87cbbdb4858..d90124c6800 100644 --- a/src/sage/rings/function_field/order_rational.py +++ b/src/sage/rings/function_field/order_rational.py @@ -83,7 +83,7 @@ def _element_constructor_(self, f): except TypeError: raise TypeError("unable to convert to an element of {}".format(F)) - if not f.denominator() in self.function_field().constant_base_field(): + if f.denominator() not in self.function_field().constant_base_field(): raise TypeError("%r is not an element of %r" % (f,self)) return f diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index d62ae34fb95..3686840ccba 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -2161,7 +2161,7 @@ def reduce(self, f): R = self.number_field().maximal_order() - if not (f in R): + if f not in R: raise TypeError("reduce only defined for integral elements") Rbasis = R.basis() diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index e54d2f454af..55db3bbbcbf 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -894,7 +894,7 @@ def ring_generators(self): gens.append(g) n.append(g.absolute_minpoly().degree()) W = A.span([to_V(x) for x in monomials(gens, n)]) - remaining = [x for x in remaining if not to_V(x) in W] + remaining = [x for x in remaining if to_V(x) not in W] return Sequence(gens, immutable=True) @cached_method @@ -1590,7 +1590,7 @@ def _element_constructor_(self, x): if not isinstance(x, Element) or x.parent() is not self._K: x = self._K(x) V, _, embedding = self._K.vector_space() - if not embedding(x) in self._module_rep: + if embedding(x) not in self._module_rep: raise TypeError("Not an element of the order.") return self._element_type(self, x) diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index 61459d8d50d..b8f2b62d5a7 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -124,7 +124,7 @@ def __pow__(self, other): sage: a^2 9 """ - if not (other in PariRing()): + if other not in PariRing(): other = Pari(other) return self.__class__(self.__x ** other.__x, parent=_inst) diff --git a/src/sage/rings/polynomial/pbori/ll.py b/src/sage/rings/polynomial/pbori/ll.py index 5292050d6a7..9ec3a57bb4c 100644 --- a/src/sage/rings/polynomial/pbori/ll.py +++ b/src/sage/rings/polynomial/pbori/ll.py @@ -79,7 +79,7 @@ def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None, lm = p.lex_lead() if lm.deg() == 1: - if not (lm in linear_leading_monomials): + if lm not in linear_leading_monomials: linear_leading_monomials.add(lm) linear_leads.append(p) else: diff --git a/src/sage/rings/valuation/augmented_valuation.py b/src/sage/rings/valuation/augmented_valuation.py index ff35d1166e9..b9f0229f787 100644 --- a/src/sage/rings/valuation/augmented_valuation.py +++ b/src/sage/rings/valuation/augmented_valuation.py @@ -1390,7 +1390,7 @@ def lift(self, F, report_coefficients=False): F = self.residue_ring().coerce(F) from sage.categories.fields import Fields - if not self.domain().base_ring() in Fields(): + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") if F.is_constant(): @@ -1481,7 +1481,7 @@ def lift_to_key(self, F, check=True): F = self.residue_ring().coerce(F) from sage.categories.fields import Fields - if not self.domain().base_ring() in Fields(): + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") if check: diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index 9646cf5e429..470e4990bed 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -1375,7 +1375,7 @@ def minimal_representative(self, f): f = self.domain().coerce(f) from sage.categories.fields import Fields - if not self.domain().base_ring() in Fields(): + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") if f.is_zero(): diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index d98209bdba1..0b647c8411b 100755 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -579,7 +579,7 @@ def multiplicity(self, P): TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over Rational Field defined by x^6 - x^3 + y^3) """ - if not self.base_ring() in Fields(): + if self.base_ring() not in Fields(): raise TypeError("curve must be defined over a field") # Check whether P is a point on this curve @@ -866,7 +866,7 @@ def __init__(self, A, X): """ super().__init__(A, X) - if not A.base_ring() in Fields(): + if A.base_ring() not in Fields(): raise TypeError("curve not defined over a field") d = super(Curve_generic, self).dimension() @@ -1320,7 +1320,7 @@ def blowup(self, P=None): self(P) except TypeError: raise TypeError("(=%s) must be a point on this curve" % P) - if not self.base_ring() in Fields(): + if self.base_ring() not in Fields(): raise TypeError("the base ring of this curve must be a field") if not self.is_irreducible(): raise TypeError("this curve must be irreducible") diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 7c8cf62c5ea..b21b6bbed91 100755 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1466,7 +1466,7 @@ def extension(self): # make sure the defining polynomial variable names are the same for K, N N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen())) return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0] - if not self.base_ring() in NumberFields(): + if self.base_ring() not in NumberFields(): raise NotImplementedError("the base ring of this curve must be a number field") if not self.is_irreducible(): raise TypeError("this curve must be irreducible") @@ -1499,7 +1499,7 @@ def extension(self): try: temp_pt = (temp_qua*temp_exc)(temp_exc.domain()(pts[i])) pts.pop(i) - if not PP(list(temp_pt)) in [PP(list(tpt)) for tpt in pts]: + if PP(list(temp_pt)) not in [PP(list(tpt)) for tpt in pts]: pts.append(temp_pt) except (TypeError, ValueError): pass @@ -1519,7 +1519,7 @@ def extension(self): newpts = [PP(list(pt) + [0]) for pt in X.rational_points()] # avoid duplicates for pt in newpts: - if not PP(list(pt)) in [PP(list(tpt)) for tpt in pts]: + if PP(list(pt)) not in [PP(list(tpt)) for tpt in pts]: pts.append(pt) return phi @@ -1604,7 +1604,7 @@ def __init__(self, A, X, category=None): """ super().__init__(A, X, category=category) - if not A.base_ring() in Fields(): + if A.base_ring() not in Fields(): raise TypeError("curve not defined over a field") d = super(Curve_generic, self).dimension() @@ -2296,7 +2296,7 @@ def __init__(self, A, f): ideal = self.defining_ideal() gs = self.ambient_space().gens() for i in range(self.ngens()): - if not gs[i] in ideal: + if gs[i] not in ideal: self._open_affine = self.affine_patch(i) self._open_affine_index = i break @@ -2733,7 +2733,7 @@ def places_on(self, point): # determine the affine patch where the point lies S = prime.ring() for i in range(S.ngens()): - if not S.gen(i) in prime: + if S.gen(i) not in prime: break phi = self._map_to_function_field diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 925d1d9f2d0..f410a73f8fc 100755 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -732,7 +732,7 @@ def roots_interval(f, x0): diam = min((CF(r) - CF(r0)).abs() for r0 in roots[:i] + roots[i + 1:]) / divisor envelop = IF(diam) * IF((-1, 1), (-1, 1)) - while not newton(fx, r, r + envelop) in r + envelop: + while newton(fx, r, r + envelop) not in r + envelop: prec += 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) @@ -1302,7 +1302,7 @@ def braid_monodromy(f, arrangement=(), vertical=False): g = f.parent()(prod(glist)) d = g.degree(y) if not arrangement_v: # change of coordinates only if indices_v is empty - while not g.coefficient(y**d) in F: + while g.coefficient(y**d) not in F: g = g.subs({x: x + y}) d = g.degree(y) arrangement_h = tuple(f1.subs({x: x + y}) for f1 in arrangement_h) @@ -1752,7 +1752,7 @@ def fundamental_group(f, simplified=True, projective=False, puiseux=True): x, y = g.parent().gens() F = g.parent().base_ring() d = g.degree(y) - while not g.coefficient(y**d) in F: + while g.coefficient(y**d) not in F: g = g.subs({x: x + y}) d = g.degree(y) if projective: diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index a8678861b91..3a7b7f553a6 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -213,11 +213,11 @@ def unify_arguments(self, x): temp = set() # Sorting remaining variables. for j in range(i, len(a)): - if not a[j] in temp: + if a[j] not in temp: temp.add(a[j]) for j in range(i, len(b)): - if not b[j] in temp: + if b[j] not in temp: temp.add(b[j]) new_list.extend(sorted(temp, key=repr)) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 241b56a0ff6..54166cf4f1f 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -3707,7 +3707,7 @@ def stellar_subdivision(self, simplex, inplace=False, is_mutable=True): if inplace and self._is_immutable: raise ValueError("this simplicial complex is not mutable") - if not Simplex(simplex) in self: + if Simplex(simplex) not in self: raise ValueError("the face to subdivide is not a face of self") if inplace: From 181e9603a39a3cb0202c53b805c09cd70368b4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Oct 2024 20:08:41 +0200 Subject: [PATCH 098/108] activate ruff check for E713 --- src/tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tox.ini b/src/tox.ini index 094c1f54806..c76a8b65c2d 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -291,7 +291,6 @@ passenv = RUFF_OUTPUT_FORMAT # 116 PLR0402 [*] Use `from matplotlib import cm` in lieu of alias # 111 PLW0603 [ ] Using the global statement to update `AA_0` is discouraged # 78 F841 [*] Local variable `B` is assigned to but never used -# 64 E713 [*] Test for membership should be `not in` # 48 PLW0602 [ ] Using global for `D` but no assignment is done # 33 PLR1711 [*] Useless `return` statement at end of function # 24 E714 [*] Test for object identity should be `is not` @@ -315,7 +314,7 @@ passenv = RUFF_OUTPUT_FORMAT # 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable # 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values # -commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,E713,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} [flake8] rst-roles = From 86aa87109d3bc798b1b5b6b0ab9197075214cb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 9 Oct 2024 11:59:04 +0200 Subject: [PATCH 099/108] avoid some type comparisons in combinat --- src/sage/combinat/cluster_algebra_quiver/quiver.py | 12 +++++++++--- .../cluster_algebra_quiver/quiver_mutation_type.py | 4 +++- src/sage/combinat/core.py | 12 ++++++------ .../root_system/integrable_representations.py | 2 +- src/sage/combinat/shard_order.py | 2 +- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 93cdfef5c8a..7e07835b935 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -232,7 +232,8 @@ def __init__(self, data, frozen=None, user_labels=None): values)) # constructs a quiver from a mutation type - if type( data ) in [QuiverMutationType_Irreducible,QuiverMutationType_Reducible]: + if isinstance(data, (QuiverMutationType_Irreducible, + QuiverMutationType_Reducible)): if frozen is not None: print('The input specifies a mutation type, so the' ' additional parameter frozen is ignored.' @@ -1950,10 +1951,15 @@ def is_mutation_finite( self, nr_of_checks=None, return_path=False ): path = None elif not return_path and self._mutation_type == 'undetermined infinite mutation type': is_finite = False - elif type( self._mutation_type ) in [QuiverMutationType_Irreducible, QuiverMutationType_Reducible] and self._mutation_type.is_mutation_finite(): + elif (isinstance(self._mutation_type, (QuiverMutationType_Irreducible, + QuiverMutationType_Reducible)) + and self._mutation_type.is_mutation_finite()): is_finite = True path = None - elif not return_path and type( self._mutation_type ) in [QuiverMutationType_Irreducible, QuiverMutationType_Reducible] and not self._mutation_type.is_mutation_finite(): + elif (not return_path and isinstance(self._mutation_type, + (QuiverMutationType_Irreducible, + QuiverMutationType_Reducible)) + and not self._mutation_type.is_mutation_finite()): is_finite = False else: # turning dg_component into a canonical form diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index 25610dff117..c9f06a4761f 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -67,7 +67,9 @@ def __call__(self, *args): _mutation_type_error(data) # check for reducible types - if all(type(data_component) in [list, tuple, QuiverMutationType_Irreducible] for data_component in data): + if all(isinstance(data_component, (list, tuple, + QuiverMutationType_Irreducible)) + for data_component in data): if len(data) == 1: return QuiverMutationType(data[0]) else: diff --git a/src/sage/combinat/core.py b/src/sage/combinat/core.py index d6775040c48..21ce49f57f1 100644 --- a/src/sage/combinat/core.py +++ b/src/sage/combinat/core.py @@ -102,7 +102,7 @@ def __init__(self, parent, core): raise ValueError("%s is not a %s-core" % (part, k)) CombinatorialElement.__init__(self, parent, core) - def __eq__(self, other): + def __eq__(self, other) -> bool: """ Test for equality. @@ -123,7 +123,7 @@ def __eq__(self, other): self.parent().k == other.parent().k) return False - def __ne__(self, other): + def __ne__(self, other) -> bool: """ Test for un-equality. @@ -169,7 +169,7 @@ def __hash__(self): self._hash = hash(tuple(self._list)) + hash(self.parent().k) return self._hash - def _latex_(self): + def _latex_(self) -> str: r""" Output the LaTeX representation of this core as a partition. @@ -449,7 +449,7 @@ def weak_le(self, other): ... ValueError: the two cores do not have the same k """ - if type(self) is type(other): + if isinstance(other, Core): if self.k() != other.k(): raise ValueError("the two cores do not have the same k") else: @@ -504,14 +504,14 @@ def strong_le(self, other): ... ValueError: the two cores do not have the same k """ - if type(self) is type(other): + if isinstance(other, Core): if self.k() != other.k(): raise ValueError("the two cores do not have the same k") else: other = Core(other, self.k()) return other.contains(self) - def contains(self, other): + def contains(self, other) -> bool: r""" Check whether ``self`` contains ``other``. diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index b7d4b163242..0cda82af318 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -1046,7 +1046,7 @@ def modular_characteristic(self, mu=None): sage: [V.modular_characteristic(x) for x in V.dominant_maximal_weights()] [11/56, -1/280, 111/280] """ - if type(mu) is tuple: + if isinstance(mu, tuple): n = mu else: n = self.from_weight(mu) diff --git a/src/sage/combinat/shard_order.py b/src/sage/combinat/shard_order.py index 4bcc75d0871..f9081ef77dc 100644 --- a/src/sage/combinat/shard_order.py +++ b/src/sage/combinat/shard_order.py @@ -127,7 +127,7 @@ def __le__(self, other): sage: e1 <= e0 False """ - if type(self) is not type(other) or len(self) != len(other): + if not isinstance(other, ShardPosetElement) or len(self) != len(other): raise TypeError("these are not comparable") if self.runs == other.runs: return True From bf79d5c14fcd56acd189716a4cb71c708353be19 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 9 Oct 2024 16:38:23 +0200 Subject: [PATCH 100/108] fix docstring, fix whitespace around = and , --- src/sage/modular/arithgroup/farey_symbol.pyx | 57 ++++++++++---------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index bb48288eec2..c965015b41d 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -279,7 +279,7 @@ cdef class Farey: [ -3 1] [-40 13] """ - gens_dict = {g:i+1 for i,g in enumerate(self.generators())} + gens_dict = {g: i+1 for i, g in enumerate(self.generators())} ans = [] for pm in self.pairing_matrices(): a, b, c, d = pm.matrix().list() @@ -331,7 +331,7 @@ cdef class Farey: sage: (-g.matrix()).is_one() True """ - for i,g in enumerate(self.generators()): + for i, g in enumerate(self.generators()): m = g.matrix() if (-m).is_one(): return [i + 1] @@ -342,15 +342,17 @@ cdef class Farey: return 3 * [i + 1] return [] - def word_problem(self, M, output = 'standard', check = True): + def word_problem(self, M, output='standard', check=True): r""" Solve the word problem (up to sign) using this Farey symbol. INPUT: - ``M`` -- an element `M` of `\SL_2(\ZZ)` - - ``output`` -- (default: ``'standard'``) should be one of ``'standard'``, - ``'syllables'``, ``'gens'``. + + - ``output`` -- (default: ``'standard'``) should be one of + ``'standard'``, ``'syllables'``, ``'gens'``. + - ``check`` -- boolean (default: ``True``); whether to check for correct input and output @@ -359,17 +361,17 @@ cdef class Farey: A solution to the word problem for the matrix `M`. The format depends on the ``output`` parameter, as follows. - - ``standard`` returns the so called the Tietze representation, - consists of a tuple of nonzero integers `i`, where if `i` > 0 - then it indicates the `i`-th generator (that is, ``self.generators()[0]`` - would correspond to `i` = 1), and if `i` < 0 then it indicates - the inverse of the `i`-th generator. - - ``syllables`` returns a tuple of tuples of the form `(i,n)`, where - `(i,n)` represents ``self.generators()[i] ^ n``, + - ``'standard'`` returns the so called Tietze representation, + which consists of a tuple of nonzero integers. A positive + integer `i` indicates the `i`-th generator (that is, + ``self.generators()[i-1]``), while a negative integer `i` + indicates the inverse of the `i`-th generator. + - ``'syllables'`` returns a tuple of tuples of the form + `(i, n)`, where `(i, n)` represents ``self.generators()[i] ^ n``, whose product equals `M` up to sign. - - ``gens`` returns tuple of tuples of the form `(g,n)`, - `(g,n)` such that the product of the matrices `g^n` - equals `M` up to sign. + - ``'gens'`` returns a tuple of pairs `(g, n)`, where `g` is a + matrix and `n` an integer, such that the product of the + matrices `g^n` equals `M` up to sign. EXAMPLES:: @@ -385,7 +387,7 @@ cdef class Farey: sage: g [-5048053 586303] [-5558280 645563] - sage: F.word_problem(g, output = 'gens') + sage: F.word_problem(g, output='gens') (( [109 -10] [120 -11], 1 @@ -402,7 +404,7 @@ cdef class Farey: [17 -2] [60 -7], 1 )) - sage: F.word_problem(g, output = 'syllables') + sage: F.word_problem(g, output='syllables') ((3, 1), (10, 2), (8, -1), (5, 1)) TESTS: @@ -413,7 +415,7 @@ cdef class Farey: sage: G = Gamma0(10) sage: F = G.farey_symbol() sage: g = G([-701,-137,4600,899]) - sage: g1 = prod(F.generators()[i]**a for i,a in F.word_problem(g, output = 'syllables')) + sage: g1 = prod(F.generators()[i]**a for i, a in F.word_problem(g, output='syllables')) sage: g == g1 True @@ -426,15 +428,16 @@ cdef class Farey: Check that :issue:`20347` is solved:: sage: from sage.misc.misc_c import prod - sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)",S3="(1,2,3)") + sage: G = ArithmeticSubgroup_Permutation(S2="(1,2)(3,4)", S3="(1,2,3)") sage: S = G.farey_symbol() - sage: g1,g2 = S.generators() + sage: g1, g2 = S.generators() sage: g = g1^3 * g2^-2 * g1 * g2 sage: S.word_problem(g) (2, 2, 2, 1, 1, 1, 2, 1, 2) - sage: h = prod(S.generators()[i]**a for i,a in S.word_problem(g, output = 'syllables')) + sage: h = prod(S.generators()[i]**a for i, a in S.word_problem(g, output='syllables')) sage: g == h True + """ if output not in ['standard', 'syllables', 'gens']: raise ValueError('Unrecognized output format') @@ -464,7 +467,7 @@ cdef class Farey: if sgn == -1: beta, mbeta = mbeta, beta - gens_dict = {g:i+1 for i,g in enumerate(self.generators())} + gens_dict = {g: i+1 for i, g in enumerate(self.generators())} extra_tietze = [] if beta.is_one(): found = True @@ -501,13 +504,13 @@ cdef class Farey: for i in range(len(tietze)): t = tietze[i] tmp = tmp * gens[t-1] if t > 0 else tmp * gens[-t-1]**-1 - assert tmp.matrix() == M.matrix(),'%s %s %s' % (tietze, tmp.matrix(),M.matrix()) + assert tmp.matrix() == M.matrix(), '%s %s %s' % (tietze, tmp.matrix(), M.matrix()) if output == 'standard': return tuple(tietze) if output == 'syllables': - return tuple((a-1,len(list(g))) if a > 0 else (-a-1,-len(list(g))) for a,g in groupby(tietze)) + return tuple((a-1, len(list(g))) if a > 0 else (-a-1, -len(list(g))) for a, g in groupby(tietze)) else: # output == 'gens' - return tuple((gens[a-1],len(list(g))) if a > 0 else (gens[-a-1],-len(list(g))) for a, g in groupby(tietze)) + return tuple((gens[a-1], len(list(g))) if a > 0 else (gens[-a-1], -len(list(g))) for a, g in groupby(tietze)) def __contains__(self, M): r""" @@ -594,9 +597,9 @@ cdef class Farey: EXAMPLES:: - sage: FareySymbol(Gamma0(11))._latex_(forced_format = 'plain') + sage: FareySymbol(Gamma0(11))._latex_(forced_format='plain') '\\left( -\\infty\\underbrace{\\quad}_{1} 0\\underbrace{\\quad}_{2} \\frac{1}{3}\\underbrace{\\quad}_{3} \\frac{1}{2}\\underbrace{\\quad}_{2} \\frac{2}{3}\\underbrace{\\quad}_{3} 1\\underbrace{\\quad}_{1} \\infty\\right)' - sage: FareySymbol(Gamma0(11))._latex_(forced_format = 'xymatrix') + sage: FareySymbol(Gamma0(11))._latex_(forced_format='xymatrix') '\\begin{xy}\\xymatrix{& -\\infty \\ar@{-}@/_1pc/[r]_{1}& 0 \\ar@{-}@/_1pc/[r]_{2}& \\frac{1}{3} \\ar@{-}@/_1pc/[r]_{3}& \\frac{1}{2} \\ar@{-}@/_1pc/[r]_{2}& \\frac{2}{3} \\ar@{-}@/_1pc/[r]_{3}& 1 \\ar@{-}@/_1pc/[r]_{1}& \\infty }\\end{xy}' sage: 'xymatrix' in FareySymbol(Gamma0(11))._latex_() From 81bbadfe494a786a03abe219a0658063827757b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 09:21:33 +0200 Subject: [PATCH 101/108] switch to nauty for generating posets --- src/sage/combinat/posets/posets.py | 10 +++++----- src/sage/combinat/tutorial.py | 8 ++++---- src/sage/databases/findstat.py | 9 +++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 6471163fe00..5822d6af366 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -8884,11 +8884,11 @@ class FinitePosets_n(UniqueRepresentation, Parent): sage: P.cardinality() 5 sage: for p in P: print(p.cover_relations()) - [] - [[1, 2]] + [[1, 2], [0, 2]] [[0, 1], [0, 2]] + [[0, 2]] [[0, 1], [1, 2]] - [[1, 2], [0, 2]] + [] """ def __init__(self, n) -> None: @@ -8945,8 +8945,8 @@ def __iter__(self): sage: list(P) [Finite poset containing 2 elements, Finite poset containing 2 elements] """ - from sage.graphs.digraph_generators import DiGraphGenerators - for dig in DiGraphGenerators()(self._n, is_poset): + from sage.graphs.digraph_generators import DiGraphGenerators as DG + for dig in DG().nauty_posetg(f"{self._n} o"): # We need to relabel the digraph since range(self._n) must be a linear # extension. Too bad we need to compute this again. TODO: Fix this. label_dict = dict(zip(dig.topological_sort(), range(dig.order()))) diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 1b8555f4565..ef77bf66d4e 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -844,15 +844,15 @@ Partial orders on a set of `8` elements, up to isomorphism:: - sage: C = Posets(8); C - Posets containing 8 elements + sage: C = Posets(7); C + Posets containing 7 elements sage: C.cardinality() - 16999 + 2045 :: sage: C.unrank(20).plot() - Graphics object consisting of 20 graphics primitives + Graphics object consisting of ... graphics primitives .. image:: ../../media/a_poset.png diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 89cd74f457e..852c258a4ac 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4002,16 +4002,17 @@ def _finite_lattices(n): TESTS:: sage: from sage.databases.findstat import _finite_lattices - sage: [L.cover_relations() for L in _finite_lattices(4)] - [[['bottom', 0], ['bottom', 1], [0, 'top'], [1, 'top']], - [['bottom', 0], [0, 1], [1, 'top']]] + sage: sorted((L.cover_relations() for L in _finite_lattices(4)), + ....: key=len) + [[['bottom', 0], [0, 1], [1, 'top']], + [['bottom', 0], ['bottom', 1], [0, 'top'], [1, 'top']]] """ if n <= 2: for P in Posets(n): if P.is_lattice(): yield LatticePoset(P) else: - for P in Posets(n-2): + for P in Posets(n - 2): Q = P.with_bounds() if Q.is_lattice(): yield LatticePoset(Q) From bb3749de0179383b816ae4c6d76d6bce123abfef Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 10 Oct 2024 09:43:06 +0200 Subject: [PATCH 102/108] more tests --- src/sage/graphs/orientations.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 038ee1ebe81..2d0a74f1eb5 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -150,6 +150,15 @@ def orient(G, f, weighted=None, data_structure=None, sparse=None, sage: G.orient(foo, immutable=False, sparse=False)._backend + sage: G.orient(foo, data_structure=None, immutable=None, sparse=True)._backend + + sage: G.orient(foo, data_structure=None, immutable=None, sparse=False)._backend + + sage: G.orient(foo, data_structure=None, immutable=None, sparse=None)._backend + + sage: H = Graph(data_structure='dense') + sage: H.orient(foo, data_structure=None, immutable=None, sparse=None)._backend + """ # Which data structure should be used ? if data_structure is not None: From c66f999722c4307dc42f042920ebe9ce952a3908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 10:15:16 +0200 Subject: [PATCH 103/108] fix for linter --- src/sage/databases/findstat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 852c258a4ac..c3a886645ac 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4005,7 +4005,7 @@ def _finite_lattices(n): sage: sorted((L.cover_relations() for L in _finite_lattices(4)), ....: key=len) [[['bottom', 0], [0, 1], [1, 'top']], - [['bottom', 0], ['bottom', 1], [0, 'top'], [1, 'top']]] + [['bottom', 0], ['bottom', 1], [0, 'top'], [1, 'top']]] """ if n <= 2: for P in Posets(n): From 1e9209ace2e7aff49e6fa5ac416922e5196e7234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 13:17:09 +0200 Subject: [PATCH 104/108] details --- src/sage/combinat/posets/posets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 5822d6af366..aa0ee7f249f 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -8936,7 +8936,7 @@ def __iter__(self): .. NOTE:: - This uses the DiGraph iterator as a backend to construct + This uses an iterator from ``nauty`` as a backend to construct transitively-reduced, acyclic digraphs. EXAMPLES:: @@ -8945,8 +8945,8 @@ def __iter__(self): sage: list(P) [Finite poset containing 2 elements, Finite poset containing 2 elements] """ - from sage.graphs.digraph_generators import DiGraphGenerators as DG - for dig in DG().nauty_posetg(f"{self._n} o"): + from sage.graphs.digraph_generators import DiGraphGenerators + for dig in DiGraphGenerators().nauty_posetg(f"{self._n} o"): # We need to relabel the digraph since range(self._n) must be a linear # extension. Too bad we need to compute this again. TODO: Fix this. label_dict = dict(zip(dig.topological_sort(), range(dig.order()))) From 8b55fc3f8dc08ea09261024bd4531df68176149d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 13:18:56 +0200 Subject: [PATCH 105/108] move import --- src/sage/combinat/posets/posets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index aa0ee7f249f..9e2e1250e76 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -8945,8 +8945,7 @@ def __iter__(self): sage: list(P) [Finite poset containing 2 elements, Finite poset containing 2 elements] """ - from sage.graphs.digraph_generators import DiGraphGenerators - for dig in DiGraphGenerators().nauty_posetg(f"{self._n} o"): + for dig in digraphs.nauty_posetg(f"{self._n} o"): # We need to relabel the digraph since range(self._n) must be a linear # extension. Too bad we need to compute this again. TODO: Fix this. label_dict = dict(zip(dig.topological_sort(), range(dig.order()))) From 93c0c8b3b39b993508ab2283f597331580dc27ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 15:37:02 +0200 Subject: [PATCH 106/108] add switch for n > 16 --- src/sage/combinat/posets/posets.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 9e2e1250e76..8a85febf4c8 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -8930,22 +8930,35 @@ def __contains__(self, P) -> bool: return P in FinitePosets() and P.cardinality() == self._n def __iter__(self): - """ + r""" Return an iterator of representatives of the isomorphism classes of finite posets of a given size. .. NOTE:: - This uses an iterator from ``nauty`` as a backend to construct - transitively-reduced, acyclic digraphs. + If the size `n\leq 16`, this uses an iterator from + ``nauty`` as a backend to construct only transitively-reduced, + acyclic digraphs. Otherwise it uses a slow naive iterator, + as the ``nauty`` iterator is not available. EXAMPLES:: sage: P = Posets(2) sage: list(P) [Finite poset containing 2 elements, Finite poset containing 2 elements] + + TESTS:: + + sage: it = iter(Posets(17)) + sage: next(it) + Finite poset containing 17 elements """ - for dig in digraphs.nauty_posetg(f"{self._n} o"): + if self._n <= 16: + it = digraphs.nauty_posetg(f"{self._n} o") + else: + it = digraphs(self._n, is_poset) + + for dig in it: # We need to relabel the digraph since range(self._n) must be a linear # extension. Too bad we need to compute this again. TODO: Fix this. label_dict = dict(zip(dig.topological_sort(), range(dig.order()))) From 17f72fa4080c60a8a2d772ec4c21fd928c7471ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 10 Oct 2024 17:43:44 +0200 Subject: [PATCH 107/108] avoid copy of graph --- src/sage/combinat/posets/posets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 8a85febf4c8..e565eb3d2ee 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -8961,8 +8961,9 @@ def __iter__(self): for dig in it: # We need to relabel the digraph since range(self._n) must be a linear # extension. Too bad we need to compute this again. TODO: Fix this. - label_dict = dict(zip(dig.topological_sort(), range(dig.order()))) - yield FinitePoset(dig.relabel(label_dict, inplace=False)) + label_dict = dict(zip(dig.topological_sort(), range(self._n))) + dig.relabel(label_dict, inplace=True) + yield FinitePoset(dig) def cardinality(self, from_iterator=False): r""" From 7726cd9e1d01ad32b0f14374c9a4096989c87e14 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sat, 12 Oct 2024 11:15:20 +0200 Subject: [PATCH 108/108] Updated SageMath version to 10.5.beta7 --- CITATION.cff | 4 ++-- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 4 ++-- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/version_requirements.txt | 2 +- build/pkgs/sage_docbuild/version_requirements.txt | 2 +- build/pkgs/sage_setup/version_requirements.txt | 2 +- build/pkgs/sage_sws2rst/version_requirements.txt | 2 +- build/pkgs/sagelib/version_requirements.txt | 2 +- build/pkgs/sagemath_bliss/version_requirements.txt | 2 +- build/pkgs/sagemath_categories/version_requirements.txt | 2 +- build/pkgs/sagemath_coxeter3/version_requirements.txt | 2 +- build/pkgs/sagemath_environment/version_requirements.txt | 2 +- build/pkgs/sagemath_mcqd/version_requirements.txt | 2 +- build/pkgs/sagemath_meataxe/version_requirements.txt | 2 +- build/pkgs/sagemath_objects/version_requirements.txt | 2 +- build/pkgs/sagemath_repl/version_requirements.txt | 2 +- build/pkgs/sagemath_sirocco/version_requirements.txt | 2 +- build/pkgs/sagemath_tdlib/version_requirements.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_conda/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-bliss/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-coxeter3/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-mcqd/VERSION.txt | 2 +- pkgs/sagemath-meataxe/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- pkgs/sagemath-sirocco/VERSION.txt | 2 +- pkgs/sagemath-tdlib/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 38 files changed, 44 insertions(+), 44 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index b74bd3b74a2..8982711590a 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.5.beta6 +version: 10.5.beta7 doi: 10.5281/zenodo.8042260 -date-released: 2024-09-29 +date-released: 2024-10-12 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index b250e9488be..ff5659834ae 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.5.beta6, Release Date: 2024-09-29 +SageMath version 10.5.beta7, Release Date: 2024-10-12 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 3e363aa3fb3..daf9720f908 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=2b8c8181575563ae16afca012c2188b31f3e8bb7 -sha256=77d20639b03b1c125d6ccf88ebb2cb0202b32059dff4bf38ca05db229913f639 +sha1=978eb775a20fea3ed9b88f0d67ecd84a3d9cd6ea +sha256=c3987bb0f8aca81e112a17d8904ef2353a706159d43250305dc2bcac4ca2e33a diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 29095152c52..009fd772239 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -a1d9c1e13576bf777e95ba50d51d81ee09d2a0c9 +4326d0d9422011034a230ab3c1445fafeb2ac444 diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index e8756c3ed2e..d44223c9381 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.5b6 +sage-conf ~= 10.5b7 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index 0d48260c2b5..4547750313b 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.5b6 +sage-docbuild ~= 10.5b7 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index 8ed26a30af6..e5817221c36 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.5b6 +sage-setup ~= 10.5b7 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index d7e1976c10f..98387b4f230 100644 --- a/build/pkgs/sage_sws2rst/version_requirements.txt +++ b/build/pkgs/sage_sws2rst/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.5b6 +sage-sws2rst ~= 10.5b7 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 6a025036f77..945f0defa0c 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.5b6 +sagemath-standard ~= 10.5b7 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index 0c4ed7bfbe2..c800884c141 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.5b6 +sagemath-bliss ~= 10.5b7 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 332e97045f1..207da958f87 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.5b6 +sagemath-categories ~= 10.5b7 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index 358218fdf52..4f875089251 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.5b6 +sagemath-coxeter3 ~= 10.5b7 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 6c1bfca1159..826485f3148 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.5b6 +sagemath-environment ~= 10.5b7 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index 7d912264960..6cc3008eebd 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.5b6 +sagemath-mcqd ~= 10.5b7 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index eaac709b9e8..a1468e68dcd 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.5b6 +sagemath-meataxe ~= 10.5b7 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index 7548688007d..bfc33505932 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.5b6 +sagemath-objects ~= 10.5b7 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index ecc83e28712..6ee449e0010 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.5b6 +sagemath-repl ~= 10.5b7 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index 5e1de281a8c..4807b6d0eb8 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.5b6 +sagemath-sirocco ~= 10.5b7 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index a18dda841b4..bf62c189022 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.5b6 +sagemath-tdlib ~= 10.5b7 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/src/VERSION.txt b/src/VERSION.txt index fd111ad93ec..92fecb8fddc 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.5.beta6 +10.5.beta7 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 23685eb51c0..6e92078d830 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.5.beta6' -SAGE_RELEASE_DATE='2024-09-29' -SAGE_VERSION_BANNER='SageMath version 10.5.beta6, Release Date: 2024-09-29' +SAGE_VERSION='10.5.beta7' +SAGE_RELEASE_DATE='2024-10-12' +SAGE_VERSION_BANNER='SageMath version 10.5.beta7, Release Date: 2024-10-12' diff --git a/src/sage/version.py b/src/sage/version.py index 635791563a7..b26f1f87f03 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.5.beta6' -date = '2024-09-29' -banner = 'SageMath version 10.5.beta6, Release Date: 2024-09-29' +version = '10.5.beta7' +date = '2024-10-12' +banner = 'SageMath version 10.5.beta7, Release Date: 2024-10-12'