From 952d654c7c3d547a027804a9554783fea0fc3972 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 23 Nov 2020 14:12:24 +0100 Subject: [PATCH 001/355] Add interface to new sirocco functions --- src/sage/libs/sirocco.pyx | 120 +++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 7ab52c7915f..4634899ab23 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -23,7 +23,8 @@ from sage.rings.real_mpfr import RealField cdef extern from "sirocco.h": mpfr_t* homotopyPath_mp(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec) double* homotopyPath(int degree, double *_coef, double _y0R, double _y0I) - + mpfr_t* homotopyPath_mp_comps(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec, int nothercomps, int *degreescomps, mpfr_t *_coefscomps) + double* homotopyPath_comps(int degree, double *_coef, double _y0R, double _y0I, int nothercomps, int *degreescomps, double *_coefscomps) cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0i, int prec): @@ -76,6 +77,71 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 free(rop) return l +cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNumber y0i, int prec, list otherdegs, list othercoefs): + """ + Mimics :func:`contpath`, but with the following differences: + + - The floating point numbers can be arbitrary precision RealNumbers. + + - A extra argument is needed, indicating the bits of precision used + in the computations. + """ + cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) + cdef mpfr_t* cothercoefs = check_allocarray(len(othercoefs), sizeof(mpfr_t)) + cdef int* cotherdegs = check_allocarray(len(otherdegs), sizeof(int)) + cdef mpfr_t* rop + cdef int i, j + cdef mpfr_t y0R + cdef mpfr_t y0I + + for j in range(len(values)): + mpfr_init2(cvalues[j], prec) + mpfr_set(cvalues[j], (values[j]).value, MPFR_RNDN) + + for j in range(len(othercoefs)): + mpfr_init2(cothercoefs[j], prec) + mpfr_set(cothercoefs[j], (othercoefs[j]).value, MPFR_RNDN) + + for j in range(len(otherdegs)): + cotherdegs[j] = int(otherdegs[j]) + + + sig_on() + mpfr_init2(y0R, prec) + mpfr_set(y0R, (y0r).value, MPFR_RNDN) + mpfr_init2(y0I, prec) + mpfr_set(y0I, (y0i).value, MPFR_RNDN) + rop = homotopyPath_mp_comps(deg, cvalues, y0R, y0I, prec, int(len(otherdegs)), cotherdegs, cothercoefs) + sig_off() + + for j in range(len(values)): + mpfr_clear(cvalues[j]) + free(cvalues) + + for j in range(len(othercoefs)): + mpfr_clear(cothercoefs[j]) + free(cothercoefs) + free(cotherdegs) + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + + cdef int n = mpfr_get_si(rop[0], MPFR_RNDN) + cdef list l = [] + cdef list inner + cdef RealNumber RN + field = RealField(prec) + for i in range(n): + inner = [] + for j in range(3*i+1, 3*(i+1)+1): + RN = RealNumber.__new__(RealNumber, field) + mpfr_set(RN.value, rop[j], MPFR_RNDN) + mpfr_clear(rop[j]) + inner.append(RN) + l.append(tuple(inner)) + free(rop) + return l + + cpdef list[list] contpath(int deg, list values, double y0r, double y0i): """ INPUT: @@ -119,3 +185,55 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): free(c_values) return l +cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, list otherdegrees, list othercoefs): + """ + INPUT: + + - An integer, representing the degree of the polynomial + + - A list of floating point numbers. Each four consecutive elements + of this list represent the interval corresponding to a coefficient. + Coefficients are listed in increasing deglex order, and inside each + coefficients, the four numbers represent the lower real, upper real, + lower imaginary and real imaginary limits of the interval. + + - A float representing the real part of the initial root approximation + + - A float representing the imaginary part of the initial root. + + OUTPUT: + + A list of tuples. Each tuple represents the `x` value (between 0 and 1) + and the real and imaginary parts of the `y` value of a vertex in + the piecewise linear approximation of the path tracked by the root. + """ + cdef double* rop + cdef double* c_values = check_allocarray(len(values), sizeof(double)) + cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) + cdef double* c_othercoefs = check_allocarray(len(othercoefs), sizeof(double)) + cdef int clen = len(values) + cdef int i + for i,v in enumerate(values): + c_values[i] = values[i] + + for i,v in enumerate(otherdegrees): + c_otherdegrees[i] = otherdegrees[i] + for i,v in enumerate(othercoefs): + c_othercoefs[i] = othercoefs[i] + + cdef double y0R = y0r + cdef double y0I = y0i + sig_on() + rop = homotopyPath_comps(deg, c_values, y0R, y0I, int(len(otherdegrees)), c_otherdegrees, c_othercoefs) + sig_off() + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + cdef int n = int(rop[0]) + cdef list l = [0] * n + for i in range(n): + l[i] = (rop[3*i+1], rop[3*i+2], rop[3*i+3]) + free(rop) + free(c_values) + free(c_otherdegrees) + free(c_othercoefs) + return l From f9ca3e329325cfe9c71f2c9525098bcdaf85ba48 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 3 Dec 2020 19:57:16 +0100 Subject: [PATCH 002/355] all method treelength --- src/doc/en/reference/references/index.rst | 10 + src/sage/graphs/graph.py | 2 + .../tree_decomposition.pxd | 15 + .../tree_decomposition.pyx | 749 +++++++++++++++++- 4 files changed, 773 insertions(+), 3 deletions(-) create mode 100644 src/sage/graphs/graph_decompositions/tree_decomposition.pxd diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index c6bc4166b1e..9daacdb4c4a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1840,6 +1840,11 @@ REFERENCES: standards et permutations de Baxter, proceedings of Formal Power Series and Algebraic Combinatorics, 1994. +.. [DG2006] Yon Dourisboure and Cyril Gavoille. *Tree-decompositions with bags + of small diameter*. Discrete Mathematics, 307 (16) (2007), + pp. 2008-2029. + :doi:`10.1016/j.disc.2005.12.060` + .. [DGH2020] \C. Donnot, A. Genitrini and Y. Herida. Unranking Combinations Lexicographically: an efficient new strategy compared with others, 2020, https://hal.archives-ouvertes.fr/hal-02462764v1 @@ -3764,6 +3769,11 @@ REFERENCES: modular functions*, Int. Math. Res. Not 2007 (050). :arxiv:`math/0701168`. +.. [Lokshtanov2009] Daniel Lokshtanov. *On the complexity of computing + treelength*. Discrete Applied + Mathematics. 158(7):820-827, 2009. + :doi:`10.1016/j.dam.2009.10.007` + .. [LOS2012] \C. Lecouvey, M. Okado, M. Shimozono. "Affine crystals, one-dimensional sums and parabolic Lusztig `q`-analogues". Mathematische Zeitschrift. **271** (2012). Issue 3-4. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 79b85b409f7..fe28bc6d683 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -9248,6 +9248,7 @@ def bipartite_double(self, extended=False): from sage.graphs.graph_decompositions.rankwidth import rank_decomposition from sage.graphs.graph_decompositions.tree_decomposition import treewidth from sage.graphs.graph_decompositions.vertex_separation import pathwidth + from sage.graphs.graph_decompositions.tree_decomposition import treelength from sage.graphs.graph_decompositions.clique_separators import atoms_and_clique_separators from sage.graphs.matchpoly import matching_polynomial from sage.graphs.cliquer import all_max_clique as cliques_maximum @@ -9285,6 +9286,7 @@ def bipartite_double(self, extended=False): "rank_decomposition" : "Algorithmically hard stuff", "treewidth" : "Algorithmically hard stuff", "pathwidth" : "Algorithmically hard stuff", + "treelength" : "Algorithmically hard stuff", "matching_polynomial" : "Algorithmically hard stuff", "all_max_clique" : "Clique-related methods", "cliques_maximum" : "Clique-related methods", diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pxd b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd new file mode 100644 index 00000000000..b45006eb087 --- /dev/null +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd @@ -0,0 +1,15 @@ +from sage.graphs.generic_graph_pyx cimport GenericGraph_pyx + +cdef class TreelengthConnected: + cdef unsigned int n + cdef unsigned short * c_distances + cdef unsigned short ** distances + cdef unsigned int diameter + cdef str name + cdef dict perm_inv + cdef bint certificate + cdef bint k_is_defined + cdef unsigned int k + cdef GenericGraph_pyx tree # The final tree decomposition is stored + cdef unsigned int length + cdef bint leq_k diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index a8a6ea0dc64..14e4179bafd 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -24,6 +24,40 @@ one, i.e., `\max_{X_i \in X} |X_i| - 1`, and the *treewidth* `tw(G)` of a graph that, the size of the largest set is diminished by one in order to make the treewidth of a tree equal to one. +The *length* of a tree decomposition, as proposed in [DG2006]_, is the maximum +*diameter* in `G` of its bags, where the diameter of a bag `X_i` is the largest +distance in `G` between the vertices in `X_i` (i.e., `\max_{u, v \in X_i} +dist_G(u, v)`). The *treelength* `tl(G)` of a graph `G` is the minimum length +among all possible tree decompositions of `G`. + +While deciding whether a graph has treelength 1 can be done in linear time +(equivalant to deciding if the graph is chordal), deciding if it has treelength +at most `k` for any fixed constant `k \leq 2` is NP-complete [Lokshtanov2009]_. + +Treewidth and treelength are different measures of tree-likeness. In particular, +trees have treewidth and treelength 1:: + + sage: T = graphs.RandomTree(20) + sage: T.treewidth() + 1 + sage: T.treelength() + 1 + +However, while the treewidth of a cycle is 2, its treelength is `\lceil n/3 \rceil`:: + + sage: [graphs.CycleGraph(n).treewidth() for n in range(3, 11)] + [2, 2, 2, 2, 2, 2, 2, 2] + sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] + [1, 2, 2, 2, 3, 3, 3, 4] + +The treewidth if a clique is `n-1` while its treelength is 1:: + + sage: [graphs.CompleteGraph(n).treewidth() for n in range(3, 11)] + [2, 3, 4, 5, 6, 7, 8, 9] + sage: [graphs.CompleteGraph(n).treelength() for n in range(3, 11)] + [1, 1, 1, 1, 1, 1, 1, 1] + + .. SEEALSO:: - :wikipedia:`Tree_decomposition` @@ -37,7 +71,8 @@ treewidth of a tree equal to one. :widths: 30, 70 :delim: | - :meth:`treewidth` | Compute the tree-width of `G` (and provide a decomposition). + :meth:`treewidth` | Compute the treewidth of `G` (and provide a decomposition). + :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. :meth:`reduced_tree_decomposition(T)` | Return a reduced tree-decomposition of `T`. @@ -45,8 +80,6 @@ treewidth of a tree equal to one. .. TODO: - Add method to return a *nice* tree decomposition - - Add methods to compute treelength and examples in the module documentation - of the difference between treewidth and treelength - Approximation of treelength based on :meth:`~sage.graphs.graph.Graph.lex_M` - Approximation of treelength based on BFS Layering @@ -72,6 +105,11 @@ from itertools import combinations from itertools import chain from sage.features import PythonModule from sage.sets.disjoint_set import DisjointSet +from sage.functions.other import ceil +from sage.rings.infinity import Infinity +from sage.graphs.distances_all_pairs cimport c_distances_all_pairs +from cysignals.memory cimport sig_malloc, sig_calloc, sig_free + def is_valid_tree_decomposition(G, T): r""" @@ -723,3 +761,708 @@ def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): G.name("Tree decomposition") return G + +# +# Treelength +# + +def treelength_lowerbound(G): + r""" + Return a lower bound on the treelength of `G`. + + See [DG2006]_ for more details`. + + INPUT: + + - ``G`` -- a sage Graph + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import treelength_lowerbound + sage: G = graphs.PetersenGraph() + sage: treelength_lowerbound(G) + 1 + sage: G.treelength() + 2 + sage: G = graphs.CycleGraph(5) + sage: treelength_lowerbound(G) + 2 + sage: G.treelength() + 2 + """ + if G.is_cycle(): + return int(ceil(G.order() / 3.0)) + + lowerbound = 0 + girth = G.girth() + if girth is not Infinity: + lowerbound = max(lowerbound, girth / 3.0) + + return int(lowerbound) + + +cdef class TreelengthConnected: + r""" + Compute the treelength of a connected graph (and provide a decomposition). + + This class implements an algorithm for computing the treelength of a + connected graph that virtually explores the graph of all pairs + ``(vertex_cut, connected_component)``, where ``vertex_cut`` is a vertex cut + of the graph of length `\leq k`, and ``connected_component`` is a connected + component of the graph induced by `G - vertex_cut`. + + We deduce that the pair ``(vertex_cut, connected_component)`` is feasible + with treelength `k` if ``connected_component`` is empty, or if a vertex + ``v`` from ``vertex_cut`` can be replaced with a vertex from + ``connected_component``, such that the pair ``(vertex_cut + v, + connected_component - v)`` is feasible. + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph has + treelength `\leq k`. If `k` is ``None`` (default), the method computes the + optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to return the + tree-decomposition itself + + OUTPUT: + + ``TreelengthConnected(G)`` returns the treelength of `G`. When `k` is + specified, it returns ``False`` when no tree-decomposition of length + `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the + tree-decomposition is also returned. + + EXAMPLES: + + A clique has treelength 1:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: TreelengthConnected(graphs.CompleteGraph(3)).get_length() + 1 + sage: TC = TreelengthConnected(graphs.CompleteGraph(4), certificate=True) + sage: TC.get_length() + 1 + sage: TC.get_tree_decomposition() + Tree decomposition of Complete graph: Graph on 1 vertex + + A cycle has treelength `\lceil n/3 \rceil`:: + + sage: TreelengthConnected(graphs.CycleGraph(6)).get_length() + 2 + sage: TreelengthConnected(graphs.CycleGraph(7)).get_length() + 3 + sage: TreelengthConnected(graphs.CycleGraph(7), k=3).is_less_than_k() + True + sage: TreelengthConnected(graphs.CycleGraph(7), k=2).is_less_than_k() + False + + TESTS: + + The input graph must be connected:: + + sage: TreelengthConnected(Graph(2)) + Traceback (most recent call last): + ... + ValueError: the graph is not connected + + The parameter `k` must be non-negative:: + + sage: TreelengthConnected(Graph(1), k=-1) + Traceback (most recent call last): + ... + ValueError: k (= -1) must be a nonnegative integer + + Parameter ``certificate`` must be ``True`` to get a tree decomposition:: + + sage: TreelengthConnected(Graph(1), certificate=False).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: parameter 'certificate' has not been set to True + + When parameter `k` is specified and ``certificate`` is ``True``, the + computed tree decomposition is any valid tree decomposition with length at + most `k`. However, this tree decomposition exists only if the treelength of + `G` is at most `k` (i.e., `tl(G) \leq k`):: + + sage: G = graphs.Grid2dGraph(2, 3) + sage: TC = TreelengthConnected(G, k=2, certificate=True) + sage: TC.is_less_than_k() + True + sage: TC.get_tree_decomposition() + Tree decomposition of 2D Grid Graph for [2, 3]: Graph on 3 vertices + sage: TC = TreelengthConnected(G, k=1, certificate=True) + sage: TC.is_less_than_k() + False + sage: TC.get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + """ + + def __init__(self, G, k=None, certificate=False): + r""" + Initialize this object and compute the treelength of `G`. + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph + has treelength `\leq k`. If `k` is ``None`` (default), the method + computes the optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to compute + the tree-decomposition itself + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 + """ + if k is not None and k < 0: + raise ValueError("k (= {}) must be a nonnegative integer".format(k)) + + self.certificate = certificate + self.k_is_defined = k is not None + self.k = k if self.k_is_defined else 0 + + if certificate: + from sage.graphs.graph import Graph + self.name = "Tree decomposition of {}".format(G.name()) + + self.n = G.order() + self.distances = NULL # used in the destructor + + # Trivial cases + if self.n <= 1: + if certificate: + if self.n: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + else: + self.tree = Graph(name=self.name) + self.length = 0 + self.leq_k = True # We know that k is non negative + return + + if not G.is_connected(): + raise ValueError("the graph is not connected") + + if k == 0: + self.leq_k = False + return + + if G.is_clique(): + if certificate: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + self.length = 1 + self.leq_k = True + return + + cdef unsigned int i, j + + # If the vertices are not labeled 0..n-1, we relabel the graph. This + # way, the labeling of the vertices matches the rows and columns of the + # distance matrix + if set(G) == set(range(self.n)): + graph = G + self.perm_inv = dict() + else: + graph, perm = G.relabel(inplace=False, return_map=True) + self.perm_inv = {i: u for u, i in perm.items()} + + # We compute the distance matrix. + self.c_distances = c_distances_all_pairs(graph, vertex_list=list(range(self.n))) + self.distances = sig_calloc(self.n, sizeof(unsigned short *)) + for i in range(self.n): + self.distances[i] = self.c_distances + i * self.n + + # and the diameter of the graph + self.diameter = 0 + for i in range(self.n): + for j in range(i, self.n): + self.diameter = max(self.diameter, self.distances[i][j]) + + if ((self.k_is_defined and k >= self.diameter) or + (not self.k_is_defined and self.diameter == 1)): + # All vertices fit in one bag + if certificate: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + self.length = self.diameter + self.leq_k = True + return + + # Forcing k to be defined + if not self.k_is_defined: + for i in range(treelength_lowerbound(graph), self.diameter + 1): + ans = self._treelength(graph, i) + if ans: + self.length = i + return + + # If k is defined + ans = self._treelength(graph, k) + if ans: + self.length = k + self.leq_k = True + else: + self.leq_k = False + + def __destroy__(self): + r""" + Destroy the object + """ + if self.distances: + sig_free(self.c_distances) + sig_free(self.distances) + + + def _treelength(self, g, k): + r""" + Check whether the treelength of `g` is at most `k`. + + INPUT: + + - ``g`` -- a sage Graph + + - ``k`` -- integer; indicates the length to be considered + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, k=2).is_less_than_k() + True + """ + + # This is the recursion described in the method's documentation. All + # computations are cached, and depends on the pair ``cut, + # connected_component`` only. + # + # It returns either a boolean or the corresponding tree-decomposition, + # as a list of edges between vertex cuts (used to build the complete + # tree-decomposition at the end of the _treelength method). + @cached_function + def rec(cut, cc): + if len(cc) == 1: + [v] = cc + reduced_cut = frozenset([x for x in g.neighbor_iterator(v) if x in cut]) + if any(self.distances[v][x] > k for x in reduced_cut): + return False + if self.certificate: + if cut == reduced_cut: + return [(cut, cut.union(cc))] + # We need to forget some vertices + return [(cut, reduced_cut), (reduced_cut, reduced_cut.union(cc))] + + return True + + # We explore all possible extensions of the cut + for v in cc: + + # New cuts and connected components, with v respectively added + # and removed + cutv = cut.union([v]) + if any(self.distances[v][x] > k for x in cutv): + continue + ccv = cc.difference([v]) + + # The values returned by the recursive calls. + sons = [] + + # Removing v may have disconnected cc. We iterate on its + # connected components + for cci in g.subgraph(ccv).connected_components(): + cci = frozenset(cci) + + # The recursive subcalls. We remove on-the-fly the vertices + # from the cut which play no role in separating the + # connected component from the rest of the graph. + reduced_cutv = frozenset([x for x in cutv + if x == v or any(xx in cci for xx in g.neighbor_iterator(x))]) + reduced_cuti = frozenset([x for x in reduced_cutv + if any(xx in cci for xx in g.neighbor_iterator(x))]) + son = rec(reduced_cuti, cci) + if not son: + break + + if self.certificate: + sons.append((cut, cutv)) + if cutv != reduced_cutv: + sons.append((cutv, reduced_cutv)) + if reduced_cutv != reduced_cuti: + sons.append((reduced_cutv, reduced_cuti)) + sons.extend(son) + + # Weird Python syntax which is useful once in a lifetime : if break + # was never called in the loop above, we return "sons". + else: + return sons if self.certificate else True + + return False + + # Main call to rec function, i.e. rec({v}, V-{v}) + V = list(g) + v = frozenset([V.pop()]) + TD = rec(v, frozenset(V)) + + if TD is False: + return False + + if not self.certificate: + return True + + # Building the Tree-Decomposition graph. Its vertices are cuts of the + # decomposition, and there is an edge from a cut C1 to a cut C2 if C2 is an + # immediate subcall of C1. If needed, the vertices are relabeled. + if self.perm_inv: + def good_label(x): + return Set([self.perm_inv[i] for i in x]) + else: + def good_label(x): + return Set(x) + + from sage.graphs.graph import Graph + T = Graph([(good_label(x), good_label(y)) for x, y in TD if x != y], + format="list_of_edges") + self.tree = reduced_tree_decomposition(T) + self.tree.name(self.name) + return True + + def get_tree_decomposition(self): + """ + Return the tree-decomposition. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, certificate=True).get_tree_decomposition() + Tree decomposition of Cycle graph: Graph on 2 vertices + sage: G.diameter() + 2 + sage: TreelengthConnected(G, k=2, certificate=True).get_tree_decomposition() + Tree decomposition of Cycle graph: Graph on 1 vertex + sage: TreelengthConnected(G, k=1, certificate=True).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + sage: TreelengthConnected(G,certificate=False).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: parameter 'certificate' has not been set to True + """ + if self.certificate: + if self.k_is_defined and not self.leq_k: + raise ValueError("no tree decomposition with length <= {} was found".format(self.k)) + return self.tree + else: + raise ValueError("parameter 'certificate' has not been set to True") + + def get_length(self): + """ + Return the length of the tree decomposition. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 + sage: TreelengthConnected(G, k=2).get_length() + 2 + sage: TreelengthConnected(G, k=1).get_length() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + """ + if self.k_is_defined and not self.leq_k: + raise ValueError("no tree decomposition with length <= {} was found".format(self.k)) + return self.length + + def is_less_than_k(self): + """ + Return whether a tree decomposition with length at most `k` was found. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, k=1).is_less_than_k() + False + sage: TreelengthConnected(G, k=2).is_less_than_k() + True + sage: TreelengthConnected(G).is_less_than_k() + Traceback (most recent call last): + ... + ValueError: parameter 'k' has not been specified + """ + if self.k_is_defined: + return self.leq_k + raise ValueError("parameter 'k' has not been specified") + + +def treelength(G, k=None, certificate=False): + r""" + Compute the tree-length of `G` (and provide a decomposition). + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph has + treelength `\leq k`. If `k` is ``None`` (default), the method computes the + optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to return the + tree-decomposition itself + + OUTPUT: + + ``G.treelength()`` returns the treelength of `G`. When `k` is specified, + it returns ``False`` when no tree-decomposition of length `\leq k` + exists or ``True`` otherwise. When ``certificate=True``, the + tree-decomposition is also returned. + + ALGORITHM: + + This method virtually explores the graph of all pairs ``(vertex_cut, + connected_component)``, where ``vertex_cut`` is a vertex cut of the + graph of length `\leq k`, and ``connected_component`` is a + connected component of the graph induced by `G - vertex_cut`. + + We deduce that the pair ``(vertex_cut, connected_component)`` is + feasible with treelength `k` if ``connected_component`` is empty, or if + a vertex ``v`` from ``vertex_cut`` can be replaced with a vertex from + ``connected_component``, such that the pair ``(vertex_cut + v, + connected_component - v)`` is feasible. + + In practice, this method decomposes the graph by its clique minimal + separators into atoms, computes the treelength of each of atom and + returns the maximum value over all the atoms. Indeed, we have that + `tl(G) = \max_{X \in A} tl(G[X])` where `A` is the set of atoms of the + decomposition by clique separators of `G`. When ``certificate == True``, + the tree-decompositions of the atoms are connected to each others by + adding edges with respect to the clique separators. + + .. SEEALSO:: + + - :meth:`treewidth` computes the treewidth of a + graph. + - :meth:`~sage.graphs.graph_decompositions.vertex_separation.path_decomposition` + computes the pathwidth of a graph. + - :mod:`~sage.graphs.graph_decompositions.vertex_separation` module. + - :meth:`~sage.graphs.Graph.atoms_and_clique_separators` + + EXAMPLES: + + The PetersenGraph has treelength 2:: + + sage: G = graphs.PetersenGraph() + sage: G.treelength() + 2 + + Disconnected graphs have infinite treelength:: + + sage: G = Graph(2) + sage: G.treelength() + +Infinity + sage: G.treelength(k=+Infinity) + True + sage: G.treelength(k=2) + False + sage: G.treelength(certificate=True) + Traceback (most recent call last): + ... + ValueError: the tree decomposition of a disconnected graph is not defined + + Chordal graphs have treelength 1:: + + sage: G = graphs.RandomChordalGraph(30) + sage: while not G.is_connected(): + ....: G = graphs.RandomChordalGraph(30) + sage: G.treelength() + 1 + + Cycles have treelength `\lceil n/3 \rceil`:: + + sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] + [1, 2, 2, 2, 3, 3, 3, 4] + + TESTS:: + + Check that the decomposition by clique separators is valid:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.Grid2dGraph(2, 3) + sage: G.treelength() == TreelengthConnected(G).get_length() + True + sage: G = graphs.RandomBarabasiAlbert(30, 2) # long time + sage: G.treelength() == TreelengthConnected(G).get_length() # long time + True + + Check that the returned tree is a valid tree decomposition:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_decomposition + sage: G = graphs.RandomBarabasiAlbert(30, 2) # long time + sage: T = G.treelength(certificate=True) # long time + sage: is_valid_tree_decomposition(G, T) # long time + True + + Corner cases:: + + sage: Graph().treelength() + 0 + sage: Graph().treelength(certificate=True) + Tree decomposition: Graph on 0 vertices + sage: Graph(1).treelength() + 0 + sage: Graph(1).treelength(k=0) + True + sage: Graph(1).treelength(certificate=True) + Tree decomposition: Graph on 1 vertex + sage: G = graphs.PathGraph(2) + sage: G.treelength() + 1 + sage: G.treelength(k=0) + False + sage: G.treelength(certificate=True) + Tree decomposition of Path graph: Graph on 1 vertex + sage: G.treelength(certificate=True, k=0) + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length 0 was found + sage: G.treelenth(k=-1) + Traceback (most recent call last): + ... + ValueError: k(=-1) must be a nonnegative integer + """ + if G.is_directed(): + raise ValueError("this method is defined for undirected graphs only") + + if k is not None and k < 0: + raise ValueError("k(={}) must be a nonnegative integer".format(k)) + + name = "Tree decomposition" + if G.name(): + name += " of {}".format(G.name()) + + # Corner cases + from sage.graphs.graph import Graph + if G.order() <= 1: + if certificate: + if G: + return Graph({Set(G): []}, format="dict_of_lists", name=name) + else: + return Graph(name=name) + elif k is None: + return 0 + else: + return True # We know that k is non negative + if not G.is_connected(): + if certificate: + raise ValueError("the tree decomposition of a disconnected graph is not defined") + elif k is None: + return +Infinity + else: + return k is Infinity + if k == 0: + if certificate: + raise ValueError("no tree decomposition with length 0 was found") + return False + if not certificate and G.is_chordal(): + return 1 if k is None else True + + # We decompose the graph by clique minimal separators into atoms and solve + # the problem on each of them + atoms, cliques = G.atoms_and_clique_separators() + + # As some atoms might be isomorphic, we use a dictionary keyed by immutable + # copies of canonical graphs to store intermediate results. + data = dict() + result = [] + tl = 1 # The graph is connected and of order least 2 + + for atom in atoms: + + ga = G.subgraph(atom) + if ga.is_clique(): + if certificate: + result.append(Graph({Set(atom): []}, format="dict_of_lists")) + continue + + gc, certif = ga.canonical_label(certificate=True) + gci = gc.copy(immutable=True) + + if gci in data: + # We already solved the problem for an isomorphic atom. + if certificate: + # We deduce the solution for this atom + certif_inv = {i: u for u, i in certif.items()} + perm = {u: Set([certif_inv[i] for i in u]) for u in data[gci]} + result.append(data[gci].relabel(perm=perm, inplace=False, immutable=False)) + continue + + # We solve the problem for this atom and store the result + TC = TreelengthConnected(gci, k=k, certificate=certificate) + if certificate: + T = TC.get_tree_decomposition() + data[gci] = T + certif_inv = {i: u for u, i in certif.items()} + perm = {u: Set([certif_inv[i] for i in u]) for u in T} + result.append(T.relabel(perm=perm, inplace=False, immutable=False)) + if k is None: + tl = max(tl, TC.get_length()) + elif not TC.is_less_than_k(): + return False + + if not certificate: + if k is None: + return tl + return True + + # We now build the tree decomposition of the graph by connecting the tree + # decompositions of its atoms. This is done in an order that is consistent + # with the order of the atoms and cliques returned by method + # atoms_and_clique_separators. More precisely, the first clique separates + # the first atom from the rest of the graph (call G1 this part of the + # graph), the second clique separates (in G1) the second atom from the rest + # of the graph G1, etc. So we merge the tree decompositions in the reverse + # order of the atoms. + T = result.pop() + while result: + A = result.pop() + C = cliques.pop() + + # We search for a vertex in A and T containing clique C + ua, ut = None, None + for u in A: + if u.issuperset(C): + ua = u + break + for u in T: + if u.issuperset(C): + ut = u + break + if ua and ut: + A.add_edge(ua, ut) + else: + # This should never happen + raise RuntimeError("something goes wrong. Please report the issue " + "to sage-devel@googlegroups.com") + + # We merge T and A + T.add_edges(A.edges()) + + # The Tree-Decomposition may contain a lot of useless nodes. + # We merge all edges between two sets S,S' where S is a subset of S' + T = reduced_tree_decomposition(T) + T.name(name) + return T From 5adc99db5896267b5ccc6bf2dd980037cc3b8e0c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 3 Dec 2020 22:19:36 +0100 Subject: [PATCH 003/355] trac #30998: improve doctests coverage --- .../tree_decomposition.pyx | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 14e4179bafd..0c4b57a2a5e 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -789,6 +789,11 @@ def treelength_lowerbound(G): 2 sage: G.treelength() 2 + + TESTS:: + + sage: treelength_lowerbound(Graph()) + 0 """ if G.is_cycle(): return int(ceil(G.order() / 3.0)) @@ -919,7 +924,7 @@ cdef class TreelengthConnected: - ``certificate`` -- boolean (default: ``False``); whether to compute the tree-decomposition itself - EXAMPLES:: + TESTS:: sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected sage: G = graphs.CycleGraph(4) @@ -1017,6 +1022,13 @@ cdef class TreelengthConnected: def __destroy__(self): r""" Destroy the object + + TESTS:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 """ if self.distances: sig_free(self.c_distances) @@ -1033,7 +1045,7 @@ cdef class TreelengthConnected: - ``k`` -- integer; indicates the length to be considered - EXAMPLES:: + TESTS:: sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected sage: G = graphs.CycleGraph(4) @@ -1153,7 +1165,11 @@ cdef class TreelengthConnected: Traceback (most recent call last): ... ValueError: no tree decomposition with length <= 1 was found - sage: TreelengthConnected(G,certificate=False).get_tree_decomposition() + + TESTS:: + + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, certificate=False).get_tree_decomposition() Traceback (most recent call last): ... ValueError: parameter 'certificate' has not been set to True @@ -1181,6 +1197,11 @@ cdef class TreelengthConnected: Traceback (most recent call last): ... ValueError: no tree decomposition with length <= 1 was found + + TESTS:: + + sage: TreelengthConnected(Graph()).get_length() + 0 """ if self.k_is_defined and not self.leq_k: raise ValueError("no tree decomposition with length <= {} was found".format(self.k)) @@ -1202,6 +1223,11 @@ cdef class TreelengthConnected: Traceback (most recent call last): ... ValueError: parameter 'k' has not been specified + + TESTS:: + + sage: TreelengthConnected(Graph(), k=1).is_less_than_k() + True """ if self.k_is_defined: return self.leq_k From 51b783021b05179919492e426022b2410bd825bb Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 5 Dec 2020 16:33:55 +0100 Subject: [PATCH 004/355] trac #30998: further improvements --- .../tree_decomposition.pyx | 129 +++++++++++------- 1 file changed, 83 insertions(+), 46 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 0c4b57a2a5e..dc7708cfc4b 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -279,7 +279,16 @@ def reduced_tree_decomposition(T): True sage: T == reduced_tree_decomposition(T) True + sage: G = Graph(1) + sage: T = G.treewidth(certificate=True) + sage: T.order() + 1 + sage: T == reduced_tree_decomposition(T) + True """ + if T.order() < 2: + return T + def get_ancestor(ancestor, u): if ancestor[u] == u: return u @@ -831,8 +840,8 @@ cdef class TreelengthConnected: treelength `\leq k`. If `k` is ``None`` (default), the method computes the optimal treelength. - - ``certificate`` -- boolean (default: ``False``); whether to return the - tree-decomposition itself + - ``certificate`` -- boolean (default: ``False``); whether to also compute + the tree-decomposition itself OUTPUT: @@ -933,6 +942,9 @@ cdef class TreelengthConnected: """ if k is not None and k < 0: raise ValueError("k (= {}) must be a nonnegative integer".format(k)) + G._scream_if_not_simple() + if not G.is_connected(): + raise ValueError("the graph is not connected") self.certificate = certificate self.k_is_defined = k is not None @@ -946,20 +958,19 @@ cdef class TreelengthConnected: self.distances = NULL # used in the destructor # Trivial cases - if self.n <= 1: + if (self.n <= 1 or + (self.k_is_defined and self.n <= k)): if certificate: if self.n: self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) else: self.tree = Graph(name=self.name) - self.length = 0 + self.length = 0 if self.n <= 1 else G.diameter(algorithm='DHV') self.leq_k = True # We know that k is non negative return - if not G.is_connected(): - raise ValueError("the graph is not connected") - - if k == 0: + if self.k_is_defined and k == 0: + # We have at least 2 vertices and 1 edges, so tl >= 1 self.leq_k = False return @@ -994,8 +1005,7 @@ cdef class TreelengthConnected: for j in range(i, self.n): self.diameter = max(self.diameter, self.distances[i][j]) - if ((self.k_is_defined and k >= self.diameter) or - (not self.k_is_defined and self.diameter == 1)): + if self.k_is_defined and k >= self.diameter: # All vertices fit in one bag if certificate: self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) @@ -1064,9 +1074,12 @@ cdef class TreelengthConnected: def rec(cut, cc): if len(cc) == 1: [v] = cc - reduced_cut = frozenset([x for x in g.neighbor_iterator(v) if x in cut]) - if any(self.distances[v][x] > k for x in reduced_cut): - return False + # We identify the neighbors of v in cut + reduced_cut = cut.intersection(g.neighbor_iterator(v)) + # We can form a new bag with its closed neighborhood, and this + # bag has diameter at most 2. Furthermore, if k == 1, we know + # that the bag cut has diameter <= 1, and so the new bag has + # diameter 1 if self.certificate: if cut == reduced_cut: return [(cut, cut.union(cc))] @@ -1078,11 +1091,12 @@ cdef class TreelengthConnected: # We explore all possible extensions of the cut for v in cc: - # New cuts and connected components, with v respectively added - # and removed - cutv = cut.union([v]) - if any(self.distances[v][x] > k for x in cutv): + # We know that the cut has diameter <= k. So we check is adding + # v to the cut does not make its diameter > k + if any(self.distances[v][x] > k for x in cut): continue + # We add v to the cut and remove it from cc + cutv = cut.union([v]) ccv = cc.difference([v]) # The values returned by the recursive calls. @@ -1095,20 +1109,28 @@ cdef class TreelengthConnected: # The recursive subcalls. We remove on-the-fly the vertices # from the cut which play no role in separating the - # connected component from the rest of the graph. - reduced_cutv = frozenset([x for x in cutv - if x == v or any(xx in cci for xx in g.neighbor_iterator(x))]) - reduced_cuti = frozenset([x for x in reduced_cutv + # connected component from the rest of the graph. That is, + # we identify the vertices of cutv with a neighbor in cci + reduced_cuti = frozenset([x for x in cutv if any(xx in cci for xx in g.neighbor_iterator(x))]) + if not reduced_cuti: + # This should not happen + break + + # and we do a recursive call son = rec(reduced_cuti, cci) if not son: break + # We get a valid decomposition of cci if self.certificate: + # We connect cut, cutv, reduced_cci and son sons.append((cut, cutv)) - if cutv != reduced_cutv: + if v in reduced_cuti: + sons.append((cutv, reduced_cuti)) + else: + reduced_cutv = reduced_cuti.union([v]) sons.append((cutv, reduced_cutv)) - if reduced_cutv != reduced_cuti: sons.append((reduced_cutv, reduced_cuti)) sons.extend(son) @@ -1247,8 +1269,8 @@ def treelength(G, k=None, certificate=False): treelength `\leq k`. If `k` is ``None`` (default), the method computes the optimal treelength. - - ``certificate`` -- boolean (default: ``False``); whether to return the - tree-decomposition itself + - ``certificate`` -- boolean (default: ``False``); whether to also return + the tree-decomposition itself OUTPUT: @@ -1338,7 +1360,7 @@ def treelength(G, k=None, certificate=False): sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_decomposition sage: G = graphs.RandomBarabasiAlbert(30, 2) # long time - sage: T = G.treelength(certificate=True) # long time + sage: tl, T = G.treelength(certificate=True) # long time sage: is_valid_tree_decomposition(G, T) # long time True @@ -1347,32 +1369,35 @@ def treelength(G, k=None, certificate=False): sage: Graph().treelength() 0 sage: Graph().treelength(certificate=True) - Tree decomposition: Graph on 0 vertices + (0, Tree decomposition: Graph on 0 vertices) sage: Graph(1).treelength() 0 sage: Graph(1).treelength(k=0) True sage: Graph(1).treelength(certificate=True) - Tree decomposition: Graph on 1 vertex + (0, Tree decomposition: Graph on 1 vertex) + sage: Graph(1).treelength(k=0, certificate=True) + (True, Tree decomposition: Graph on 1 vertex) sage: G = graphs.PathGraph(2) sage: G.treelength() 1 sage: G.treelength(k=0) False sage: G.treelength(certificate=True) - Tree decomposition of Path graph: Graph on 1 vertex + (1, Tree decomposition of Path graph: Graph on 1 vertex) sage: G.treelength(certificate=True, k=0) - Traceback (most recent call last): - ... - ValueError: no tree decomposition with length 0 was found - sage: G.treelenth(k=-1) + (False, None) + sage: G.treelength(certificate=True, k=1) + (True, Tree decomposition of Path graph: Graph on 1 vertex) + sage: G.treelength(certificate=True, k=0) + (False, None) + sage: G.treelength(k=-1) Traceback (most recent call last): ... ValueError: k(=-1) must be a nonnegative integer """ if G.is_directed(): raise ValueError("this method is defined for undirected graphs only") - if k is not None and k < 0: raise ValueError("k(={}) must be a nonnegative integer".format(k)) @@ -1383,15 +1408,13 @@ def treelength(G, k=None, certificate=False): # Corner cases from sage.graphs.graph import Graph if G.order() <= 1: + answer = 0 if k is None else True if certificate: if G: - return Graph({Set(G): []}, format="dict_of_lists", name=name) + answer = answer, Graph({Set(G): []}, format="dict_of_lists", name=name) else: - return Graph(name=name) - elif k is None: - return 0 - else: - return True # We know that k is non negative + answer = answer, Graph(name=name) + return answer if not G.is_connected(): if certificate: raise ValueError("the tree decomposition of a disconnected graph is not defined") @@ -1400,9 +1423,7 @@ def treelength(G, k=None, certificate=False): else: return k is Infinity if k == 0: - if certificate: - raise ValueError("no tree decomposition with length 0 was found") - return False + return (False, None) if certificate else False if not certificate and G.is_chordal(): return 1 if k is None else True @@ -1410,11 +1431,25 @@ def treelength(G, k=None, certificate=False): # the problem on each of them atoms, cliques = G.atoms_and_clique_separators() + if not cliques: + # We have a single atom + TC = TreelengthConnected(G, k=k, certificate=certificate) + if certificate: + if k is None: + return TC.get_length(), TC.get_tree_decomposition() + elif TC.is_less_than_k(): + return True, TC.get_tree_decomposition() + else: + return False, None + if k is None: + return TC.get_length() + return TC.is_less_than_k() + # As some atoms might be isomorphic, we use a dictionary keyed by immutable # copies of canonical graphs to store intermediate results. data = dict() result = [] - tl = 1 # The graph is connected and of order least 2 + tl = 1 # The graph is connected and of order at least 2 for atom in atoms: @@ -1447,7 +1482,7 @@ def treelength(G, k=None, certificate=False): if k is None: tl = max(tl, TC.get_length()) elif not TC.is_less_than_k(): - return False + return False if not certificate else (False, None) if not certificate: if k is None: @@ -1491,4 +1526,6 @@ def treelength(G, k=None, certificate=False): # We merge all edges between two sets S,S' where S is a subset of S' T = reduced_tree_decomposition(T) T.name(name) - return T + if k is None: + return tl, T + return True, T From eeaef0d887f97460e1a3bfdbbc21c0e847ad8873 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 7 Dec 2020 18:30:50 +0100 Subject: [PATCH 005/355] trac #30998: use method _from_tree_decompositions_of_atoms_to_tree_decomposition --- .../tree_decomposition.pyx | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index dc7708cfc4b..aa255489a73 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -1302,8 +1302,7 @@ def treelength(G, k=None, certificate=False): .. SEEALSO:: - - :meth:`treewidth` computes the treewidth of a - graph. + - :meth:`treewidth` computes the treewidth of a graph. - :meth:`~sage.graphs.graph_decompositions.vertex_separation.path_decomposition` computes the pathwidth of a graph. - :mod:`~sage.graphs.graph_decompositions.vertex_separation` module. @@ -1490,37 +1489,8 @@ def treelength(G, k=None, certificate=False): return True # We now build the tree decomposition of the graph by connecting the tree - # decompositions of its atoms. This is done in an order that is consistent - # with the order of the atoms and cliques returned by method - # atoms_and_clique_separators. More precisely, the first clique separates - # the first atom from the rest of the graph (call G1 this part of the - # graph), the second clique separates (in G1) the second atom from the rest - # of the graph G1, etc. So we merge the tree decompositions in the reverse - # order of the atoms. - T = result.pop() - while result: - A = result.pop() - C = cliques.pop() - - # We search for a vertex in A and T containing clique C - ua, ut = None, None - for u in A: - if u.issuperset(C): - ua = u - break - for u in T: - if u.issuperset(C): - ut = u - break - if ua and ut: - A.add_edge(ua, ut) - else: - # This should never happen - raise RuntimeError("something goes wrong. Please report the issue " - "to sage-devel@googlegroups.com") - - # We merge T and A - T.add_edges(A.edges()) + # decompositions of its atoms. + T = _from_tree_decompositions_of_atoms_to_tree_decomposition(result, cliques) # The Tree-Decomposition may contain a lot of useless nodes. # We merge all edges between two sets S,S' where S is a subset of S' From 4fb2610585cc1ed5e28df6c4a57921a6ca7e2d5a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 7 Dec 2020 18:50:51 +0100 Subject: [PATCH 006/355] trac #30998: corrections and faster doctest --- .../tree_decomposition.pyx | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index aa255489a73..45ff3e60e32 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -43,14 +43,14 @@ trees have treewidth and treelength 1:: sage: T.treelength() 1 -However, while the treewidth of a cycle is 2, its treelength is `\lceil n/3 \rceil`:: +The treewidth of a cycle is 2 and its treelength is `\lceil n/3 \rceil`:: sage: [graphs.CycleGraph(n).treewidth() for n in range(3, 11)] [2, 2, 2, 2, 2, 2, 2, 2] sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] [1, 2, 2, 2, 3, 3, 3, 4] -The treewidth if a clique is `n-1` while its treelength is 1:: +The treewidth of a clique is `n-1` and its treelength is 1:: sage: [graphs.CompleteGraph(n).treewidth() for n in range(3, 11)] [2, 3, 4, 5, 6, 7, 8, 9] @@ -75,6 +75,7 @@ The treewidth if a clique is `n-1` while its treelength is 1:: :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. :meth:`reduced_tree_decomposition(T)` | Return a reduced tree-decomposition of `T`. + :meth:`width_of_tree_decomposition` | Return the width of the tree decomposition `T` of `G`. .. TODO: @@ -1258,7 +1259,7 @@ cdef class TreelengthConnected: def treelength(G, k=None, certificate=False): r""" - Compute the tree-length of `G` (and provide a decomposition). + Compute the treelength of `G` (and provide a decomposition). INPUT: @@ -1348,19 +1349,14 @@ def treelength(G, k=None, certificate=False): Check that the decomposition by clique separators is valid:: sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected - sage: G = graphs.Grid2dGraph(2, 3) - sage: G.treelength() == TreelengthConnected(G).get_length() - True - sage: G = graphs.RandomBarabasiAlbert(30, 2) # long time - sage: G.treelength() == TreelengthConnected(G).get_length() # long time - True - - Check that the returned tree is a valid tree decomposition:: - sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_decomposition - sage: G = graphs.RandomBarabasiAlbert(30, 2) # long time - sage: tl, T = G.treelength(certificate=True) # long time - sage: is_valid_tree_decomposition(G, T) # long time + sage: G = graphs.StarGraph(3) + sage: G.subdivide_edges(G.edges(sort=False), 2) + sage: G = G.cartesian_product(graphs.CycleGraph(3)) + sage: tl, T = G.treelength(certificate=True) + sage: tl == TreelengthConnected(G).get_length() + True + sage: is_valid_tree_decomposition(G, T) True Corner cases:: From b92e036d7d6ea6a9e5a8ffd93cdd2804d0f0315a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Feb 2021 16:22:14 -0800 Subject: [PATCH 007/355] sage.doctest: Handle file directives '# sage.doctest: optional - xyz' --- src/doc/en/developer/coding_basics.rst | 15 ++++++++++++ src/sage/doctest/control.py | 33 ++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 41c0532c1c1..43823abe469 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1059,6 +1059,21 @@ framework. Here is a comprehensive list: sage: SloaneEncyclopedia[60843] # optional - sloane_database + .. NOTE:: + + If one of the first 10 lines of a file starts with any of + ``r""" sage.doctest: optional - keyword`` + (or ``""" sage.doctest: optional - keyword`` + or ``# sage.doctest: optional - keyword`` + or ``% sage.doctest: optional - keyword`` + or ``.. sage.doctest: optional - keyword``, + or any of these with different spacing), + then that file will be skipped unless + the ``--optional=keyword`` flag is passed to ``sage -t``. + + This does not apply to files which are explicitly given + as command line arguments: those are always tested. + - **internet:** For lines that require an internet connection:: sage: oeis(60843) # optional - internet diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 7d2b84b9c3a..6e75131fb34 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -38,9 +38,11 @@ from .reporting import DocTestReporter from .util import Timer, count_noun, dict_difference from .external import external_software, available_software +from .parsing import parse_optional_tags nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') optionaltag_regex = re.compile(r'^\w+$') +optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') # Optional tags which are always automatically added @@ -202,11 +204,18 @@ def skipdir(dirname): return True return False -def skipfile(filename): +def skipfile(filename, tested_optional_tags=False): """ Return True if and only if the file ``filename`` should not be doctested. + INPUT: + + - ``filename`` - name of a file + + - ``tested_optional_tags`` - a list or tuple or set of optional tags to test, + or ``False`` (no optional test) or ``True`` (all optional tests) + EXAMPLES:: sage: from sage.doctest.control import skipfile @@ -219,6 +228,16 @@ def skipfile(filename): ....: _ = f.write("# nodoctest") sage: skipfile(filename) True + sage: with open(filename, "w") as f: + ....: _ = f.write("# sage.doctest: optional - xyz") + sage: skipfile(filename, False) + True + sage: skipfile(filename, ['abc']) + True + sage: skipfile(filename, ['abc', 'xyz']) + False + sage: skipfile(filename, True) + False """ base, ext = os.path.splitext(filename) if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex'): @@ -228,6 +247,16 @@ def skipfile(filename): for line in F: if nodoctest_regex.match(line): return True + if tested_optional_tags is not True: + # Adapted from code in SageDocTestParser.parse + m = optionalfiledirective_regex.match(line) + if m: + if tested_optional_tags is False: + return True + optional_tags = parse_optional_tags('#' + m.group(2)) + extra = optional_tags - set(tested_optional_tags) + if extra: + return True line_count += 1 if line_count >= 10: break @@ -781,7 +810,7 @@ def expand(): if dir[0] == "." or skipdir(os.path.join(root,dir)): dirs.remove(dir) for file in files: - if not skipfile(os.path.join(root,file)): + if not skipfile(os.path.join(root, file), self.options.optional): yield os.path.join(root, file) else: # the user input this file explicitly, so we don't skip it From 07818e626a8a69bee77668969840c98d61f9a983 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 18 Feb 2021 20:04:51 -0800 Subject: [PATCH 008/355] trac 30778: when a module is labeled "optional - xyz", print a warning when doing introspection. Documentation: recommend that people document it if they add such a tag to a module. --- src/doc/en/developer/coding_basics.rst | 5 +++++ src/sage/doctest/control.py | 13 ++++++++++--- src/sage/misc/sageinspect.py | 9 +++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 43823abe469..b0f9bb9d1a7 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1074,6 +1074,11 @@ framework. Here is a comprehensive list: This does not apply to files which are explicitly given as command line arguments: those are always tested. + If you add such a line to a file, you are strongly encouraged + to add a note to the module-level documentation, saying that + the doctests in this file will be skipped unless the + appropriate conditions are met. + - **internet:** For lines that require an internet connection:: sage: oeis(60843) # optional - internet diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 6e75131fb34..db3ca10279b 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -216,6 +216,11 @@ def skipfile(filename, tested_optional_tags=False): - ``tested_optional_tags`` - a list or tuple or set of optional tags to test, or ``False`` (no optional test) or ``True`` (all optional tests) + If ``filename`` contains a line of the form ``"# sage.doctest: + optional - xyz")``, then this will return ``False`` if "xyz" is in + ``tested_optional_tags``. Otherwise, it returns the matching tag + ("optional - xyz"). + EXAMPLES:: sage: from sage.doctest.control import skipfile @@ -231,9 +236,11 @@ def skipfile(filename, tested_optional_tags=False): sage: with open(filename, "w") as f: ....: _ = f.write("# sage.doctest: optional - xyz") sage: skipfile(filename, False) + 'optional - xyz' + sage: bool(skipfile(filename, False)) True sage: skipfile(filename, ['abc']) - True + 'optional - xyz' sage: skipfile(filename, ['abc', 'xyz']) False sage: skipfile(filename, True) @@ -252,11 +259,11 @@ def skipfile(filename, tested_optional_tags=False): m = optionalfiledirective_regex.match(line) if m: if tested_optional_tags is False: - return True + return m.group(2) optional_tags = parse_optional_tags('#' + m.group(2)) extra = optional_tags - set(tested_optional_tags) if extra: - return True + return m.group(2) line_count += 1 if line_count >= 10: break diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index a37edbbffc3..74fa086db6a 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2031,6 +2031,15 @@ def sage_getdoc(obj, obj_name='', embedded_override=False): return '' r = sage_getdoc_original(obj) s = sage.misc.sagedoc.format(r, embedded=(embedded_override or EMBEDDED_MODE)) + f = sage_getfile(obj) + if f: + from sage.doctest.control import skipfile + skip = skipfile(f) + if skip: + warn = """WARNING: the enclosing module is marked '{}', +so doctests may not pass.""".format(skip) + s = warn + "\n\n" + s + pass # Fix object naming if obj_name != '': From bdc72234cc17c709847d06f2213162c8f7d6c99f Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 12 Mar 2021 00:22:16 +0100 Subject: [PATCH 009/355] partial reqrite for the new sirocco version --- src/sage/libs/sirocco.pyx | 4 + src/sage/schemes/curves/zariski_vankampen.py | 174 +++++++++++++------ 2 files changed, 126 insertions(+), 52 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 4634899ab23..9d0ad0b0230 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -86,6 +86,7 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum - A extra argument is needed, indicating the bits of precision used in the computations. """ + cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) cdef mpfr_t* cothercoefs = check_allocarray(len(othercoefs), sizeof(mpfr_t)) cdef int* cotherdegs = check_allocarray(len(otherdegs), sizeof(int)) @@ -207,6 +208,8 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. """ + + cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) @@ -237,3 +240,4 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li free(c_otherdegrees) free(c_othercoefs) return l + diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 5209e6f2cd2..36989d663e9 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -56,6 +56,7 @@ from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation from sage.functions.generalized import sign +from sage.combinat.subset import Subsets def braid_from_piecewise(strands): @@ -64,8 +65,8 @@ def braid_from_piecewise(strands): INPUT: - - ``strands`` -- a list of lists of tuples ``(t, c)``, where ``t`` - is a number between 0 and 1, and ``c`` is a complex number + - ``strands`` -- a list of lists of tuples ``(t, c1, c2)``, where ``t`` + is a number between 0 and 1, and ``c1`` and ``c2`` are rationals or algebraic reals. OUTPUT: @@ -74,34 +75,36 @@ def braid_from_piecewise(strands): EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco - sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)], - ....: [(0, -1), (0.5, -I), (1, 1)], - ....: [(0, 1), (0.5, 1 + I), (1, I)]] + sage: paths = [[(0, 0, 1), (0.2, -1, -0.5), (0.8, -1, 0), (1, 0, -1)], + ....: [(0, -1, 0), (0.5, 0, -1), (1, 1, 0)], + ....: [(0, 1, 0), (0.5, 1, 1), (1, 0, 1)]] sage: braid_from_piecewise(paths) # optional - sirocco s0*s1 """ L = strands i = min(val[1][0] for val in L) - totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L] + totalpoints = [[[a[0][1], a[0][2]]] for a in L] indices = [1 for a in range(len(L))] while i < 1: for j, val in enumerate(L): if val[indices[j]][0] > i: - xaux = val[indices[j] - 1][1] - yaux = val[indices[j]][1] + xauxr = val[indices[j] - 1][1] + xauxi = val[indices[j] - 1][2] + yauxr = val[indices[j]][1] + yauxi = val[indices[j]][2] aaux = val[indices[j] - 1][0] baux = val[indices[j]][0] - interpola = xaux + (yaux - xaux) * (i - aaux) / (baux - aaux) - totalpoints[j].append([interpola.real(), interpola.imag()]) + interpolar = xauxr + (yauxr - xauxr) * (i - aaux) / (baux - aaux) + interpolai = xauxi + (yauxi - xauxi) * (i - aaux) / (baux - aaux) + totalpoints[j].append([interpolar, interpolai]) else: - totalpoints[j].append([val[indices[j]][1].real(), - val[indices[j]][1].imag()]) + totalpoints[j].append([val[indices[j]][1], + val[indices[j]][2]]) indices[j] = indices[j] + 1 i = min(val[indices[k]][0] for k, val in enumerate(L)) for j, val in enumerate(L): - totalpoints[j].append([val[-1][1].real(), val[-1][1].imag()]) - + totalpoints[j].append([val[-1][1], val[-1][2]]) braid = [] G = SymmetricGroup(len(totalpoints)) @@ -122,7 +125,7 @@ def sgn(x, y): for j in range(len(l2)): for k in range(j): if l2[j] < l2[k]: - t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0]) + t = (l1[j][0] - l1[k][0])/((l2[k][0]-l2[j][0]) + (l1[j][0] - l1[k][0])) s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1]) cruces.append([t, k, j, s]) if cruces: @@ -172,9 +175,9 @@ def discrim(f): -0.500000000000000? - 0.866025403784439?*I, -0.500000000000000? + 0.866025403784439?*I] """ - x, y = f.variables() + x, y = f.parent().gens() F = f.base_ring() - poly = F[x](f.discriminant(y).resultant(f, y)).radical() + poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) @@ -234,7 +237,7 @@ def segments(points): return res -def followstrand(f, x0, x1, y0a, prec=53): +def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation of the root ``y0a`` from ``x0`` to ``x1``. @@ -270,10 +273,18 @@ def followstrand(f, x0, x1, y0a, prec=53): (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] """ + if f.degree() == 1: + CF = ComplexField(prec) + g = f.change_ring(CF) + (x, y) = g.parent().gens() + y0 = CF[y](g.subs({x: x0})).roots()[0][0] + y1 = CF[y](g.subs({x: x1})).roots()[0][0] + res = [(0.0, y0.real(), y0.imag()), (1.0, y1.real(), y1.imag())] + return res CIF = ComplexIntervalField(prec) CC = ComplexField(prec) G = f.change_ring(QQbar).change_ring(CIF) - (x, y) = G.variables() + (x, y) = G.parent().gens() g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) coefs = [] deg = g.total_degree() @@ -286,19 +297,40 @@ def followstrand(f, x0, x1, y0a, prec=53): coefs += list(ci.endpoints()) yr = CC(y0a).real() yi = CC(y0a).imag() - from sage.libs.sirocco import contpath, contpath_mp + coefsfactors = [] + degsfactors = [] + for fc in factors: + degfc = fc.degree() + degsfactors.append(degfc) + G = fc.change_ring(QQbar).change_ring(CIF) + g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) + for d in range(degfc + 1): + for i in range(d + 1): + c = CIF(g.coefficient({x: d - i, y: i})) + cr = c.real() + ci = c.imag() + coefsfactors += list(cr.endpoints()) + coefsfactors += list(ci.endpoints()) + from sage.libs.sirocco import contpath, contpath_mp, contpath_comps, contpath_mp_comps try: if prec == 53: - points = contpath(deg, coefs, yr, yi) + if factors: + points = contpath_comps(deg, coefs, yr, yi, degsfactors, coefsfactors) + else: + points = contpath(deg, coefs, yr, yi) else: - points = contpath_mp(deg, coefs, yr, yi, prec) + if factors: + points = contpath_mp_comps(deg, coefs, yr, yi, prec, degsfactors, coefsfactors) + else: + points = contpath_mp(deg, coefs, yr, yi, prec) return points except Exception: - return followstrand(f, x0, x1, y0a, 2 * prec) + return followstrand(f, factors, x0, x1, y0a, 2 * prec) + @parallel -def braid_in_segment(f, x0, x1): +def braid_in_segment(g, x0, x1): """ Return the braid formed by the `y` roots of ``f`` when `x` moves from ``x0`` to ``x1``. @@ -340,41 +372,78 @@ def braid_in_segment(f, x0, x1): sage: B.left_normal_form() # optional - sirocco (1, s5) """ - CC = ComplexField(64) - (x, y) = f.variables() + (x, y) = g.value().parent().gens() I = QQbar.gen() X0 = QQ(x0.real()) + I * QQ(x0.imag()) X1 = QQ(x1.real()) + I * QQ(x1.imag()) - F0 = QQbar[y](f(X0, y)) - y0s = F0.roots(multiplicities=False) - strands = [followstrand(f, x0, x1, CC(a)) for a in y0s] - complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands] + intervals = {} + precision = {} + y0s = [] + for (f, naux) in g: + if f.variables() == (y,): + F0 = QQbar[y](f.base_ring()[y](f)) + else: + F0 = QQbar[y](f(X0, y)) + y0sf = F0.roots(multiplicities=False) + y0s += list(y0sf) + precision[f]=53 + while True: + intervals[f] = [r.interval(ComplexIntervalField(precision[f])) for r in y0sf] + if not any([a.overlaps(b) for a,b in Subsets(intervals[f], 2)]): + break + precision[f] *= 2 + strands = [followstrand(f[0], [p[0] for p in g if p[0]!= f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] + complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) + y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] + + + CIF = ComplexIntervalField() + y0ints = QQbar[y](g.value()(X0,y)).roots(CIF, multiplicities=False) initialstrands = [] - y0aps = [c[0][1] for c in complexstrands] - used = [] + f = g.value() for y0ap in y0aps: - distances = [((y0ap - y0).norm(), y0) for y0 in y0s] - y0 = sorted(distances)[0][1] - if y0 in used: - raise ValueError("different roots are too close") - used.append(y0) - initialstrands.append([(0, y0), (1, y0ap)]) + dist, point = min([((y0ap-i.center()).abs(),i) for i in y0ints]) + diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) + y0api = y0ap + (dist+diam)*CIF((-1,1),(-1,1)) + newton = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api) + if newton in y0api and point in y0api: + initialstrands.append([(0, QQ(point.center().real()),QQ(point.center().imag())), (1, y0ap.real(), y0ap.imag())]) + else: + print(y0ap) + print(y0api) + print(point) + print(newton) + print(dist) + print(diam) + print(point in y0api) + print(newton in y0api) + y0api2 = y0ap + 0.00025*(dist)*CIF((-1,1),(-1,1)) + newton2 = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api2) + print(newton2 in y0api2) + raise ValueError("could not ensure that gluing of segments is correct") initialbraid = braid_from_piecewise(initialstrands) - F1 = QQbar[y](f(X1, y)) - y1s = F1.roots(multiplicities=False) + + y1aps = [QQ(c[-1][1])+QQbar.gen()*QQ(c[-1][2]) for c in complexstrands] + y1ints = QQbar[y](g.value()(X1,y)).roots(CIF, multiplicities=False) finalstrands = [] - y1aps = [c[-1][1] for c in complexstrands] - used = [] for y1ap in y1aps: - distances = [((y1ap - y1).norm(), y1) for y1 in y1s] - y1 = sorted(distances)[0][1] - if y1 in used: - raise ValueError("different roots are too close") - used.append(y1) - finalstrands.append([(0, y1ap), (1, y1)]) - finallbraid = braid_from_piecewise(finalstrands) - return initialbraid * centralbraid * finallbraid + dist, point = min([((y1ap-i.center()).abs(),i) for i in y1ints]) + diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) + y1api = y1ap + (dist+diam)*CIF((-1,1),(-1,1)) + newton = y1ap -f(X1,y).change_ring(CIF)(0,y1ap)/f.derivative(y)(x1,y).change_ring(CIF)(0,y1api) + if newton in y1api and point in y1api: + finalstrands.append([(0, y1ap.real(), y1ap.imag()), (1, QQ(point.center().real()),QQ(point.center().imag())) ]) + else: + print(y0ap) + print(y0api) + print(point) + print(newton) + raise ValueError("could not ensure that gluing of segments is correct") + finalbraid = braid_from_piecewise(finalstrands) + + + return initialbraid * centralbraid * finalbraid def fundamental_group(f, simplified=True, projective=False): @@ -438,7 +507,7 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ - (x, y) = f.variables() + (x, y) = f.parent().gens() F = f.base_ring() g = f.radical() d = g.degree(y) @@ -453,7 +522,8 @@ def fundamental_group(f, simplified=True, projective=False): rels = [] if projective: rels.append(prod(F.gen(i) for i in range(d))) - braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs]) + gfac = g.factor() + braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) b = braidcomputed[1] From 1bf7fba0167a8d33672fae2fd096314ecf917b64 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Thu, 20 May 2021 09:01:28 +0200 Subject: [PATCH 010/355] 30997: initial version --- src/sage/groups/braid.py | 64 +++++++++++++++++++++++++++++++++ src/sage/knots/link.py | 77 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 81d09d8e369..e4d0e69d4a4 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -1359,6 +1359,45 @@ def sliding_circuits(self): B = self.parent() return [[B._element_from_libbraiding(i) for i in s] for s in slc] + def mirror_image(self): + r""" + Return the image of ``self`` under the mirror involution (see + :meth:`BraidGroup_class.mirror_involution`). The link closure of + it is mirrored to the closure of ``self`` (see the example below + of a positive amphicheiral knot). + + EXAMPLES:: + + sage: B5 = BraidGroup(5) + sage: b = B5((-1, 2, -3, -1, -3, 4, 2, -3, 2, 4, 2, -3)) # closure K12a_427 + sage: bm = b.mirror_image(); bm + s0*s1^-1*s2*s0*s2*s3^-1*s1^-1*s2*s1^-1*s3^-1*s1^-1*s2 + sage: bm.is_conjugated(b) + True + sage: bm.is_conjugated(~b) + False + """ + return self.parent().mirror_involution()(self) + + def reverse(self): + r""" + Return the reverse of ``self`` obtained by reversing the order of the + generators in its word. This defines an anti-involution on the braid + group. The link closure of it has the reversed orientation (see the + example below of a non reversible knot). + + EXAMPLES:: + + sage: b = BraidGroup(3)((1, 1, -2, 1, -2, 1, -2, -2)) # closure K8_17 + sage: br = b.reverse(); br + s1^-1*(s1^-1*s0)^3*s0 + sage: br.is_conjugated(b) + False + """ + t = [i for i in self.Tietze()] + t.reverse() + return self.parent()(tuple(t)) + class BraidGroup_class(FiniteTypeArtinGroup): """ @@ -2137,6 +2176,31 @@ def _element_from_libbraiding(self, nf): from sage.misc.misc_c import prod return self.delta() ** nf[0][0] * prod(self(i) for i in nf[1:]) + def mirror_involution(self): + r""" + Return the mirror involution of ``self``. + + This automorphism maps a braid to another one by replacing each generator + in its word by the inverse. In general this is different from the inverse + of the braid since the order of the generators in the word is not reversed. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: mirr = B.mirror_involution() + sage: b = B((1,-2,-1,3,2,1)) + sage: bm = mirr(b); bm + s0^-1*s1*s0*s2^-1*s1^-1*s0^-1 + sage: bm == ~b + False + sage: bm.is_conjugated(b) + False + sage: bm.is_conjugated(~b) + True + """ + gens_mirr = [~g for g in self.gens()] + return self.hom(gens_mirr, check=False) + def BraidGroup(n=None, names='s'): """ diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 1587990aaf3..64888f8bf1d 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -362,6 +362,9 @@ def __init__(self, data): else: raise ValueError("invalid input: data must be either a list or a braid") + self._mirror = None # set on invocation of :meth:`mirror_image` + self._reverse = None # set on invocation of :meth:`reverse` + def arcs(self, presentation='pd'): r""" Return the arcs of ``self``. @@ -2234,9 +2237,23 @@ def mirror_image(self): K = Link([[[1,-2,3,-1,2,-3]],[1,1,1]]) K2 = K.mirror_image() sphinx_plot(K2.plot()) + + TESTS: + + check that :trac:`30997` is fixed:: + + sage: L = Link([[6, 2, 7, 1], [5, 13, 6, 12], [8, 3, 9, 4], + ....: [2, 13, 3, 14], [14, 8, 15, 7], [11, 17, 12, 16], + ....: [9, 18, 10, 11], [17, 10, 18, 5], [4, 16, 1, 15]]) # L9n25{0}{0} from KnotInfo + sage: Lmm = L.mirror_image().mirror_image() + sage: L == Lmm + True """ # Use the braid information if it is the shortest version # of what we have already computed + if self._mirror: + return self._mirror + if self._braid: lb = len(self._braid.Tietze()) @@ -2251,11 +2268,67 @@ def mirror_image(self): logc = float('inf') if lb <= logc and lb <= lpd: - return type(self)(~self._braid) + self._mirror = type(self)(self._braid.mirror_image()) + self._mirror._mirror = self + return self._mirror # Otherwise we fallback to the PD code pd = [[a[0], a[3], a[2], a[1]] for a in self.pd_code()] - return type(self)(pd) + self._mirror = type(self)(pd) + self._mirror._mirror = self + return self._mirror + + def reverse(self): + r""" + Return the reverse of ``self``. This is the link obtained from ``self`` + by reverting the orientation on all components. + + EXAMPLES:: + + sage: K3 = Knot([[5, 2, 4, 1], [3, 6, 2, 5], [1, 4, 6, 3]]) + sage: K3r = K3.reverse(); K3r.pd_code() + [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] + sage: K3 == K3r + True + + a non reversable knot:: + + sage: K8_17 = Knot([[6, 2, 7, 1], [14, 8, 15, 7], [8, 3, 9, 4], + ....: [2, 13, 3, 14], [12, 5, 13, 6], [4, 9, 5, 10], + ....: [16, 12, 1, 11], [10, 16, 11, 15]]) + sage: K8_17r = K8_17.reverse() + sage: b = K8_17.braid(); b + s0^2*s1^-1*(s1^-1*s0)^2*s1^-1 + sage: br = K8_17r.braid(); br + s0^-1*s1*s0^-2*s1^2*s0^-1*s1 + sage: b.is_conjugated(br) + False + sage: b == br.reverse() + False + sage: b.is_conjugated(br.reverse()) + True + sage: K8_17b = Link(b) + sage: K8_17br = K8_17b.reverse() + sage: bbr = K8_17br.braid(); bbr + (s1^-1*s0)^2*s1^-2*s0^2 + sage: br == bbr + False + sage: br.is_conjugated(bbr) + True + """ + if self._reverse: + return self._reverse + + if self._braid: + self._reverse = type(self)(self._braid.reverse()) + self._reverse._reverse = self + return self._reverse + + # Otherwise we fallback to the PD code + pd = [[a[2], a[3], a[0], a[1]] for a in self.pd_code()] + self._reverse = type(self)(pd) + self._reverse._reverse = self + return self._reverse def writhe(self): """ From 8f20e1f57a72710f819cb841fca30c1549d7d3d5 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 30 Jun 2021 12:42:54 +0200 Subject: [PATCH 011/355] Add braid monodromy --- src/sage/schemes/curves/zariski_vankampen.py | 631 ++++++++++++++++--- 1 file changed, 543 insertions(+), 88 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 36989d663e9..46cb5cf25b0 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -53,12 +53,19 @@ from sage.groups.free_group import FreeGroup from sage.misc.misc_c import prod from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfr import RealField from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation from sage.functions.generalized import sign from sage.combinat.subset import Subsets +from sage.geometry.voronoi_diagram import VoronoiDiagram +from sage.graphs.graph import Graph +from sage.misc.cachefunc import cached_function +from copy import deepcopy +roots_interval_cache = dict() + def braid_from_piecewise(strands): r""" Compute the braid corresponding to the piecewise linear curves strands. @@ -167,10 +174,10 @@ def discrim(f): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim sage: R. = QQ[] sage: f = (y^3 + x^3 - 1) * (x + y) - sage: discrim(f) # optional - sirocco + sage: discrim(f) [1, -0.500000000000000? - 0.866025403784439?*I, -0.500000000000000? + 0.866025403784439?*I] @@ -180,6 +187,62 @@ def discrim(f): poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) +@cached_function +def corrected_voronoi_diagram(points): + r""" + compute a Voronoi diagram of a set of points with rational coordinates, such + that the given points are granted to lie one in each bounded region. + + INPUT: + + - ``points`` -- a list of complex numbers. + + OUTPUT: + + A VoronoiDiagram constructed from rational approximations of the points, + with the guarantee that each bounded region contains exactly one of the + input points. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import corrected_voronoi_diagram + sage: points = (2, I, 0.000001, 0, 0.000001*I) + sage: V = corrected_voronoi_diagram(points) + sage: V + The Voronoi diagram of 9 points of dimension 2 in the Rational Field + sage: V.regions() + {P(-7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, -7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 1): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(0, 1/1000000): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 2 rays, + P(1/1000000, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} + + + """ + prec = 53 + point_coordinates = [(p.real(), p.imag()) for p in points] + while True: + RF = RealField(prec) + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))):p for p in point_coordinates} + added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 + configuration = list(apprpoints.keys())+[(added_points, 0), + (-added_points, 0), + (0, added_points), + (0, -added_points)] + V = VoronoiDiagram(configuration) + valid = True + for r in V.regions().items(): + if not r[1].rays() and not apprpoints[r[0].affine()] in r[1]: + prec += 53 + valid = False + break + if valid: + break + return V def segments(points): """ @@ -196,45 +259,42 @@ def segments(points): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim, segments # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim, segments sage: R. = QQ[] sage: f = y^3 + x^3 - 1 - sage: disc = discrim(f) # optional - sirocco - sage: segments(disc) # optional - sirocco # abs tol 1e-15 - [(-2.84740787203333 - 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (-2.84740787203333 + 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (2.50000000000000 + 2.50000000000000*I, - 1.26513881334184 + 2.19128470333546*I), - (2.50000000000000 + 2.50000000000000*I, - 2.50000000000000 - 2.50000000000000*I), - (1.26513881334184 + 2.19128470333546*I, 0.000000000000000), - (0.000000000000000, 1.26513881334184 - 2.19128470333546*I), - (2.50000000000000 - 2.50000000000000*I, - 1.26513881334184 - 2.19128470333546*I), - (-2.84740787203333 + 2.84740787203333*I, - 1.26513881334184 + 2.19128470333546*I), - (-2.14285714285714 + 1.11022302462516e-16*I, 0.000000000000000), - (-2.84740787203333 - 2.84740787203333*I, - 1.26513881334184 - 2.19128470333546*I)] + sage: disc = discrim(f) + sage: segments(disc) + [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -192951821525958031/90044183378780414), + (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, 5/2*I + 5/2), + (1/38590364305191606, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/90044183378780414, 1/38590364305191606), + (-192951821525958031/90044183378780414, + 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), + (1/38590364305191606, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (5/2*I + 5/2, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] """ - from numpy import array, vstack - from scipy.spatial import Voronoi - discpoints = array([(CC(a).real(), CC(a).imag()) for a in points]) - added_points = 3 * abs(discpoints).max() + 1.0 - configuration = vstack([discpoints, array([[added_points, 0], - [-added_points, 0], - [0, added_points], - [0, -added_points]])]) - V = Voronoi(configuration) - res = [] - for rv in V.ridge_vertices: - if -1 not in rv: - p1 = CC(list(V.vertices[rv[0]])) - p2 = CC(list(V.vertices[rv[1]])) - res.append((p1, p2)) - return res + V = corrected_voronoi_diagram(tuple(points)) + res = set([]) + for region in V.regions().values(): + if region.rays(): + continue + segments = region.facets() + for s in segments: + t = tuple((tuple(v.vector()) for v in s.vertices())) + if not t in res and not tuple(reversed(t)) in res: + res.add(t) + return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] + def followstrand(f, factors, x0, x1, y0a, prec=53): @@ -244,7 +304,8 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): INPUT: - - ``f`` -- a polynomial in two variables + - ``f`` -- ann irreducible polynomial in two variables + - ``factors`` -- a list of irreducible polynomials in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends - ``y0a`` -- an approximate solution of the polynomial `F(y) = f(x_0, y)` @@ -259,7 +320,8 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): is zero (or a good enough approximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and - no other root intersects it. + no other root of `f`, nor any root of the polynomials in `factors`, + intersects it. EXAMPLES:: @@ -268,10 +330,18 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) - sage: followstrand(f, x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + sage: followstrand(f, [], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] + sage: fup = f.subs({y:y-1/10}) + sage: fdown = f.subs({y:y+1/10}) + sage: followstrand(f, [fup, fdown], x0, x1, -1.0) + [(0.0, -1.0, 0.0), + (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), + (0.7651655429449553, -1.015686131039112, -0.25243563967299404), + (1.0, -1.026166099551513, -0.3276894025360433)] + """ if f.degree() == 1: CF = ComplexField(prec) @@ -327,6 +397,119 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): except Exception: return followstrand(f, factors, x0, x1, y0a, 2 * prec) +def newton(f, x0, i0): + r""" + Return the interval Newton operator. + + INPUT: + + - ``f``` -- a univariate polynomial + - ``x0`` -- a number + - ``I0`` -- an interval + + OUTPUT: + + The interval `x_0-\frac{f(x_0)}{f'(I_0)}` + + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import newton + sage: R. = QQbar[] + sage: f = x^3 + x + sage: x0 = 1/10 + sage: I0 = RIF((-1/5,1/5)) + sage: n = newton(f, x0, I0) + sage: n + 0.0? + sage: n.real().endpoints() + (-0.0147727272727274, 0.00982142857142862) + sage: n.imag().endpoints() + (0.000000000000000, -0.000000000000000) + + """ + return x0 - f(x0)/f.derivative()(i0) + +@parallel +def roots_interval(f, x0): + """ + Find disjoint intervals that isolate the roots of a polynomial for a fixed + value of the first variable. + + INPUT: + + - ``f`` -- a bivariate squarefree polynomial + - ``x0`` -- a value where the first coordinate will be fixed + + The intervals are taken as big as possible to be able to detect when two + approximate roots of `f(x_0, y)` correspond to the same exact root. + + The result is given as a dictionary, where the keys are approximations to the roots + with rational real and imaginary parts, and the values are intervals containing them. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: ri = roots_interval(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: [r.endpoints() for r in ri.values()] + [(0.566987298107781 - 0.433012701892219*I, + 1.43301270189222 + 0.433012701892219*I, + 0.566987298107781 + 0.433012701892219*I, + 1.43301270189222 - 0.433012701892219*I), + (-0.933012701892219 - 1.29903810567666*I, + -0.0669872981077806 - 0.433012701892219*I, + -0.933012701892219 - 0.433012701892219*I, + -0.0669872981077806 - 1.29903810567666*I), + (-0.933012701892219 + 0.433012701892219*I, + -0.0669872981077806 + 1.29903810567666*I, + -0.933012701892219 + 1.29903810567666*I, + -0.0669872981077806 + 0.433012701892219*I)] + + """ + F = f.base_ring() + x, y = f.parent().gens() + I = QQbar.gen() + fx = QQbar[y](f.subs({x:QQ(x0.real())+I*QQ(x0.imag())})) + roots = fx.roots(QQbar, multiplicities=False) + result = {} + for i in range(len(roots)): + r = roots[i] + prec = 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor = 4 + diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + envelop = diam*IF((-1,1),(-1,1)) + while not newton(fx, r, r+envelop) in r+envelop: + prec += 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor *=2 + diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + envelop = diam*IF((-1,1),(-1,1)) + qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) + if not qapr in r+envelop: + raise ValueError("Could not approximate roots with exact values") + result[qapr] = r+envelop + return result + +def roots_interval_cached(f, x0): + r""" + Cached version of :func:`roots_interval`. + """ + global roots_interval_cache + if (f,x0) in roots_interval_cache.keys(): + return roots_interval_cache[(f,x0)] + else: + result = roots_interval(f,x0) + roots_interval_cache[(f,x0)] = result + return result @parallel @@ -337,7 +520,7 @@ def braid_in_segment(g, x0, x1): INPUT: - - ``f`` -- a polynomial in two variables + - ``g`` -- a polynomial factorization in two variables - ``x0`` -- a complex number - ``x1`` -- a complex number @@ -352,7 +535,7 @@ def braid_in_segment(g, x0, x1): sage: f = x^2 + y^3 sage: x0 = CC(1,0) sage: x1 = CC(1, 0.5) - sage: braid_in_segment(f, x0, x1) # optional - sirocco + sage: braid_in_segment(f.factor(), x0, x1) # optional - sirocco s1 TESTS: @@ -368,9 +551,9 @@ def braid_in_segment(g, x0, x1): sage: g = f.subs({x: x + 2*y}) sage: p1 = QQbar(sqrt(-1/3)) sage: p2 = QQbar(1/2+sqrt(-1/3)/2) - sage: B = zvk.braid_in_segment(g,CC(p1),CC(p2)) # optional - sirocco - sage: B.left_normal_form() # optional - sirocco - (1, s5) + sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco + sage: B # optional - sirocco + s5*s3^-1 """ (x, y) = g.value().parent().gens() I = QQbar.gen() @@ -395,55 +578,322 @@ def braid_in_segment(g, x0, x1): strands = [followstrand(f[0], [p[0] for p in g if p[0]!= f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) + initialstrands = [] + finalstrands = [] + initialintervals = roots_interval_cached(g.value(), X0) + finalintervals = roots_interval_cached(g.value(), X1) + for cs in complexstrands: + ip = cs[0][1] + I*cs[0][2] + fp = cs[-1][1] + I*cs[-1][2] + for center,interval in initialintervals.items(): + if ip in interval: + initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) + for center,interval in finalintervals.items(): + if fp in interval: + finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] + initialbraid = braid_from_piecewise(initialstrands) + finalbraid = braid_from_piecewise(finalstrands) + return initialbraid * centralbraid * finalbraid - CIF = ComplexIntervalField() - y0ints = QQbar[y](g.value()(X0,y)).roots(CIF, multiplicities=False) - initialstrands = [] - f = g.value() - for y0ap in y0aps: - dist, point = min([((y0ap-i.center()).abs(),i) for i in y0ints]) - diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) - y0api = y0ap + (dist+diam)*CIF((-1,1),(-1,1)) - newton = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api) - if newton in y0api and point in y0api: - initialstrands.append([(0, QQ(point.center().real()),QQ(point.center().imag())), (1, y0ap.real(), y0ap.imag())]) - else: - print(y0ap) - print(y0api) - print(point) - print(newton) - print(dist) - print(diam) - print(point in y0api) - print(newton in y0api) - y0api2 = y0ap + 0.00025*(dist)*CIF((-1,1),(-1,1)) - newton2 = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api2) - print(newton2 in y0api2) - raise ValueError("could not ensure that gluing of segments is correct") - initialbraid = braid_from_piecewise(initialstrands) - y1aps = [QQ(c[-1][1])+QQbar.gen()*QQ(c[-1][2]) for c in complexstrands] - y1ints = QQbar[y](g.value()(X1,y)).roots(CIF, multiplicities=False) - finalstrands = [] - for y1ap in y1aps: - dist, point = min([((y1ap-i.center()).abs(),i) for i in y1ints]) - diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) - y1api = y1ap + (dist+diam)*CIF((-1,1),(-1,1)) - newton = y1ap -f(X1,y).change_ring(CIF)(0,y1ap)/f.derivative(y)(x1,y).change_ring(CIF)(0,y1api) - if newton in y1api and point in y1api: - finalstrands.append([(0, y1ap.real(), y1ap.imag()), (1, QQ(point.center().real()),QQ(point.center().imag())) ]) + +def orient_circuit(circuit): + r""" + reverses a circuit if it goes clockwise + + INPUT: + + - `circuit` -- a circuit in the graph of a Voronoi Diagram, given + by a list of edges + + OUTPUT: The same circuit if it goes counterclockwise, and its reverse otherwise + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import orient_circuit + sage: points = [(-4, 0), (4, 0), (0, 4), (0, -4), (0, 0)] + sage: V = VoronoiDiagram(points) + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + sage: E.vertices() + [A vertex at (-2, -2), + A vertex at (-2, 2), + A vertex at (2, -2), + A vertex at (2, 2)] + sage: cir = E.eulerian_circuit() + sage: cir + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: orient_circuit(cir) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: cirinv = list(reversed([(c[1],c[0],c[2]) for c in cir])) + sage: cirinv + [(A vertex at (-2, -2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (-2, -2), None)] + sage: orient_circuit(cirinv) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + + """ + prec = 53 + vectors = [v[1].vector()-v[0].vector() for v in circuit] + while True: + CIF = ComplexIntervalField(prec) + totalangle = sum((CIF(*vectors[i])/CIF(*vectors[i-1])).argument() for i in range(len(vectors))) + if totalangle < 0: + return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) + elif totalangle > 0: + return circuit else: - print(y0ap) - print(y0api) - print(point) - print(newton) - raise ValueError("could not ensure that gluing of segments is correct") - finalbraid = braid_from_piecewise(finalstrands) + prec *= 2 +def geometric_basis(G, E, p): + r""" + Return a geometric basis, based on a vertex. + + INPUT: + + - ``G`` -- The graph of the bounded regions of a Voronoi Diagram + + - ``E`` -- The subgraph of `G` formed by the edges that touch an unbounded + region + + - ``p`` -- A vertex of `E` + + OUTPUT: A geometric basis. It is formed by a list of sequences of paths. + Each path is a list of vertices, that form a closed path in `G`, based at + `p`, that goes to a region, surrounds it, and comes back by the same path it + came. The concatenation of all these paths is equivalent to `E`. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import geometric_basis + sage: points = [(-3,0),(3,0),(0,3),(0,-3)]+ [(0,0),(0,-1),(0,1),(1,0),(-1,0)] + sage: V = VoronoiDiagram(points) + sage: G = Graph() + sage: for reg in V.regions().values(): + ....: G = G.union(reg.vertex_graph()) + ....: + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + ....: + sage: p = E.vertices()[0] + sage: geometric_basis(G, E, p) + [[A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (2, 2), + A vertex at (1/2, 1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (1/2, 1/2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (1/2, 1/2), + A vertex at (2, 2), + A vertex at (-2, 2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (-2, 2), + A vertex at (-2, -2)]] + + """ + EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] + i = EC.index(p) + EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p + if len(G.edges()) == len(E.edges()): + if E.is_cycle(): + return [EC] + + I = Graph() + for e in G.edges(): + if not E.has_edge(e): + I.add_edge(e) # interior graph + + #treat the case where I is empty + if not I.vertices(): + for v in E.vertices(): + if len(E.neighbors(v))>2: + I.add_vertex(v) + + for i in range(len(EC)): #q and r are the points we will cut through + + if EC[i] in I.vertices(): + q = EC[i] + connecting_path = EC[:i] + break + elif EC[-i] in I.vertices(): + q = EC[-i] + connecting_path = list(reversed(EC[-i:])) + break + distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] + r = max(distancequotients)[1] + cutpath = I.shortest_path(q, r) + + Gcut = deepcopy(G) + Ecut = deepcopy(E) + Ecut.delete_vertices([q,r]) + Gcut.delete_vertices(cutpath) + + #I think this cannot happen, but just in case, we check it to raise + # an error instead of giving a wrong answer + if Gcut.connected_components_number() != 2: + raise ValueError("can't compute a correct path") + G1, G2 = Gcut.connected_components_subgraphs() + + for v in cutpath: + neighs = G.neighbors(v) + for n in neighs: + if n in G1.vertices()+cutpath: + G1.add_edge(v,n,None) + if n in G2.vertices()+cutpath: + G2.add_edge(v,n,None) + + if EC[EC.index(q)+1] in G2.vertices(): + G1, G2 = G2,G1 + + E1, E2 = Ecut.connected_components_subgraphs() + if EC[EC.index(q)+1] in E2.vertices(): + E1, E2 = E2, E1 + + for i in range(len(cutpath)-1): + E1.add_edge(cutpath[i], cutpath[i+1], None) + E2.add_edge(cutpath[i], cutpath[i+1], None) + + for v in [q,r]: + for n in E.neighbors(v): + if n in E1.vertices(): + E1.add_edge(v, n, None) + if n in E2.vertices(): + E2.add_edge(v,n, None) + + gb1 = geometric_basis(G1, E1, q) + gb2 = geometric_basis(G2, E2, q) + + resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1+gb2] + for r in resul: + i = 0 + while i< len(r)-2: + if r[i] == r[i+2]: + r.pop(i) + r.pop(i) + if i>0: + i -=1 + else: + i+=1 + return resul + +def braid_monodromy(f): + r""" + Compute the braid monodromy of a projection of the curve defined by a polynomial + + INPUT: + + - ``f`` -- a polynomial with two variables, over a number field with an embedding + in the complex numbers. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of `f`. + + NOTE: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy + sage: R. = QQ[] + sage: f = (x^2-y^3)*(x+3*y-5) + sage: braid_monodromy(f) + [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, + s2^2] + + """ + global roots_interval_cache + (x, y) = f.parent().gens() + F = f.base_ring() + g = f.radical() + d = g.degree(y) + while not g.coefficient(y**d) in F: + g = g.subs({x: x + y}) + d = g.degree(y) + disc = discrim(g) + segs = segments(disc) + V = corrected_voronoi_diagram(tuple(disc)) + G = Graph() + for reg in V.regions().values(): + G = G.union(reg.vertex_graph()) + E = Graph() + for reg in V.regions().values(): + if reg.rays() or reg.lines(): + E = E.union(reg.vertex_graph()) + p = E.vertices()[0] + geombasis = geometric_basis(G, E, p) + vertices = list(set(flatten(segs))) + newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + rootsintervals = list(roots_interval([(g, v) for v in newvertices])) + for r in rootsintervals: + roots_interval_cache[r[0][0]] = r[1] + gfac = g.factor() + braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) + segsbraids = dict() + for braidcomputed in braidscomputed: + seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) + beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) + endseg = (QQ(seg[1].real()), QQ(seg[1].imag())) + b = braidcomputed[1] + segsbraids[(beginseg, endseg)] = b + segsbraids[(endseg, beginseg)] = b.inverse() + B = b.parent() + result = [] + for path in geombasis: + braidpath = B.one() + for i in range(len(path)-1): + x0 = tuple(path[i].vector()) + x1 = tuple(path[i+1].vector()) + braidpath = braidpath * segsbraids[(x0, x1)] + result.append(braidpath) + return result - return initialbraid * centralbraid * finalbraid def fundamental_group(f, simplified=True, projective=False): @@ -507,6 +957,7 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ + global roots_interval_cache (x, y) = f.parent().gens() F = f.base_ring() g = f.radical() @@ -517,6 +968,10 @@ def fundamental_group(f, simplified=True, projective=False): disc = discrim(g) segs = segments(disc) vertices = list(set(flatten(segs))) + newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + rootsintervals = list(roots_interval([(g, v) for v in newvertices])) + for r in rootsintervals: + roots_interval_cache[r[0][0]] = r[1] Faux = FreeGroup(d) F = FreeGroup(d * len(vertices)) rels = [] From f7c14913d2690e0b4e40c6936c19d49f9e2856d5 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 30 Jun 2021 12:48:42 +0200 Subject: [PATCH 012/355] update to newer sirocco version --- build/pkgs/sirocco/checksums.ini | 6 +++--- build/pkgs/sirocco/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sirocco/checksums.ini b/build/pkgs/sirocco/checksums.ini index 672a9235128..2f0181ec823 100644 --- a/build/pkgs/sirocco/checksums.ini +++ b/build/pkgs/sirocco/checksums.ini @@ -1,5 +1,5 @@ tarball=libsirocco-VERSION.tar.gz -sha1=96e16ce48d6d320895b8d1ee8e07b738765f5e8d -md5=44c67dccf82fe3e2c61b5b7a51543718 -cksum=596947378 +sha1=23311c0944f0c128b493589c1575476cf88177b6 +md5=e86b1dc9b72aee0d80186be7f49c295e +cksum=784051898 upstream_url=https://github.com/miguelmarco/SIROCCO2/releases/download/VERSION/libsirocco-VERSION.tar.gz diff --git a/build/pkgs/sirocco/package-version.txt b/build/pkgs/sirocco/package-version.txt index e9307ca5751..7ec1d6db408 100644 --- a/build/pkgs/sirocco/package-version.txt +++ b/build/pkgs/sirocco/package-version.txt @@ -1 +1 @@ -2.0.2 +2.1.0 From d761ca3a608244f35d0c6fa08478c6675a3a7608 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 1 Jul 2021 14:17:51 +0200 Subject: [PATCH 013/355] Address reveiwer's corrections, and add method in affine_curve --- src/sage/schemes/curves/affine_curve.py | 35 +++++++++++++ src/sage/schemes/curves/zariski_vankampen.py | 55 ++++++++------------ 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 33f69326728..7a1ec8c1191 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1738,6 +1738,41 @@ def fundamental_group(self): f = self.defining_polynomial() return fundamental_group(f, projective=False) + def braid_monodromy(self): + r""" + Compute the braid monodromy of a projection of the curve. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of `self`. + + NOTE: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + A. = AffineSpace(QQ, 2) + sage: C = A.curve((x^2-y^3)*(x+3*y-5)) + sage: C.braid_monodromy() # optional - sirocco + [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, + s2^2] + """ + from sage.schemes.curves.zariski_vankampen import braid_monodromy + F = self.base_ring() + from sage.rings.qqbar import QQbar + if QQbar.coerce_map_from(F) is None: + raise NotImplementedError("the base field must have an embedding" + " to the algebraic field") + f = self.defining_polynomial() + return braid_monodromy(f) + + def riemann_surface(self,**kwargs): r"""Return the complex riemann surface determined by this curve diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 46cb5cf25b0..4b7925332f4 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -155,7 +155,6 @@ def sgn(x, y): B = BraidGroup(len(L)) return B(braid) - def discrim(f): r""" Return the points in the discriminant of ``f``. @@ -190,12 +189,12 @@ def discrim(f): @cached_function def corrected_voronoi_diagram(points): r""" - compute a Voronoi diagram of a set of points with rational coordinates, such + Compute a Voronoi diagram of a set of points with rational coordinates, such that the given points are granted to lie one in each bounded region. INPUT: - - ``points`` -- a list of complex numbers. + - ``points`` -- a list of complex numbers OUTPUT: @@ -221,7 +220,6 @@ def corrected_voronoi_diagram(points): P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} - """ prec = 53 point_coordinates = [(p.real(), p.imag()) for p in points] @@ -295,8 +293,6 @@ def segments(points): res.add(t) return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] - - def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation @@ -304,7 +300,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): INPUT: - - ``f`` -- ann irreducible polynomial in two variables + - ``f`` -- an irreducible polynomial in two variables - ``factors`` -- a list of irreducible polynomials in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends @@ -320,7 +316,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): is zero (or a good enough approximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and - no other root of `f`, nor any root of the polynomials in `factors`, + no other root of ``f``, nor any root of the polynomials in ``factors``, intersects it. EXAMPLES:: @@ -554,6 +550,7 @@ def braid_in_segment(g, x0, x1): sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco sage: B # optional - sirocco s5*s3^-1 + """ (x, y) = g.value().parent().gens() I = QQbar.gen() @@ -597,18 +594,18 @@ def braid_in_segment(g, x0, x1): return initialbraid * centralbraid * finalbraid - - def orient_circuit(circuit): r""" - reverses a circuit if it goes clockwise + Reverses a circuit if it goes clockwise; otherwise leaves it unchanged. INPUT: - - `circuit` -- a circuit in the graph of a Voronoi Diagram, given + - ``circuit`` -- a circuit in the graph of a Voronoi Diagram, given by a list of edges - OUTPUT: The same circuit if it goes counterclockwise, and its reverse otherwise + OUTPUT: + + The same circuit if it goes counterclockwise, and its reverse otherwise EXAMPLES:: @@ -666,12 +663,12 @@ def geometric_basis(G, E, p): INPUT: - - ``G`` -- The graph of the bounded regions of a Voronoi Diagram + - ``G`` -- the graph of the bounded regions of a Voronoi Diagram - - ``E`` -- The subgraph of `G` formed by the edges that touch an unbounded + - ``E`` -- the subgraph of ``G`` formed by the edges that touch an unbounded region - - ``p`` -- A vertex of `E` + - ``p`` -- a vertex of ``E`` OUTPUT: A geometric basis. It is formed by a list of sequences of paths. Each path is a list of vertices, that form a closed path in `G`, based at @@ -737,12 +734,10 @@ def geometric_basis(G, E, p): if len(G.edges()) == len(E.edges()): if E.is_cycle(): return [EC] - I = Graph() for e in G.edges(): if not E.has_edge(e): I.add_edge(e) # interior graph - #treat the case where I is empty if not I.vertices(): for v in E.vertices(): @@ -762,16 +757,14 @@ def geometric_basis(G, E, p): distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) - Gcut = deepcopy(G) Ecut = deepcopy(E) Ecut.delete_vertices([q,r]) Gcut.delete_vertices(cutpath) - #I think this cannot happen, but just in case, we check it to raise # an error instead of giving a wrong answer if Gcut.connected_components_number() != 2: - raise ValueError("can't compute a correct path") + raise ValueError("unable to compute a correct path") G1, G2 = Gcut.connected_components_subgraphs() for v in cutpath: @@ -823,25 +816,25 @@ def braid_monodromy(f): INPUT: - ``f`` -- a polynomial with two variables, over a number field with an embedding - in the complex numbers. + in the complex numbers. OUTPUT: A list of braids. The braids correspond to paths based in the same point; each of this paths is the conjugated of a loop around one of the points - in the discriminant of the projection of `f`. + in the discriminant of the projection of ``f``. - NOTE: + .. NOTE:: - The projection over the `x` axis is used if there are no vertical asymptotes. - Otherwise, a linear change of variables is done to fall into the previous case. + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy sage: R. = QQ[] sage: f = (x^2-y^3)*(x+3*y-5) - sage: braid_monodromy(f) + sage: braid_monodromy(f) # optional - sirocco [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, @@ -866,10 +859,10 @@ def braid_monodromy(f): for reg in V.regions().values(): if reg.rays() or reg.lines(): E = E.union(reg.vertex_graph()) - p = E.vertices()[0] + p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] rootsintervals = list(roots_interval([(g, v) for v in newvertices])) for r in rootsintervals: roots_interval_cache[r[0][0]] = r[1] @@ -894,8 +887,6 @@ def braid_monodromy(f): result.append(braidpath) return result - - def fundamental_group(f, simplified=True, projective=False): r""" Return a presentation of the fundamental group of the complement of @@ -968,7 +959,7 @@ def fundamental_group(f, simplified=True, projective=False): disc = discrim(g) segs = segments(disc) vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] rootsintervals = list(roots_interval([(g, v) for v in newvertices])) for r in rootsintervals: roots_interval_cache[r[0][0]] = r[1] From c7edf9563699734f832e26fd30002d7c4b1ac41a Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 1 Jul 2021 14:46:13 +0200 Subject: [PATCH 014/355] Fix some doctests --- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/zariski_vankampen.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 7a1ec8c1191..7bfe483d884 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1755,7 +1755,7 @@ def braid_monodromy(self): EXAMPLES:: - A. = AffineSpace(QQ, 2) + sage: A. = AffineSpace(QQ, 2) sage: C = A.curve((x^2-y^3)*(x+3*y-5)) sage: C.braid_monodromy() # optional - sirocco [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 4b7925332f4..a737717664f 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -498,6 +498,23 @@ def roots_interval(f, x0): def roots_interval_cached(f, x0): r""" Cached version of :func:`roots_interval`. + + + TESTS:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: (f, 1) in roots_interval_cache + False + sage: ri = roots_interval_cached(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: (f, 1) in roots_interval_cache + True + """ global roots_interval_cache if (f,x0) in roots_interval_cache.keys(): From 9205fa247e8b337c1e9d17bb7a32713a434c0b27 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 5 Jul 2021 13:32:31 +0200 Subject: [PATCH 015/355] Several fixes Correct some bugs Clean fundamental group to avoid code duplication Fix and add doctest --- src/sage/libs/sirocco.pyx | 59 ++++++++++++ src/sage/schemes/curves/affine_curve.py | 9 +- src/sage/schemes/curves/zariski_vankampen.py | 98 +++++++++----------- 3 files changed, 106 insertions(+), 60 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 9d0ad0b0230..165ecab8680 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -35,6 +35,17 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 - A extra argument is needed, indicating the bits of precision used in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp(2, pol, RR(0), RR(0), 53) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + """ cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) cdef mpfr_t* rop @@ -85,6 +96,24 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum - A extra argument is needed, indicating the bits of precision used in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp_comps + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp_comps(2, pol, RR(0), RR(0), 53, [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.125000000000000, -0.0156250000000000, 0.000000000000000), + (0.250000000000000, -0.0625000000000000, 0.000000000000000), + (0.375000000000000, -0.140625000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (0.625000000000000, -0.390625000000000, 0.000000000000000), + (0.750000000000000, -0.562500000000000, 0.000000000000000), + (0.875000000000000, -0.765625000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + """ cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) @@ -164,6 +193,18 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): A list of tuples. Each tuple represents the `x` value (between 0 and 1) and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath(2, pol, RR(0), RR(0)) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.3535533905932738, -0.12500000000000003, 0.0), + (0.7071067811865476, -0.5000000000000001, 0.0), + (1.0, -1.0, 0.0)] + """ cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) @@ -207,6 +248,24 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li A list of tuples. Each tuple represents the `x` value (between 0 and 1) and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_comps + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_comps(2, pol, RR(0), RR(0), [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.125, -0.015625, 0.0), + (0.25, -0.0625, 0.0), + (0.375, -0.140625, 0.0), + (0.5, -0.25, 0.0), + (0.625, -0.390625, 0.0), + (0.75, -0.5625, 0.0), + (0.875, -0.765625, 0.0), + (1.0, -1.0, 0.0)] + """ diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 7bfe483d884..c7cbb696f62 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1758,10 +1758,11 @@ def braid_monodromy(self): sage: A. = AffineSpace(QQ, 2) sage: C = A.curve((x^2-y^3)*(x+3*y-5)) sage: C.braid_monodromy() # optional - sirocco - [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, - s2^2] + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] + """ from sage.schemes.curves.zariski_vankampen import braid_monodromy F = self.base_ring() diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index a737717664f..68aa6a60027 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -16,10 +16,6 @@ braids over this paths gives relations between these generators. This big group presentation is simplified at the end. -.. TODO:: - - Implement the complete braid monodromy approach. - AUTHORS: - Miguel Marco (2015-09-30): Initial version @@ -61,7 +57,7 @@ from sage.geometry.voronoi_diagram import VoronoiDiagram from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_function -from copy import deepcopy +from copy import copy roots_interval_cache = dict() @@ -599,12 +595,24 @@ def braid_in_segment(g, x0, x1): for cs in complexstrands: ip = cs[0][1] + I*cs[0][2] fp = cs[-1][1] + I*cs[-1][2] + matched = 0 for center,interval in initialintervals.items(): if ip in interval: initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) + matched += 1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") + matched = 0 for center,interval in finalintervals.items(): if fp in interval: finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) + matched +=1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] initialbraid = braid_from_piecewise(initialstrands) finalbraid = braid_from_piecewise(finalstrands) @@ -774,8 +782,8 @@ def geometric_basis(G, E, p): distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) - Gcut = deepcopy(G) - Ecut = deepcopy(E) + Gcut = copy(G) + Ecut = copy(E) Ecut.delete_vertices([q,r]) Gcut.delete_vertices(cutpath) #I think this cannot happen, but just in case, we check it to raise @@ -852,10 +860,10 @@ def braid_monodromy(f): sage: R. = QQ[] sage: f = (x^2-y^3)*(x+3*y-5) sage: braid_monodromy(f) # optional - sirocco - [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, - s2^2] + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] """ global roots_interval_cache @@ -867,7 +875,6 @@ def braid_monodromy(f): g = g.subs({x: x + y}) d = g.degree(y) disc = discrim(g) - segs = segments(disc) V = corrected_voronoi_diagram(tuple(disc)) G = Graph() for reg in V.regions().values(): @@ -878,13 +885,23 @@ def braid_monodromy(f): E = E.union(reg.vertex_graph()) p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) + segs = set([]) + for p in geombasis: + for s in zip(p[:-1], p[1:]): + if (s[1], s[0]) not in segs: + segs.add((s[0], s[1])) + I = QQbar.gen() + segs = [(a[0]+I*a[1], b[0]+I*b[1]) for (a, b) in segs] vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] - rootsintervals = list(roots_interval([(g, v) for v in newvertices])) - for r in rootsintervals: - roots_interval_cache[r[0][0]] = r[1] + noncachedverts = [(g, v) for v in vertices if (g, v) not in roots_interval_cache] + for noncachedvert in roots_interval(noncachedverts): + roots_interval_cache[noncachedvert[0][0]] = noncachedvert[1] + rootsintervals = [roots_interval_cached(g, v) for v in vertices] gfac = g.factor() - braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) + try: + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) + except ChildProcessError: # hack to deal with random fails first time + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) segsbraids = dict() for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) @@ -922,10 +939,7 @@ def fundamental_group(f, simplified=True, projective=False): of the curve will be computed, otherwise, the fundamental group of the complement in the affine plane will be computed - If ``simplified`` is ``False``, the returned presentation has as - many generators as degree of the polynomial times the points in the - base used to create the segments that surround the discriminant. In - this case, the generators are granted to be meridians of the curve. + If ``simplified`` is ``False``, a Zariski-VanKampen presentation is returned. OUTPUT: @@ -965,41 +979,13 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ - global roots_interval_cache - (x, y) = f.parent().gens() - F = f.base_ring() - g = f.radical() - d = g.degree(y) - while not g.coefficient(y**d) in F or (projective and g.total_degree() > d): - g = g.subs({x: x + y}) - d = g.degree(y) - disc = discrim(g) - segs = segments(disc) - vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] - rootsintervals = list(roots_interval([(g, v) for v in newvertices])) - for r in rootsintervals: - roots_interval_cache[r[0][0]] = r[1] - Faux = FreeGroup(d) - F = FreeGroup(d * len(vertices)) - rels = [] + bm = braid_monodromy(f) + n = bm[0].parent().strands() + F = FreeGroup(n) + R = [x*b/x for x in F.gens() for b in bm] if projective: - rels.append(prod(F.gen(i) for i in range(d))) - gfac = g.factor() - braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) - for braidcomputed in braidscomputed: - seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) - b = braidcomputed[1] - i = vertices.index(seg[0]) - j = vertices.index(seg[1]) - for k in range(d): - el1 = Faux([k + 1]) * b.inverse() - el2 = k + 1 - w1 = F([sign(a) * d * i + a for a in el1.Tietze()]) - w2 = F([d * j + el2]) - rels.append(w1 / w2) - G = F / rels + R.append(prod(F.gens())) + G = F/R if simplified: return G.simplified() - else: - return G + return G From 98c2ffd75c16e5bc8266405911f532141165feb3 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 23 Nov 2020 14:12:24 +0100 Subject: [PATCH 016/355] Add interface to new sirocco functions --- src/sage/libs/sirocco.pyx | 120 +++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 7ab52c7915f..4634899ab23 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -23,7 +23,8 @@ from sage.rings.real_mpfr import RealField cdef extern from "sirocco.h": mpfr_t* homotopyPath_mp(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec) double* homotopyPath(int degree, double *_coef, double _y0R, double _y0I) - + mpfr_t* homotopyPath_mp_comps(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec, int nothercomps, int *degreescomps, mpfr_t *_coefscomps) + double* homotopyPath_comps(int degree, double *_coef, double _y0R, double _y0I, int nothercomps, int *degreescomps, double *_coefscomps) cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0i, int prec): @@ -76,6 +77,71 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 free(rop) return l +cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNumber y0i, int prec, list otherdegs, list othercoefs): + """ + Mimics :func:`contpath`, but with the following differences: + + - The floating point numbers can be arbitrary precision RealNumbers. + + - A extra argument is needed, indicating the bits of precision used + in the computations. + """ + cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) + cdef mpfr_t* cothercoefs = check_allocarray(len(othercoefs), sizeof(mpfr_t)) + cdef int* cotherdegs = check_allocarray(len(otherdegs), sizeof(int)) + cdef mpfr_t* rop + cdef int i, j + cdef mpfr_t y0R + cdef mpfr_t y0I + + for j in range(len(values)): + mpfr_init2(cvalues[j], prec) + mpfr_set(cvalues[j], (values[j]).value, MPFR_RNDN) + + for j in range(len(othercoefs)): + mpfr_init2(cothercoefs[j], prec) + mpfr_set(cothercoefs[j], (othercoefs[j]).value, MPFR_RNDN) + + for j in range(len(otherdegs)): + cotherdegs[j] = int(otherdegs[j]) + + + sig_on() + mpfr_init2(y0R, prec) + mpfr_set(y0R, (y0r).value, MPFR_RNDN) + mpfr_init2(y0I, prec) + mpfr_set(y0I, (y0i).value, MPFR_RNDN) + rop = homotopyPath_mp_comps(deg, cvalues, y0R, y0I, prec, int(len(otherdegs)), cotherdegs, cothercoefs) + sig_off() + + for j in range(len(values)): + mpfr_clear(cvalues[j]) + free(cvalues) + + for j in range(len(othercoefs)): + mpfr_clear(cothercoefs[j]) + free(cothercoefs) + free(cotherdegs) + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + + cdef int n = mpfr_get_si(rop[0], MPFR_RNDN) + cdef list l = [] + cdef list inner + cdef RealNumber RN + field = RealField(prec) + for i in range(n): + inner = [] + for j in range(3*i+1, 3*(i+1)+1): + RN = RealNumber.__new__(RealNumber, field) + mpfr_set(RN.value, rop[j], MPFR_RNDN) + mpfr_clear(rop[j]) + inner.append(RN) + l.append(tuple(inner)) + free(rop) + return l + + cpdef list[list] contpath(int deg, list values, double y0r, double y0i): """ INPUT: @@ -119,3 +185,55 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): free(c_values) return l +cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, list otherdegrees, list othercoefs): + """ + INPUT: + + - An integer, representing the degree of the polynomial + + - A list of floating point numbers. Each four consecutive elements + of this list represent the interval corresponding to a coefficient. + Coefficients are listed in increasing deglex order, and inside each + coefficients, the four numbers represent the lower real, upper real, + lower imaginary and real imaginary limits of the interval. + + - A float representing the real part of the initial root approximation + + - A float representing the imaginary part of the initial root. + + OUTPUT: + + A list of tuples. Each tuple represents the `x` value (between 0 and 1) + and the real and imaginary parts of the `y` value of a vertex in + the piecewise linear approximation of the path tracked by the root. + """ + cdef double* rop + cdef double* c_values = check_allocarray(len(values), sizeof(double)) + cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) + cdef double* c_othercoefs = check_allocarray(len(othercoefs), sizeof(double)) + cdef int clen = len(values) + cdef int i + for i,v in enumerate(values): + c_values[i] = values[i] + + for i,v in enumerate(otherdegrees): + c_otherdegrees[i] = otherdegrees[i] + for i,v in enumerate(othercoefs): + c_othercoefs[i] = othercoefs[i] + + cdef double y0R = y0r + cdef double y0I = y0i + sig_on() + rop = homotopyPath_comps(deg, c_values, y0R, y0I, int(len(otherdegrees)), c_otherdegrees, c_othercoefs) + sig_off() + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + cdef int n = int(rop[0]) + cdef list l = [0] * n + for i in range(n): + l[i] = (rop[3*i+1], rop[3*i+2], rop[3*i+3]) + free(rop) + free(c_values) + free(c_otherdegrees) + free(c_othercoefs) + return l From 358e6d6057507bf0b4b4b5b439200fcc7f0b5ad6 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 12 Mar 2021 00:22:16 +0100 Subject: [PATCH 017/355] partial reqrite for the new sirocco version --- src/sage/libs/sirocco.pyx | 4 + src/sage/schemes/curves/zariski_vankampen.py | 174 +++++++++++++------ 2 files changed, 126 insertions(+), 52 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 4634899ab23..9d0ad0b0230 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -86,6 +86,7 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum - A extra argument is needed, indicating the bits of precision used in the computations. """ + cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) cdef mpfr_t* cothercoefs = check_allocarray(len(othercoefs), sizeof(mpfr_t)) cdef int* cotherdegs = check_allocarray(len(otherdegs), sizeof(int)) @@ -207,6 +208,8 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. """ + + cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) @@ -237,3 +240,4 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li free(c_otherdegrees) free(c_othercoefs) return l + diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 96d456e7c18..6608fc7bf8e 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -55,6 +55,7 @@ from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation from sage.functions.generalized import sign +from sage.combinat.subset import Subsets def braid_from_piecewise(strands): @@ -63,8 +64,8 @@ def braid_from_piecewise(strands): INPUT: - - ``strands`` -- a list of lists of tuples ``(t, c)``, where ``t`` - is a number between 0 and 1, and ``c`` is a complex number + - ``strands`` -- a list of lists of tuples ``(t, c1, c2)``, where ``t`` + is a number between 0 and 1, and ``c1`` and ``c2`` are rationals or algebraic reals. OUTPUT: @@ -73,34 +74,36 @@ def braid_from_piecewise(strands): EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco - sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)], - ....: [(0, -1), (0.5, -I), (1, 1)], - ....: [(0, 1), (0.5, 1 + I), (1, I)]] + sage: paths = [[(0, 0, 1), (0.2, -1, -0.5), (0.8, -1, 0), (1, 0, -1)], + ....: [(0, -1, 0), (0.5, 0, -1), (1, 1, 0)], + ....: [(0, 1, 0), (0.5, 1, 1), (1, 0, 1)]] sage: braid_from_piecewise(paths) # optional - sirocco s0*s1 """ L = strands i = min(val[1][0] for val in L) - totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L] + totalpoints = [[[a[0][1], a[0][2]]] for a in L] indices = [1 for a in range(len(L))] while i < 1: for j, val in enumerate(L): if val[indices[j]][0] > i: - xaux = val[indices[j] - 1][1] - yaux = val[indices[j]][1] + xauxr = val[indices[j] - 1][1] + xauxi = val[indices[j] - 1][2] + yauxr = val[indices[j]][1] + yauxi = val[indices[j]][2] aaux = val[indices[j] - 1][0] baux = val[indices[j]][0] - interpola = xaux + (yaux - xaux) * (i - aaux) / (baux - aaux) - totalpoints[j].append([interpola.real(), interpola.imag()]) + interpolar = xauxr + (yauxr - xauxr) * (i - aaux) / (baux - aaux) + interpolai = xauxi + (yauxi - xauxi) * (i - aaux) / (baux - aaux) + totalpoints[j].append([interpolar, interpolai]) else: - totalpoints[j].append([val[indices[j]][1].real(), - val[indices[j]][1].imag()]) + totalpoints[j].append([val[indices[j]][1], + val[indices[j]][2]]) indices[j] = indices[j] + 1 i = min(val[indices[k]][0] for k, val in enumerate(L)) for j, val in enumerate(L): - totalpoints[j].append([val[-1][1].real(), val[-1][1].imag()]) - + totalpoints[j].append([val[-1][1], val[-1][2]]) braid = [] G = SymmetricGroup(len(totalpoints)) @@ -121,7 +124,7 @@ def sgn(x, y): for j in range(len(l2)): for k in range(j): if l2[j] < l2[k]: - t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0]) + t = (l1[j][0] - l1[k][0])/((l2[k][0]-l2[j][0]) + (l1[j][0] - l1[k][0])) s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1]) cruces.append([t, k, j, s]) if cruces: @@ -171,9 +174,9 @@ def discrim(f): -0.500000000000000? - 0.866025403784439?*I, -0.500000000000000? + 0.866025403784439?*I] """ - x, y = f.variables() + x, y = f.parent().gens() F = f.base_ring() - poly = F[x](f.discriminant(y).resultant(f, y)).radical() + poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) @@ -233,7 +236,7 @@ def segments(points): return res -def followstrand(f, x0, x1, y0a, prec=53): +def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation of the root ``y0a`` from ``x0`` to ``x1``. @@ -269,10 +272,18 @@ def followstrand(f, x0, x1, y0a, prec=53): (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] """ + if f.degree() == 1: + CF = ComplexField(prec) + g = f.change_ring(CF) + (x, y) = g.parent().gens() + y0 = CF[y](g.subs({x: x0})).roots()[0][0] + y1 = CF[y](g.subs({x: x1})).roots()[0][0] + res = [(0.0, y0.real(), y0.imag()), (1.0, y1.real(), y1.imag())] + return res CIF = ComplexIntervalField(prec) CC = ComplexField(prec) G = f.change_ring(QQbar).change_ring(CIF) - (x, y) = G.variables() + (x, y) = G.parent().gens() g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) coefs = [] deg = g.total_degree() @@ -285,19 +296,40 @@ def followstrand(f, x0, x1, y0a, prec=53): coefs += list(ci.endpoints()) yr = CC(y0a).real() yi = CC(y0a).imag() - from sage.libs.sirocco import contpath, contpath_mp + coefsfactors = [] + degsfactors = [] + for fc in factors: + degfc = fc.degree() + degsfactors.append(degfc) + G = fc.change_ring(QQbar).change_ring(CIF) + g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) + for d in range(degfc + 1): + for i in range(d + 1): + c = CIF(g.coefficient({x: d - i, y: i})) + cr = c.real() + ci = c.imag() + coefsfactors += list(cr.endpoints()) + coefsfactors += list(ci.endpoints()) + from sage.libs.sirocco import contpath, contpath_mp, contpath_comps, contpath_mp_comps try: if prec == 53: - points = contpath(deg, coefs, yr, yi) + if factors: + points = contpath_comps(deg, coefs, yr, yi, degsfactors, coefsfactors) + else: + points = contpath(deg, coefs, yr, yi) else: - points = contpath_mp(deg, coefs, yr, yi, prec) + if factors: + points = contpath_mp_comps(deg, coefs, yr, yi, prec, degsfactors, coefsfactors) + else: + points = contpath_mp(deg, coefs, yr, yi, prec) return points except Exception: - return followstrand(f, x0, x1, y0a, 2 * prec) + return followstrand(f, factors, x0, x1, y0a, 2 * prec) + @parallel -def braid_in_segment(f, x0, x1): +def braid_in_segment(g, x0, x1): """ Return the braid formed by the `y` roots of ``f`` when `x` moves from ``x0`` to ``x1``. @@ -339,41 +371,78 @@ def braid_in_segment(f, x0, x1): sage: B.left_normal_form() # optional - sirocco (1, s5) """ - CC = ComplexField(64) - (x, y) = f.variables() + (x, y) = g.value().parent().gens() I = QQbar.gen() X0 = QQ(x0.real()) + I * QQ(x0.imag()) X1 = QQ(x1.real()) + I * QQ(x1.imag()) - F0 = QQbar[y](f(X0, y)) - y0s = F0.roots(multiplicities=False) - strands = [followstrand(f, x0, x1, CC(a)) for a in y0s] - complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands] + intervals = {} + precision = {} + y0s = [] + for (f, naux) in g: + if f.variables() == (y,): + F0 = QQbar[y](f.base_ring()[y](f)) + else: + F0 = QQbar[y](f(X0, y)) + y0sf = F0.roots(multiplicities=False) + y0s += list(y0sf) + precision[f]=53 + while True: + intervals[f] = [r.interval(ComplexIntervalField(precision[f])) for r in y0sf] + if not any([a.overlaps(b) for a,b in Subsets(intervals[f], 2)]): + break + precision[f] *= 2 + strands = [followstrand(f[0], [p[0] for p in g if p[0]!= f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] + complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) + y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] + + + CIF = ComplexIntervalField() + y0ints = QQbar[y](g.value()(X0,y)).roots(CIF, multiplicities=False) initialstrands = [] - y0aps = [c[0][1] for c in complexstrands] - used = [] + f = g.value() for y0ap in y0aps: - distances = [((y0ap - y0).norm(), y0) for y0 in y0s] - y0 = sorted(distances)[0][1] - if y0 in used: - raise ValueError("different roots are too close") - used.append(y0) - initialstrands.append([(0, y0), (1, y0ap)]) + dist, point = min([((y0ap-i.center()).abs(),i) for i in y0ints]) + diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) + y0api = y0ap + (dist+diam)*CIF((-1,1),(-1,1)) + newton = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api) + if newton in y0api and point in y0api: + initialstrands.append([(0, QQ(point.center().real()),QQ(point.center().imag())), (1, y0ap.real(), y0ap.imag())]) + else: + print(y0ap) + print(y0api) + print(point) + print(newton) + print(dist) + print(diam) + print(point in y0api) + print(newton in y0api) + y0api2 = y0ap + 0.00025*(dist)*CIF((-1,1),(-1,1)) + newton2 = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api2) + print(newton2 in y0api2) + raise ValueError("could not ensure that gluing of segments is correct") initialbraid = braid_from_piecewise(initialstrands) - F1 = QQbar[y](f(X1, y)) - y1s = F1.roots(multiplicities=False) + + y1aps = [QQ(c[-1][1])+QQbar.gen()*QQ(c[-1][2]) for c in complexstrands] + y1ints = QQbar[y](g.value()(X1,y)).roots(CIF, multiplicities=False) finalstrands = [] - y1aps = [c[-1][1] for c in complexstrands] - used = [] for y1ap in y1aps: - distances = [((y1ap - y1).norm(), y1) for y1 in y1s] - y1 = sorted(distances)[0][1] - if y1 in used: - raise ValueError("different roots are too close") - used.append(y1) - finalstrands.append([(0, y1ap), (1, y1)]) - finallbraid = braid_from_piecewise(finalstrands) - return initialbraid * centralbraid * finallbraid + dist, point = min([((y1ap-i.center()).abs(),i) for i in y1ints]) + diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) + y1api = y1ap + (dist+diam)*CIF((-1,1),(-1,1)) + newton = y1ap -f(X1,y).change_ring(CIF)(0,y1ap)/f.derivative(y)(x1,y).change_ring(CIF)(0,y1api) + if newton in y1api and point in y1api: + finalstrands.append([(0, y1ap.real(), y1ap.imag()), (1, QQ(point.center().real()),QQ(point.center().imag())) ]) + else: + print(y0ap) + print(y0api) + print(point) + print(newton) + raise ValueError("could not ensure that gluing of segments is correct") + finalbraid = braid_from_piecewise(finalstrands) + + + return initialbraid * centralbraid * finalbraid def fundamental_group(f, simplified=True, projective=False): @@ -437,7 +506,7 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ - (x, y) = f.variables() + (x, y) = f.parent().gens() F = f.base_ring() g = f.radical() d = g.degree(y) @@ -452,7 +521,8 @@ def fundamental_group(f, simplified=True, projective=False): rels = [] if projective: rels.append(prod(F.gen(i) for i in range(d))) - braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs]) + gfac = g.factor() + braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) b = braidcomputed[1] From f8cc3d58677e90f37f49b2da92d4f0f3521a1806 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 30 Jun 2021 12:42:54 +0200 Subject: [PATCH 018/355] Add braid monodromy --- src/sage/schemes/curves/zariski_vankampen.py | 631 ++++++++++++++++--- 1 file changed, 543 insertions(+), 88 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 6608fc7bf8e..140fbd2d8d4 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -52,12 +52,19 @@ from sage.groups.free_group import FreeGroup from sage.misc.misc_c import prod from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfr import RealField from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation from sage.functions.generalized import sign from sage.combinat.subset import Subsets +from sage.geometry.voronoi_diagram import VoronoiDiagram +from sage.graphs.graph import Graph +from sage.misc.cachefunc import cached_function +from copy import deepcopy +roots_interval_cache = dict() + def braid_from_piecewise(strands): r""" Compute the braid corresponding to the piecewise linear curves strands. @@ -166,10 +173,10 @@ def discrim(f): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim sage: R. = QQ[] sage: f = (y^3 + x^3 - 1) * (x + y) - sage: discrim(f) # optional - sirocco + sage: discrim(f) [1, -0.500000000000000? - 0.866025403784439?*I, -0.500000000000000? + 0.866025403784439?*I] @@ -179,6 +186,62 @@ def discrim(f): poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) +@cached_function +def corrected_voronoi_diagram(points): + r""" + compute a Voronoi diagram of a set of points with rational coordinates, such + that the given points are granted to lie one in each bounded region. + + INPUT: + + - ``points`` -- a list of complex numbers. + + OUTPUT: + + A VoronoiDiagram constructed from rational approximations of the points, + with the guarantee that each bounded region contains exactly one of the + input points. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import corrected_voronoi_diagram + sage: points = (2, I, 0.000001, 0, 0.000001*I) + sage: V = corrected_voronoi_diagram(points) + sage: V + The Voronoi diagram of 9 points of dimension 2 in the Rational Field + sage: V.regions() + {P(-7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, -7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 1): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(0, 1/1000000): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 2 rays, + P(1/1000000, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} + + + """ + prec = 53 + point_coordinates = [(p.real(), p.imag()) for p in points] + while True: + RF = RealField(prec) + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))):p for p in point_coordinates} + added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 + configuration = list(apprpoints.keys())+[(added_points, 0), + (-added_points, 0), + (0, added_points), + (0, -added_points)] + V = VoronoiDiagram(configuration) + valid = True + for r in V.regions().items(): + if not r[1].rays() and not apprpoints[r[0].affine()] in r[1]: + prec += 53 + valid = False + break + if valid: + break + return V def segments(points): """ @@ -195,45 +258,42 @@ def segments(points): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim, segments # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim, segments sage: R. = QQ[] sage: f = y^3 + x^3 - 1 - sage: disc = discrim(f) # optional - sirocco - sage: segments(disc) # optional - sirocco # abs tol 1e-15 - [(-2.84740787203333 - 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (-2.84740787203333 + 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (2.50000000000000 + 2.50000000000000*I, - 1.26513881334184 + 2.19128470333546*I), - (2.50000000000000 + 2.50000000000000*I, - 2.50000000000000 - 2.50000000000000*I), - (1.26513881334184 + 2.19128470333546*I, 0.000000000000000), - (0.000000000000000, 1.26513881334184 - 2.19128470333546*I), - (2.50000000000000 - 2.50000000000000*I, - 1.26513881334184 - 2.19128470333546*I), - (-2.84740787203333 + 2.84740787203333*I, - 1.26513881334184 + 2.19128470333546*I), - (-2.14285714285714 + 1.11022302462516e-16*I, 0.000000000000000), - (-2.84740787203333 - 2.84740787203333*I, - 1.26513881334184 - 2.19128470333546*I)] + sage: disc = discrim(f) + sage: segments(disc) + [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -192951821525958031/90044183378780414), + (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, 5/2*I + 5/2), + (1/38590364305191606, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/90044183378780414, 1/38590364305191606), + (-192951821525958031/90044183378780414, + 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), + (1/38590364305191606, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (5/2*I + 5/2, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] """ - from numpy import array, vstack - from scipy.spatial import Voronoi - discpoints = array([(CC(a).real(), CC(a).imag()) for a in points]) - added_points = 3 * abs(discpoints).max() + 1.0 - configuration = vstack([discpoints, array([[added_points, 0], - [-added_points, 0], - [0, added_points], - [0, -added_points]])]) - V = Voronoi(configuration) - res = [] - for rv in V.ridge_vertices: - if -1 not in rv: - p1 = CC(list(V.vertices[rv[0]])) - p2 = CC(list(V.vertices[rv[1]])) - res.append((p1, p2)) - return res + V = corrected_voronoi_diagram(tuple(points)) + res = set([]) + for region in V.regions().values(): + if region.rays(): + continue + segments = region.facets() + for s in segments: + t = tuple((tuple(v.vector()) for v in s.vertices())) + if not t in res and not tuple(reversed(t)) in res: + res.add(t) + return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] + def followstrand(f, factors, x0, x1, y0a, prec=53): @@ -243,7 +303,8 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): INPUT: - - ``f`` -- a polynomial in two variables + - ``f`` -- ann irreducible polynomial in two variables + - ``factors`` -- a list of irreducible polynomials in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends - ``y0a`` -- an approximate solution of the polynomial `F(y) = f(x_0, y)` @@ -258,7 +319,8 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): is zero (or a good enough approximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and - no other root intersects it. + no other root of `f`, nor any root of the polynomials in `factors`, + intersects it. EXAMPLES:: @@ -267,10 +329,18 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) - sage: followstrand(f, x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + sage: followstrand(f, [], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] + sage: fup = f.subs({y:y-1/10}) + sage: fdown = f.subs({y:y+1/10}) + sage: followstrand(f, [fup, fdown], x0, x1, -1.0) + [(0.0, -1.0, 0.0), + (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), + (0.7651655429449553, -1.015686131039112, -0.25243563967299404), + (1.0, -1.026166099551513, -0.3276894025360433)] + """ if f.degree() == 1: CF = ComplexField(prec) @@ -326,6 +396,119 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): except Exception: return followstrand(f, factors, x0, x1, y0a, 2 * prec) +def newton(f, x0, i0): + r""" + Return the interval Newton operator. + + INPUT: + + - ``f``` -- a univariate polynomial + - ``x0`` -- a number + - ``I0`` -- an interval + + OUTPUT: + + The interval `x_0-\frac{f(x_0)}{f'(I_0)}` + + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import newton + sage: R. = QQbar[] + sage: f = x^3 + x + sage: x0 = 1/10 + sage: I0 = RIF((-1/5,1/5)) + sage: n = newton(f, x0, I0) + sage: n + 0.0? + sage: n.real().endpoints() + (-0.0147727272727274, 0.00982142857142862) + sage: n.imag().endpoints() + (0.000000000000000, -0.000000000000000) + + """ + return x0 - f(x0)/f.derivative()(i0) + +@parallel +def roots_interval(f, x0): + """ + Find disjoint intervals that isolate the roots of a polynomial for a fixed + value of the first variable. + + INPUT: + + - ``f`` -- a bivariate squarefree polynomial + - ``x0`` -- a value where the first coordinate will be fixed + + The intervals are taken as big as possible to be able to detect when two + approximate roots of `f(x_0, y)` correspond to the same exact root. + + The result is given as a dictionary, where the keys are approximations to the roots + with rational real and imaginary parts, and the values are intervals containing them. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: ri = roots_interval(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: [r.endpoints() for r in ri.values()] + [(0.566987298107781 - 0.433012701892219*I, + 1.43301270189222 + 0.433012701892219*I, + 0.566987298107781 + 0.433012701892219*I, + 1.43301270189222 - 0.433012701892219*I), + (-0.933012701892219 - 1.29903810567666*I, + -0.0669872981077806 - 0.433012701892219*I, + -0.933012701892219 - 0.433012701892219*I, + -0.0669872981077806 - 1.29903810567666*I), + (-0.933012701892219 + 0.433012701892219*I, + -0.0669872981077806 + 1.29903810567666*I, + -0.933012701892219 + 1.29903810567666*I, + -0.0669872981077806 + 0.433012701892219*I)] + + """ + F = f.base_ring() + x, y = f.parent().gens() + I = QQbar.gen() + fx = QQbar[y](f.subs({x:QQ(x0.real())+I*QQ(x0.imag())})) + roots = fx.roots(QQbar, multiplicities=False) + result = {} + for i in range(len(roots)): + r = roots[i] + prec = 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor = 4 + diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + envelop = diam*IF((-1,1),(-1,1)) + while not newton(fx, r, r+envelop) in r+envelop: + prec += 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor *=2 + diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + envelop = diam*IF((-1,1),(-1,1)) + qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) + if not qapr in r+envelop: + raise ValueError("Could not approximate roots with exact values") + result[qapr] = r+envelop + return result + +def roots_interval_cached(f, x0): + r""" + Cached version of :func:`roots_interval`. + """ + global roots_interval_cache + if (f,x0) in roots_interval_cache.keys(): + return roots_interval_cache[(f,x0)] + else: + result = roots_interval(f,x0) + roots_interval_cache[(f,x0)] = result + return result @parallel @@ -336,7 +519,7 @@ def braid_in_segment(g, x0, x1): INPUT: - - ``f`` -- a polynomial in two variables + - ``g`` -- a polynomial factorization in two variables - ``x0`` -- a complex number - ``x1`` -- a complex number @@ -351,7 +534,7 @@ def braid_in_segment(g, x0, x1): sage: f = x^2 + y^3 sage: x0 = CC(1,0) sage: x1 = CC(1, 0.5) - sage: braid_in_segment(f, x0, x1) # optional - sirocco + sage: braid_in_segment(f.factor(), x0, x1) # optional - sirocco s1 TESTS: @@ -367,9 +550,9 @@ def braid_in_segment(g, x0, x1): sage: g = f.subs({x: x + 2*y}) sage: p1 = QQbar(sqrt(-1/3)) sage: p2 = QQbar(1/2+sqrt(-1/3)/2) - sage: B = zvk.braid_in_segment(g,CC(p1),CC(p2)) # optional - sirocco - sage: B.left_normal_form() # optional - sirocco - (1, s5) + sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco + sage: B # optional - sirocco + s5*s3^-1 """ (x, y) = g.value().parent().gens() I = QQbar.gen() @@ -394,55 +577,322 @@ def braid_in_segment(g, x0, x1): strands = [followstrand(f[0], [p[0] for p in g if p[0]!= f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) + initialstrands = [] + finalstrands = [] + initialintervals = roots_interval_cached(g.value(), X0) + finalintervals = roots_interval_cached(g.value(), X1) + for cs in complexstrands: + ip = cs[0][1] + I*cs[0][2] + fp = cs[-1][1] + I*cs[-1][2] + for center,interval in initialintervals.items(): + if ip in interval: + initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) + for center,interval in finalintervals.items(): + if fp in interval: + finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] + initialbraid = braid_from_piecewise(initialstrands) + finalbraid = braid_from_piecewise(finalstrands) + return initialbraid * centralbraid * finalbraid - CIF = ComplexIntervalField() - y0ints = QQbar[y](g.value()(X0,y)).roots(CIF, multiplicities=False) - initialstrands = [] - f = g.value() - for y0ap in y0aps: - dist, point = min([((y0ap-i.center()).abs(),i) for i in y0ints]) - diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) - y0api = y0ap + (dist+diam)*CIF((-1,1),(-1,1)) - newton = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api) - if newton in y0api and point in y0api: - initialstrands.append([(0, QQ(point.center().real()),QQ(point.center().imag())), (1, y0ap.real(), y0ap.imag())]) - else: - print(y0ap) - print(y0api) - print(point) - print(newton) - print(dist) - print(diam) - print(point in y0api) - print(newton in y0api) - y0api2 = y0ap + 0.00025*(dist)*CIF((-1,1),(-1,1)) - newton2 = y0ap -f(X0,y).change_ring(CIF)(0,y0ap)/f.derivative(y)(X0,y).change_ring(CIF)(0,y0api2) - print(newton2 in y0api2) - raise ValueError("could not ensure that gluing of segments is correct") - initialbraid = braid_from_piecewise(initialstrands) - y1aps = [QQ(c[-1][1])+QQbar.gen()*QQ(c[-1][2]) for c in complexstrands] - y1ints = QQbar[y](g.value()(X1,y)).roots(CIF, multiplicities=False) - finalstrands = [] - for y1ap in y1aps: - dist, point = min([((y1ap-i.center()).abs(),i) for i in y1ints]) - diam = max((point.real().absolute_diameter(), point.imag().absolute_diameter())) - y1api = y1ap + (dist+diam)*CIF((-1,1),(-1,1)) - newton = y1ap -f(X1,y).change_ring(CIF)(0,y1ap)/f.derivative(y)(x1,y).change_ring(CIF)(0,y1api) - if newton in y1api and point in y1api: - finalstrands.append([(0, y1ap.real(), y1ap.imag()), (1, QQ(point.center().real()),QQ(point.center().imag())) ]) + +def orient_circuit(circuit): + r""" + reverses a circuit if it goes clockwise + + INPUT: + + - `circuit` -- a circuit in the graph of a Voronoi Diagram, given + by a list of edges + + OUTPUT: The same circuit if it goes counterclockwise, and its reverse otherwise + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import orient_circuit + sage: points = [(-4, 0), (4, 0), (0, 4), (0, -4), (0, 0)] + sage: V = VoronoiDiagram(points) + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + sage: E.vertices() + [A vertex at (-2, -2), + A vertex at (-2, 2), + A vertex at (2, -2), + A vertex at (2, 2)] + sage: cir = E.eulerian_circuit() + sage: cir + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: orient_circuit(cir) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: cirinv = list(reversed([(c[1],c[0],c[2]) for c in cir])) + sage: cirinv + [(A vertex at (-2, -2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (-2, -2), None)] + sage: orient_circuit(cirinv) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + + """ + prec = 53 + vectors = [v[1].vector()-v[0].vector() for v in circuit] + while True: + CIF = ComplexIntervalField(prec) + totalangle = sum((CIF(*vectors[i])/CIF(*vectors[i-1])).argument() for i in range(len(vectors))) + if totalangle < 0: + return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) + elif totalangle > 0: + return circuit else: - print(y0ap) - print(y0api) - print(point) - print(newton) - raise ValueError("could not ensure that gluing of segments is correct") - finalbraid = braid_from_piecewise(finalstrands) + prec *= 2 +def geometric_basis(G, E, p): + r""" + Return a geometric basis, based on a vertex. + + INPUT: + + - ``G`` -- The graph of the bounded regions of a Voronoi Diagram + + - ``E`` -- The subgraph of `G` formed by the edges that touch an unbounded + region + + - ``p`` -- A vertex of `E` + + OUTPUT: A geometric basis. It is formed by a list of sequences of paths. + Each path is a list of vertices, that form a closed path in `G`, based at + `p`, that goes to a region, surrounds it, and comes back by the same path it + came. The concatenation of all these paths is equivalent to `E`. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import geometric_basis + sage: points = [(-3,0),(3,0),(0,3),(0,-3)]+ [(0,0),(0,-1),(0,1),(1,0),(-1,0)] + sage: V = VoronoiDiagram(points) + sage: G = Graph() + sage: for reg in V.regions().values(): + ....: G = G.union(reg.vertex_graph()) + ....: + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + ....: + sage: p = E.vertices()[0] + sage: geometric_basis(G, E, p) + [[A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (2, 2), + A vertex at (1/2, 1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (1/2, 1/2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (1/2, 1/2), + A vertex at (2, 2), + A vertex at (-2, 2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (-2, 2), + A vertex at (-2, -2)]] + + """ + EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] + i = EC.index(p) + EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p + if len(G.edges()) == len(E.edges()): + if E.is_cycle(): + return [EC] + + I = Graph() + for e in G.edges(): + if not E.has_edge(e): + I.add_edge(e) # interior graph + + #treat the case where I is empty + if not I.vertices(): + for v in E.vertices(): + if len(E.neighbors(v))>2: + I.add_vertex(v) + + for i in range(len(EC)): #q and r are the points we will cut through + + if EC[i] in I.vertices(): + q = EC[i] + connecting_path = EC[:i] + break + elif EC[-i] in I.vertices(): + q = EC[-i] + connecting_path = list(reversed(EC[-i:])) + break + distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] + r = max(distancequotients)[1] + cutpath = I.shortest_path(q, r) + + Gcut = deepcopy(G) + Ecut = deepcopy(E) + Ecut.delete_vertices([q,r]) + Gcut.delete_vertices(cutpath) + + #I think this cannot happen, but just in case, we check it to raise + # an error instead of giving a wrong answer + if Gcut.connected_components_number() != 2: + raise ValueError("can't compute a correct path") + G1, G2 = Gcut.connected_components_subgraphs() + + for v in cutpath: + neighs = G.neighbors(v) + for n in neighs: + if n in G1.vertices()+cutpath: + G1.add_edge(v,n,None) + if n in G2.vertices()+cutpath: + G2.add_edge(v,n,None) + + if EC[EC.index(q)+1] in G2.vertices(): + G1, G2 = G2,G1 + + E1, E2 = Ecut.connected_components_subgraphs() + if EC[EC.index(q)+1] in E2.vertices(): + E1, E2 = E2, E1 + + for i in range(len(cutpath)-1): + E1.add_edge(cutpath[i], cutpath[i+1], None) + E2.add_edge(cutpath[i], cutpath[i+1], None) + + for v in [q,r]: + for n in E.neighbors(v): + if n in E1.vertices(): + E1.add_edge(v, n, None) + if n in E2.vertices(): + E2.add_edge(v,n, None) + + gb1 = geometric_basis(G1, E1, q) + gb2 = geometric_basis(G2, E2, q) + + resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1+gb2] + for r in resul: + i = 0 + while i< len(r)-2: + if r[i] == r[i+2]: + r.pop(i) + r.pop(i) + if i>0: + i -=1 + else: + i+=1 + return resul + +def braid_monodromy(f): + r""" + Compute the braid monodromy of a projection of the curve defined by a polynomial + + INPUT: + + - ``f`` -- a polynomial with two variables, over a number field with an embedding + in the complex numbers. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of `f`. + + NOTE: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy + sage: R. = QQ[] + sage: f = (x^2-y^3)*(x+3*y-5) + sage: braid_monodromy(f) + [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, + s2^2] + + """ + global roots_interval_cache + (x, y) = f.parent().gens() + F = f.base_ring() + g = f.radical() + d = g.degree(y) + while not g.coefficient(y**d) in F: + g = g.subs({x: x + y}) + d = g.degree(y) + disc = discrim(g) + segs = segments(disc) + V = corrected_voronoi_diagram(tuple(disc)) + G = Graph() + for reg in V.regions().values(): + G = G.union(reg.vertex_graph()) + E = Graph() + for reg in V.regions().values(): + if reg.rays() or reg.lines(): + E = E.union(reg.vertex_graph()) + p = E.vertices()[0] + geombasis = geometric_basis(G, E, p) + vertices = list(set(flatten(segs))) + newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + rootsintervals = list(roots_interval([(g, v) for v in newvertices])) + for r in rootsintervals: + roots_interval_cache[r[0][0]] = r[1] + gfac = g.factor() + braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) + segsbraids = dict() + for braidcomputed in braidscomputed: + seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) + beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) + endseg = (QQ(seg[1].real()), QQ(seg[1].imag())) + b = braidcomputed[1] + segsbraids[(beginseg, endseg)] = b + segsbraids[(endseg, beginseg)] = b.inverse() + B = b.parent() + result = [] + for path in geombasis: + braidpath = B.one() + for i in range(len(path)-1): + x0 = tuple(path[i].vector()) + x1 = tuple(path[i+1].vector()) + braidpath = braidpath * segsbraids[(x0, x1)] + result.append(braidpath) + return result - return initialbraid * centralbraid * finalbraid def fundamental_group(f, simplified=True, projective=False): @@ -506,6 +956,7 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ + global roots_interval_cache (x, y) = f.parent().gens() F = f.base_ring() g = f.radical() @@ -516,6 +967,10 @@ def fundamental_group(f, simplified=True, projective=False): disc = discrim(g) segs = segments(disc) vertices = list(set(flatten(segs))) + newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + rootsintervals = list(roots_interval([(g, v) for v in newvertices])) + for r in rootsintervals: + roots_interval_cache[r[0][0]] = r[1] Faux = FreeGroup(d) F = FreeGroup(d * len(vertices)) rels = [] From 42a367cbf1eec7cbf2b8940ac2ac4551974ac8cc Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 30 Jun 2021 12:48:42 +0200 Subject: [PATCH 019/355] update to newer sirocco version --- build/pkgs/sirocco/checksums.ini | 6 +++--- build/pkgs/sirocco/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sirocco/checksums.ini b/build/pkgs/sirocco/checksums.ini index 672a9235128..2f0181ec823 100644 --- a/build/pkgs/sirocco/checksums.ini +++ b/build/pkgs/sirocco/checksums.ini @@ -1,5 +1,5 @@ tarball=libsirocco-VERSION.tar.gz -sha1=96e16ce48d6d320895b8d1ee8e07b738765f5e8d -md5=44c67dccf82fe3e2c61b5b7a51543718 -cksum=596947378 +sha1=23311c0944f0c128b493589c1575476cf88177b6 +md5=e86b1dc9b72aee0d80186be7f49c295e +cksum=784051898 upstream_url=https://github.com/miguelmarco/SIROCCO2/releases/download/VERSION/libsirocco-VERSION.tar.gz diff --git a/build/pkgs/sirocco/package-version.txt b/build/pkgs/sirocco/package-version.txt index e9307ca5751..7ec1d6db408 100644 --- a/build/pkgs/sirocco/package-version.txt +++ b/build/pkgs/sirocco/package-version.txt @@ -1 +1 @@ -2.0.2 +2.1.0 From f483ea99e6cf97324549edc8b116aa09250fe018 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 1 Jul 2021 14:17:51 +0200 Subject: [PATCH 020/355] Address reveiwer's corrections, and add method in affine_curve --- src/sage/schemes/curves/affine_curve.py | 35 +++++++++++++ src/sage/schemes/curves/zariski_vankampen.py | 55 ++++++++------------ 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 9fd99a3b3fc..24df1ce0495 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1737,6 +1737,41 @@ def fundamental_group(self): f = self.defining_polynomial() return fundamental_group(f, projective=False) + def braid_monodromy(self): + r""" + Compute the braid monodromy of a projection of the curve. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of `self`. + + NOTE: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + A. = AffineSpace(QQ, 2) + sage: C = A.curve((x^2-y^3)*(x+3*y-5)) + sage: C.braid_monodromy() # optional - sirocco + [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, + s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, + s2^2] + """ + from sage.schemes.curves.zariski_vankampen import braid_monodromy + F = self.base_ring() + from sage.rings.qqbar import QQbar + if QQbar.coerce_map_from(F) is None: + raise NotImplementedError("the base field must have an embedding" + " to the algebraic field") + f = self.defining_polynomial() + return braid_monodromy(f) + + def riemann_surface(self, **kwargs): r""" Return the complex Riemann surface determined by this curve diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 140fbd2d8d4..a146b99035e 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -154,7 +154,6 @@ def sgn(x, y): B = BraidGroup(len(L)) return B(braid) - def discrim(f): r""" Return the points in the discriminant of ``f``. @@ -189,12 +188,12 @@ def discrim(f): @cached_function def corrected_voronoi_diagram(points): r""" - compute a Voronoi diagram of a set of points with rational coordinates, such + Compute a Voronoi diagram of a set of points with rational coordinates, such that the given points are granted to lie one in each bounded region. INPUT: - - ``points`` -- a list of complex numbers. + - ``points`` -- a list of complex numbers OUTPUT: @@ -220,7 +219,6 @@ def corrected_voronoi_diagram(points): P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} - """ prec = 53 point_coordinates = [(p.real(), p.imag()) for p in points] @@ -294,8 +292,6 @@ def segments(points): res.add(t) return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] - - def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation @@ -303,7 +299,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): INPUT: - - ``f`` -- ann irreducible polynomial in two variables + - ``f`` -- an irreducible polynomial in two variables - ``factors`` -- a list of irreducible polynomials in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends @@ -319,7 +315,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): is zero (or a good enough approximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and - no other root of `f`, nor any root of the polynomials in `factors`, + no other root of ``f``, nor any root of the polynomials in ``factors``, intersects it. EXAMPLES:: @@ -553,6 +549,7 @@ def braid_in_segment(g, x0, x1): sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco sage: B # optional - sirocco s5*s3^-1 + """ (x, y) = g.value().parent().gens() I = QQbar.gen() @@ -596,18 +593,18 @@ def braid_in_segment(g, x0, x1): return initialbraid * centralbraid * finalbraid - - def orient_circuit(circuit): r""" - reverses a circuit if it goes clockwise + Reverses a circuit if it goes clockwise; otherwise leaves it unchanged. INPUT: - - `circuit` -- a circuit in the graph of a Voronoi Diagram, given + - ``circuit`` -- a circuit in the graph of a Voronoi Diagram, given by a list of edges - OUTPUT: The same circuit if it goes counterclockwise, and its reverse otherwise + OUTPUT: + + The same circuit if it goes counterclockwise, and its reverse otherwise EXAMPLES:: @@ -665,12 +662,12 @@ def geometric_basis(G, E, p): INPUT: - - ``G`` -- The graph of the bounded regions of a Voronoi Diagram + - ``G`` -- the graph of the bounded regions of a Voronoi Diagram - - ``E`` -- The subgraph of `G` formed by the edges that touch an unbounded + - ``E`` -- the subgraph of ``G`` formed by the edges that touch an unbounded region - - ``p`` -- A vertex of `E` + - ``p`` -- a vertex of ``E`` OUTPUT: A geometric basis. It is formed by a list of sequences of paths. Each path is a list of vertices, that form a closed path in `G`, based at @@ -736,12 +733,10 @@ def geometric_basis(G, E, p): if len(G.edges()) == len(E.edges()): if E.is_cycle(): return [EC] - I = Graph() for e in G.edges(): if not E.has_edge(e): I.add_edge(e) # interior graph - #treat the case where I is empty if not I.vertices(): for v in E.vertices(): @@ -761,16 +756,14 @@ def geometric_basis(G, E, p): distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) - Gcut = deepcopy(G) Ecut = deepcopy(E) Ecut.delete_vertices([q,r]) Gcut.delete_vertices(cutpath) - #I think this cannot happen, but just in case, we check it to raise # an error instead of giving a wrong answer if Gcut.connected_components_number() != 2: - raise ValueError("can't compute a correct path") + raise ValueError("unable to compute a correct path") G1, G2 = Gcut.connected_components_subgraphs() for v in cutpath: @@ -822,25 +815,25 @@ def braid_monodromy(f): INPUT: - ``f`` -- a polynomial with two variables, over a number field with an embedding - in the complex numbers. + in the complex numbers. OUTPUT: A list of braids. The braids correspond to paths based in the same point; each of this paths is the conjugated of a loop around one of the points - in the discriminant of the projection of `f`. + in the discriminant of the projection of ``f``. - NOTE: + .. NOTE:: - The projection over the `x` axis is used if there are no vertical asymptotes. - Otherwise, a linear change of variables is done to fall into the previous case. + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy sage: R. = QQ[] sage: f = (x^2-y^3)*(x+3*y-5) - sage: braid_monodromy(f) + sage: braid_monodromy(f) # optional - sirocco [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, @@ -865,10 +858,10 @@ def braid_monodromy(f): for reg in V.regions().values(): if reg.rays() or reg.lines(): E = E.union(reg.vertex_graph()) - p = E.vertices()[0] + p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] rootsintervals = list(roots_interval([(g, v) for v in newvertices])) for r in rootsintervals: roots_interval_cache[r[0][0]] = r[1] @@ -893,8 +886,6 @@ def braid_monodromy(f): result.append(braidpath) return result - - def fundamental_group(f, simplified=True, projective=False): r""" Return a presentation of the fundamental group of the complement of @@ -967,7 +958,7 @@ def fundamental_group(f, simplified=True, projective=False): disc = discrim(g) segs = segments(disc) vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if not (g, v) in roots_interval_cache.keys()] + newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] rootsintervals = list(roots_interval([(g, v) for v in newvertices])) for r in rootsintervals: roots_interval_cache[r[0][0]] = r[1] From 16c0757b7874829bc77dd94d4411964bfe237c44 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 1 Jul 2021 14:46:13 +0200 Subject: [PATCH 021/355] Fix some doctests --- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/zariski_vankampen.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 24df1ce0495..5a6fe00b449 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1754,7 +1754,7 @@ def braid_monodromy(self): EXAMPLES:: - A. = AffineSpace(QQ, 2) + sage: A. = AffineSpace(QQ, 2) sage: C = A.curve((x^2-y^3)*(x+3*y-5)) sage: C.braid_monodromy() # optional - sirocco [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index a146b99035e..ca4074bdb75 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -497,6 +497,23 @@ def roots_interval(f, x0): def roots_interval_cached(f, x0): r""" Cached version of :func:`roots_interval`. + + + TESTS:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: (f, 1) in roots_interval_cache + False + sage: ri = roots_interval_cached(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: (f, 1) in roots_interval_cache + True + """ global roots_interval_cache if (f,x0) in roots_interval_cache.keys(): From 9982f46a37bf90dfc5b79010b15631db404130c8 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 5 Jul 2021 13:32:31 +0200 Subject: [PATCH 022/355] Several fixes Correct some bugs Clean fundamental group to avoid code duplication Fix and add doctest --- src/sage/libs/sirocco.pyx | 59 ++++++++++++ src/sage/schemes/curves/affine_curve.py | 9 +- src/sage/schemes/curves/zariski_vankampen.py | 98 +++++++++----------- 3 files changed, 106 insertions(+), 60 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 9d0ad0b0230..165ecab8680 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -35,6 +35,17 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 - A extra argument is needed, indicating the bits of precision used in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp(2, pol, RR(0), RR(0), 53) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + """ cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) cdef mpfr_t* rop @@ -85,6 +96,24 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum - A extra argument is needed, indicating the bits of precision used in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp_comps + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp_comps(2, pol, RR(0), RR(0), 53, [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.125000000000000, -0.0156250000000000, 0.000000000000000), + (0.250000000000000, -0.0625000000000000, 0.000000000000000), + (0.375000000000000, -0.140625000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (0.625000000000000, -0.390625000000000, 0.000000000000000), + (0.750000000000000, -0.562500000000000, 0.000000000000000), + (0.875000000000000, -0.765625000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + """ cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) @@ -164,6 +193,18 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): A list of tuples. Each tuple represents the `x` value (between 0 and 1) and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath(2, pol, RR(0), RR(0)) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.3535533905932738, -0.12500000000000003, 0.0), + (0.7071067811865476, -0.5000000000000001, 0.0), + (1.0, -1.0, 0.0)] + """ cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) @@ -207,6 +248,24 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li A list of tuples. Each tuple represents the `x` value (between 0 and 1) and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_comps + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_comps(2, pol, RR(0), RR(0), [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.125, -0.015625, 0.0), + (0.25, -0.0625, 0.0), + (0.375, -0.140625, 0.0), + (0.5, -0.25, 0.0), + (0.625, -0.390625, 0.0), + (0.75, -0.5625, 0.0), + (0.875, -0.765625, 0.0), + (1.0, -1.0, 0.0)] + """ diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 5a6fe00b449..0d0a09945fa 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1757,10 +1757,11 @@ def braid_monodromy(self): sage: A. = AffineSpace(QQ, 2) sage: C = A.curve((x^2-y^3)*(x+3*y-5)) sage: C.braid_monodromy() # optional - sirocco - [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, - s2^2] + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] + """ from sage.schemes.curves.zariski_vankampen import braid_monodromy F = self.base_ring() diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index ca4074bdb75..4c2358a10de 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -16,10 +16,6 @@ braids over this paths gives relations between these generators. This big group presentation is simplified at the end. -.. TODO:: - - Implement the complete braid monodromy approach. - AUTHORS: - Miguel Marco (2015-09-30): Initial version @@ -60,7 +56,7 @@ from sage.geometry.voronoi_diagram import VoronoiDiagram from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_function -from copy import deepcopy +from copy import copy roots_interval_cache = dict() @@ -598,12 +594,24 @@ def braid_in_segment(g, x0, x1): for cs in complexstrands: ip = cs[0][1] + I*cs[0][2] fp = cs[-1][1] + I*cs[-1][2] + matched = 0 for center,interval in initialintervals.items(): if ip in interval: initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) + matched += 1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") + matched = 0 for center,interval in finalintervals.items(): if fp in interval: finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) + matched +=1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] initialbraid = braid_from_piecewise(initialstrands) finalbraid = braid_from_piecewise(finalstrands) @@ -773,8 +781,8 @@ def geometric_basis(G, E, p): distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) - Gcut = deepcopy(G) - Ecut = deepcopy(E) + Gcut = copy(G) + Ecut = copy(E) Ecut.delete_vertices([q,r]) Gcut.delete_vertices(cutpath) #I think this cannot happen, but just in case, we check it to raise @@ -851,10 +859,10 @@ def braid_monodromy(f): sage: R. = QQ[] sage: f = (x^2-y^3)*(x+3*y-5) sage: braid_monodromy(f) # optional - sirocco - [(s2*s1)^2*s0*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - (s2*s1)^2*s2^-1*s0*s2^-1*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s2*s0^-1*s2*(s1^-1*s2^-1)^2, - s2*(s1*s2*s1*s2^-1*s0*s2^-1)^2*s2^-1, - s2^2] + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] """ global roots_interval_cache @@ -866,7 +874,6 @@ def braid_monodromy(f): g = g.subs({x: x + y}) d = g.degree(y) disc = discrim(g) - segs = segments(disc) V = corrected_voronoi_diagram(tuple(disc)) G = Graph() for reg in V.regions().values(): @@ -877,13 +884,23 @@ def braid_monodromy(f): E = E.union(reg.vertex_graph()) p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) + segs = set([]) + for p in geombasis: + for s in zip(p[:-1], p[1:]): + if (s[1], s[0]) not in segs: + segs.add((s[0], s[1])) + I = QQbar.gen() + segs = [(a[0]+I*a[1], b[0]+I*b[1]) for (a, b) in segs] vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] - rootsintervals = list(roots_interval([(g, v) for v in newvertices])) - for r in rootsintervals: - roots_interval_cache[r[0][0]] = r[1] + noncachedverts = [(g, v) for v in vertices if (g, v) not in roots_interval_cache] + for noncachedvert in roots_interval(noncachedverts): + roots_interval_cache[noncachedvert[0][0]] = noncachedvert[1] + rootsintervals = [roots_interval_cached(g, v) for v in vertices] gfac = g.factor() - braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) + try: + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) + except ChildProcessError: # hack to deal with random fails first time + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) segsbraids = dict() for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) @@ -921,10 +938,7 @@ def fundamental_group(f, simplified=True, projective=False): of the curve will be computed, otherwise, the fundamental group of the complement in the affine plane will be computed - If ``simplified`` is ``False``, the returned presentation has as - many generators as degree of the polynomial times the points in the - base used to create the segments that surround the discriminant. In - this case, the generators are granted to be meridians of the curve. + If ``simplified`` is ``False``, a Zariski-VanKampen presentation is returned. OUTPUT: @@ -964,41 +978,13 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ - global roots_interval_cache - (x, y) = f.parent().gens() - F = f.base_ring() - g = f.radical() - d = g.degree(y) - while not g.coefficient(y**d) in F or (projective and g.total_degree() > d): - g = g.subs({x: x + y}) - d = g.degree(y) - disc = discrim(g) - segs = segments(disc) - vertices = list(set(flatten(segs))) - newvertices = [v for v in vertices if (g, v) not in roots_interval_cache] - rootsintervals = list(roots_interval([(g, v) for v in newvertices])) - for r in rootsintervals: - roots_interval_cache[r[0][0]] = r[1] - Faux = FreeGroup(d) - F = FreeGroup(d * len(vertices)) - rels = [] + bm = braid_monodromy(f) + n = bm[0].parent().strands() + F = FreeGroup(n) + R = [x*b/x for x in F.gens() for b in bm] if projective: - rels.append(prod(F.gen(i) for i in range(d))) - gfac = g.factor() - braidscomputed = braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]) - for braidcomputed in braidscomputed: - seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) - b = braidcomputed[1] - i = vertices.index(seg[0]) - j = vertices.index(seg[1]) - for k in range(d): - el1 = Faux([k + 1]) * b.inverse() - el2 = k + 1 - w1 = F([sign(a) * d * i + a for a in el1.Tietze()]) - w2 = F([d * j + el2]) - rels.append(w1 / w2) - G = F / rels + R.append(prod(F.gens())) + G = F/R if simplified: return G.simplified() - else: - return G + return G From 41b89a10dddbe57c63e7529054f3fe25191ea672 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Tue, 6 Jul 2021 01:45:42 +0200 Subject: [PATCH 023/355] Fix errors due to rebasing --- src/sage/schemes/curves/zariski_vankampen.py | 41 ++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 4c2358a10de..efe834fc567 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -256,25 +256,26 @@ def segments(points): sage: R. = QQ[] sage: f = y^3 + x^3 - 1 sage: disc = discrim(f) - sage: segments(disc) + sage: sorted(segments(disc)) [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - -192951821525958031/90044183378780414), - (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-5/2*I + 5/2, 5/2*I + 5/2), - (1/38590364305191606, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-5/2*I + 5/2, - -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (-192951821525958031/90044183378780414, 1/38590364305191606), - (-192951821525958031/90044183378780414, - 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), - (1/38590364305191606, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), - (5/2*I + 5/2, - 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] + -192951821525958031/90044183378780414), + (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/90044183378780414, + 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), + (-192951821525958031/90044183378780414, 1/38590364305191606), + (1/38590364305191606, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (1/38590364305191606, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, 5/2*I + 5/2), + (5/2*I + 5/2, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] + """ V = corrected_voronoi_diagram(tuple(points)) res = set([]) @@ -476,14 +477,14 @@ def roots_interval(f, x0): CF = ComplexField(prec) divisor = 4 diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor - envelop = diam*IF((-1,1),(-1,1)) + envelop = IF(diam)*IF((-1,1),(-1,1)) while not newton(fx, r, r+envelop) in r+envelop: prec += 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor *=2 diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor - envelop = diam*IF((-1,1),(-1,1)) + envelop = IF(diam)*IF((-1,1),(-1,1)) qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) if not qapr in r+envelop: raise ValueError("Could not approximate roots with exact values") From 25fd72f600652de066bd67b1f35ddd14470f04d1 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Tue, 6 Jul 2021 02:29:58 +0200 Subject: [PATCH 024/355] Stronger check for Voronoi Diagram --- src/sage/schemes/curves/zariski_vankampen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index efe834fc567..8d0c954dc78 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -229,7 +229,7 @@ def corrected_voronoi_diagram(points): V = VoronoiDiagram(configuration) valid = True for r in V.regions().items(): - if not r[1].rays() and not apprpoints[r[0].affine()] in r[1]: + if not r[1].rays() and not r[1].interior_contains(apprpoints[r[0].affine()]): prec += 53 valid = False break From 7c59e2b5e60c7427b009fbaf5eb255f8f249e4b3 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Tue, 6 Jul 2021 20:08:08 +0200 Subject: [PATCH 025/355] Linting --- src/sage/libs/sirocco.pyx | 16 +-- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/curves/zariski_vankampen.py | 100 ++++++++++--------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 165ecab8680..47504bd9d2a 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -134,8 +134,6 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum for j in range(len(otherdegs)): cotherdegs[j] = int(otherdegs[j]) - - sig_on() mpfr_init2(y0R, prec) mpfr_set(y0R, (y0r).value, MPFR_RNDN) @@ -143,18 +141,15 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum mpfr_set(y0I, (y0i).value, MPFR_RNDN) rop = homotopyPath_mp_comps(deg, cvalues, y0R, y0I, prec, int(len(otherdegs)), cotherdegs, cothercoefs) sig_off() - for j in range(len(values)): mpfr_clear(cvalues[j]) free(cvalues) - for j in range(len(othercoefs)): mpfr_clear(cothercoefs[j]) free(cothercoefs) free(cotherdegs) if rop == NULL: raise ValueError("libsirocco could not guarantee one step") - cdef int n = mpfr_get_si(rop[0], MPFR_RNDN) cdef list l = [] cdef list inner @@ -210,7 +205,7 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): cdef double* c_values = check_allocarray(len(values), sizeof(double)) cdef int clen = len(values) cdef int i - for i,v in enumerate(values): + for i, v in enumerate(values): c_values[i] = values[i] cdef double y0R = y0r cdef double y0I = y0i @@ -267,20 +262,18 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li (1.0, -1.0, 0.0)] """ - - cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) cdef double* c_othercoefs = check_allocarray(len(othercoefs), sizeof(double)) cdef int clen = len(values) cdef int i - for i,v in enumerate(values): + for i, v in enumerate(values): c_values[i] = values[i] - for i,v in enumerate(otherdegrees): + for i, v in enumerate(otherdegrees): c_otherdegrees[i] = otherdegrees[i] - for i,v in enumerate(othercoefs): + for i, v in enumerate(othercoefs): c_othercoefs[i] = othercoefs[i] cdef double y0R = y0r @@ -299,4 +292,3 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li free(c_otherdegrees) free(c_othercoefs) return l - diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 0e6ba6a1e4b..0f8cfbcb4de 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1699,7 +1699,7 @@ def fundamental_group(self): f = self.affine_patch(2).defining_polynomial() if f.degree() == self.degree(): return fundamental_group(f, projective=True) - else: #in this case, the line at infinity is part of the curve, so the complement lies in the affine patch + else: # in this case, the line at infinity is part of the curve, so the complement lies in the affine patch return fundamental_group(f, projective=False) def rational_parameterization(self): diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 8d0c954dc78..b808eb77fa0 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -42,7 +42,6 @@ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.rings.rational_field import QQ from sage.rings.qqbar import QQbar -from sage.rings.all import CC from sage.parallel.decorate import parallel from sage.misc.flatten import flatten from sage.groups.free_group import FreeGroup @@ -51,7 +50,6 @@ from sage.rings.real_mpfr import RealField from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation -from sage.functions.generalized import sign from sage.combinat.subset import Subsets from sage.geometry.voronoi_diagram import VoronoiDiagram from sage.graphs.graph import Graph @@ -61,6 +59,7 @@ roots_interval_cache = dict() + def braid_from_piecewise(strands): r""" Compute the braid corresponding to the piecewise linear curves strands. @@ -150,6 +149,7 @@ def sgn(x, y): B = BraidGroup(len(L)) return B(braid) + def discrim(f): r""" Return the points in the discriminant of ``f``. @@ -181,6 +181,7 @@ def discrim(f): poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) + @cached_function def corrected_voronoi_diagram(points): r""" @@ -220,12 +221,12 @@ def corrected_voronoi_diagram(points): point_coordinates = [(p.real(), p.imag()) for p in points] while True: RF = RealField(prec) - apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))):p for p in point_coordinates} + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p for p in point_coordinates} added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 configuration = list(apprpoints.keys())+[(added_points, 0), - (-added_points, 0), - (0, added_points), - (0, -added_points)] + (-added_points, 0), + (0, added_points), + (0, -added_points)] V = VoronoiDiagram(configuration) valid = True for r in V.regions().items(): @@ -237,6 +238,7 @@ def corrected_voronoi_diagram(points): break return V + def segments(points): """ Return the bounded segments of the Voronoi diagram of the given points. @@ -285,10 +287,11 @@ def segments(points): segments = region.facets() for s in segments: t = tuple((tuple(v.vector()) for v in s.vertices())) - if not t in res and not tuple(reversed(t)) in res: + if t not in res and not tuple(reversed(t)) in res: res.add(t) return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] + def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation @@ -389,6 +392,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): except Exception: return followstrand(f, factors, x0, x1, y0a, 2 * prec) + def newton(f, x0, i0): r""" Return the interval Newton operator. @@ -422,6 +426,7 @@ def newton(f, x0, i0): """ return x0 - f(x0)/f.derivative()(i0) + @parallel def roots_interval(f, x0): """ @@ -464,10 +469,9 @@ def roots_interval(f, x0): -0.0669872981077806 + 0.433012701892219*I)] """ - F = f.base_ring() x, y = f.parent().gens() I = QQbar.gen() - fx = QQbar[y](f.subs({x:QQ(x0.real())+I*QQ(x0.imag())})) + fx = QQbar[y](f.subs({x: QQ(x0.real())+I*QQ(x0.imag())})) roots = fx.roots(QQbar, multiplicities=False) result = {} for i in range(len(roots)): @@ -477,20 +481,21 @@ def roots_interval(f, x0): CF = ComplexField(prec) divisor = 4 diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor - envelop = IF(diam)*IF((-1,1),(-1,1)) + envelop = IF(diam)*IF((-1, 1), (-1, 1)) while not newton(fx, r, r+envelop) in r+envelop: prec += 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) - divisor *=2 + divisor *= 2 diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor - envelop = IF(diam)*IF((-1,1),(-1,1)) + envelop = IF(diam)*IF((-1, 1), (-1, 1)) qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) - if not qapr in r+envelop: + if qapr not in r+envelop: raise ValueError("Could not approximate roots with exact values") result[qapr] = r+envelop return result + def roots_interval_cached(f, x0): r""" Cached version of :func:`roots_interval`. @@ -513,11 +518,11 @@ def roots_interval_cached(f, x0): """ global roots_interval_cache - if (f,x0) in roots_interval_cache.keys(): - return roots_interval_cache[(f,x0)] + if (f, x0) in roots_interval_cache.keys(): + return roots_interval_cache[(f, x0)] else: - result = roots_interval(f,x0) - roots_interval_cache[(f,x0)] = result + result = roots_interval(f, x0) + roots_interval_cache[(f, x0)] = result return result @@ -579,13 +584,13 @@ def braid_in_segment(g, x0, x1): F0 = QQbar[y](f(X0, y)) y0sf = F0.roots(multiplicities=False) y0s += list(y0sf) - precision[f]=53 + precision[f] = 53 while True: intervals[f] = [r.interval(ComplexIntervalField(precision[f])) for r in y0sf] - if not any([a.overlaps(b) for a,b in Subsets(intervals[f], 2)]): + if not any([a.overlaps(b) for a, b in Subsets(intervals[f], 2)]): break precision[f] *= 2 - strands = [followstrand(f[0], [p[0] for p in g if p[0]!= f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] + strands = [followstrand(f[0], [p[0] for p in g if p[0] != f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) initialstrands = [] @@ -596,7 +601,7 @@ def braid_in_segment(g, x0, x1): ip = cs[0][1] + I*cs[0][2] fp = cs[-1][1] + I*cs[-1][2] matched = 0 - for center,interval in initialintervals.items(): + for center, interval in initialintervals.items(): if ip in interval: initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) matched += 1 @@ -605,20 +610,20 @@ def braid_in_segment(g, x0, x1): if matched > 1: raise ValueError("braid endpoint mathes more than one root") matched = 0 - for center,interval in finalintervals.items(): + for center, interval in finalintervals.items(): if fp in interval: finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) - matched +=1 + matched += 1 if matched == 0: raise ValueError("unable to match braid endpoint with root") if matched > 1: raise ValueError("braid endpoint mathes more than one root") - y0aps = [QQ(c[0][1])+QQbar.gen()*QQ(c[0][2]) for c in complexstrands] initialbraid = braid_from_piecewise(initialstrands) finalbraid = braid_from_piecewise(finalstrands) return initialbraid * centralbraid * finalbraid + def orient_circuit(circuit): r""" Reverses a circuit if it goes clockwise; otherwise leaves it unchanged. @@ -682,6 +687,7 @@ def orient_circuit(circuit): else: prec *= 2 + def geometric_basis(G, E, p): r""" Return a geometric basis, based on a vertex. @@ -755,7 +761,7 @@ def geometric_basis(G, E, p): """ EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] i = EC.index(p) - EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p + EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p if len(G.edges()) == len(E.edges()): if E.is_cycle(): return [EC] @@ -763,13 +769,13 @@ def geometric_basis(G, E, p): for e in G.edges(): if not E.has_edge(e): I.add_edge(e) # interior graph - #treat the case where I is empty + # treat the case where I is empty if not I.vertices(): for v in E.vertices(): - if len(E.neighbors(v))>2: + if len(E.neighbors(v)) > 2: I.add_vertex(v) - for i in range(len(EC)): #q and r are the points we will cut through + for i in range(len(EC)): # q and r are the points we will cut through if EC[i] in I.vertices(): q = EC[i] @@ -779,14 +785,14 @@ def geometric_basis(G, E, p): q = EC[-i] connecting_path = list(reversed(EC[-i:])) break - distancequotients = [(E.distance(q,v)**2/I.distance(q,v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v==q] + distancequotients = [(E.distance(q, v)**2/I.distance(q, v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v == q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) Gcut = copy(G) Ecut = copy(E) - Ecut.delete_vertices([q,r]) + Ecut.delete_vertices([q, r]) Gcut.delete_vertices(cutpath) - #I think this cannot happen, but just in case, we check it to raise + # I think this cannot happen, but just in case, we check it to raise # an error instead of giving a wrong answer if Gcut.connected_components_number() != 2: raise ValueError("unable to compute a correct path") @@ -796,12 +802,12 @@ def geometric_basis(G, E, p): neighs = G.neighbors(v) for n in neighs: if n in G1.vertices()+cutpath: - G1.add_edge(v,n,None) + G1.add_edge(v, n, None) if n in G2.vertices()+cutpath: - G2.add_edge(v,n,None) + G2.add_edge(v, n, None) if EC[EC.index(q)+1] in G2.vertices(): - G1, G2 = G2,G1 + G1, G2 = G2, G1 E1, E2 = Ecut.connected_components_subgraphs() if EC[EC.index(q)+1] in E2.vertices(): @@ -811,29 +817,30 @@ def geometric_basis(G, E, p): E1.add_edge(cutpath[i], cutpath[i+1], None) E2.add_edge(cutpath[i], cutpath[i+1], None) - for v in [q,r]: + for v in [q, r]: for n in E.neighbors(v): if n in E1.vertices(): E1.add_edge(v, n, None) if n in E2.vertices(): - E2.add_edge(v,n, None) + E2.add_edge(v, n, None) gb1 = geometric_basis(G1, E1, q) gb2 = geometric_basis(G2, E2, q) - resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1+gb2] + resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1 + gb2] for r in resul: i = 0 - while i< len(r)-2: + while i < len(r)-2: if r[i] == r[i+2]: r.pop(i) r.pop(i) - if i>0: - i -=1 + if i > 0: + i -= 1 else: - i+=1 + i += 1 return resul + def braid_monodromy(f): r""" Compute the braid monodromy of a projection of the curve defined by a polynomial @@ -877,12 +884,12 @@ def braid_monodromy(f): disc = discrim(g) V = corrected_voronoi_diagram(tuple(disc)) G = Graph() - for reg in V.regions().values(): + for reg in V.regions().values(): G = G.union(reg.vertex_graph()) E = Graph() - for reg in V.regions().values(): + for reg in V.regions().values(): if reg.rays() or reg.lines(): - E = E.union(reg.vertex_graph()) + E = E.union(reg.vertex_graph()) p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) segs = set([]) @@ -896,11 +903,11 @@ def braid_monodromy(f): noncachedverts = [(g, v) for v in vertices if (g, v) not in roots_interval_cache] for noncachedvert in roots_interval(noncachedverts): roots_interval_cache[noncachedvert[0][0]] = noncachedvert[1] - rootsintervals = [roots_interval_cached(g, v) for v in vertices] + _ = [roots_interval_cached(g, v) for v in vertices] gfac = g.factor() try: braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) - except ChildProcessError: # hack to deal with random fails first time + except ChildProcessError: # hack to deal with random fails first time braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) segsbraids = dict() for braidcomputed in braidscomputed: @@ -921,6 +928,7 @@ def braid_monodromy(f): result.append(braidpath) return result + def fundamental_group(f, simplified=True, projective=False): r""" Return a presentation of the fundamental group of the complement of From 97cac426cf8087b353069a7deae333b6ebeb0937 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 12 Jul 2021 12:32:24 +0200 Subject: [PATCH 026/355] Some changes suggested by reviewer --- src/sage/schemes/curves/zariski_vankampen.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index b808eb77fa0..b9a36734036 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -50,7 +50,7 @@ from sage.rings.real_mpfr import RealField from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation -from sage.combinat.subset import Subsets +import itertools from sage.geometry.voronoi_diagram import VoronoiDiagram from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_function @@ -480,7 +480,7 @@ def roots_interval(f, x0): IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor = 4 - diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + 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: prec += 53 @@ -518,9 +518,9 @@ def roots_interval_cached(f, x0): """ global roots_interval_cache - if (f, x0) in roots_interval_cache.keys(): + try: return roots_interval_cache[(f, x0)] - else: + except KeyError: result = roots_interval(f, x0) roots_interval_cache[(f, x0)] = result return result @@ -586,8 +586,9 @@ def braid_in_segment(g, x0, x1): y0s += list(y0sf) precision[f] = 53 while True: - intervals[f] = [r.interval(ComplexIntervalField(precision[f])) for r in y0sf] - if not any([a.overlaps(b) for a, b in Subsets(intervals[f], 2)]): + CIFp = ComplexIntervalField(precision[f]) + intervals[f] = [r.interval(CIFp) for r in y0sf] + if not any(a.overlaps(b) for a, b in itertools.combinations(intervals[f], 2)): break precision[f] *= 2 strands = [followstrand(f[0], [p[0] for p in g if p[0] != f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] From 9ae6e9c08f8f556977b5253f4410fd0cda47c588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 22 Mar 2021 02:40:40 +0100 Subject: [PATCH 027/355] 30887: Add distro info for 4ti2 --- build/pkgs/4ti2/distros/arch.txt | 1 + build/pkgs/4ti2/distros/cygwin.txt | 1 + build/pkgs/4ti2/distros/debian.txt | 1 + build/pkgs/4ti2/distros/fedora.txt | 1 + build/pkgs/4ti2/distros/freebsd.txt | 1 + build/pkgs/4ti2/distros/gentoo.txt | 1 + 6 files changed, 6 insertions(+) create mode 100644 build/pkgs/4ti2/distros/arch.txt create mode 100644 build/pkgs/4ti2/distros/cygwin.txt create mode 100644 build/pkgs/4ti2/distros/debian.txt create mode 100644 build/pkgs/4ti2/distros/fedora.txt create mode 100644 build/pkgs/4ti2/distros/freebsd.txt create mode 100644 build/pkgs/4ti2/distros/gentoo.txt diff --git a/build/pkgs/4ti2/distros/arch.txt b/build/pkgs/4ti2/distros/arch.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/arch.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/cygwin.txt b/build/pkgs/4ti2/distros/cygwin.txt new file mode 100644 index 00000000000..cd62bb6f0a0 --- /dev/null +++ b/build/pkgs/4ti2/distros/cygwin.txt @@ -0,0 +1 @@ +lib4ti2-devel diff --git a/build/pkgs/4ti2/distros/debian.txt b/build/pkgs/4ti2/distros/debian.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/debian.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/fedora.txt b/build/pkgs/4ti2/distros/fedora.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/fedora.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/freebsd.txt b/build/pkgs/4ti2/distros/freebsd.txt new file mode 100644 index 00000000000..2554e2f0552 --- /dev/null +++ b/build/pkgs/4ti2/distros/freebsd.txt @@ -0,0 +1 @@ +math/4ti2 diff --git a/build/pkgs/4ti2/distros/gentoo.txt b/build/pkgs/4ti2/distros/gentoo.txt new file mode 100644 index 00000000000..81580261c2f --- /dev/null +++ b/build/pkgs/4ti2/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/4ti2 From 9b6ad3dd01e3199e4b9628136b5968f7cdaaa40e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Mar 2021 16:52:12 -0700 Subject: [PATCH 028/355] build/pkgs/4ti2/spkg-configure.m4: New --- build/pkgs/4ti2/spkg-configure.m4 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 build/pkgs/4ti2/spkg-configure.m4 diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 new file mode 100644 index 00000000000..3501939c875 --- /dev/null +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -0,0 +1,30 @@ +SAGE_SPKG_CONFIGURE([4ti2], [ + SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [ + dnl Debian installs these programs with an executable prefix "4ti2-" + dnl but polymake and our own code do not handle this yet (Singular does). + m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], + AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog) + AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) + ) + dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4 + AC_MSG_CHECKING(for library 4ti2gmp) + BACKUP_CXXFLAGS=${CXXFLAGS} + BACKUP_LIBS=${LIBS} + FORTYTWO_CXXFLAGS="-D__STDC_LIMIT_MACROS -D_4ti2_GMP_" + FORTYTWO_LIBS="-l4ti2gmp -lzsolve" + CXXFLAGS="${BACKUP_CXXFLAGS} ${FORTYTWO_CXXFLAGS} ${GMP_CFLAGS}" + LIBS="${BACKUP_LIBS} ${FORTYTWO_LIBS} ${GMP_LIBS}" + AC_TRY_LINK([ +#include "4ti2/4ti2.h" +], +[ _4ti2_rays_create_state(_4ti2_PREC_INT_ARB); +], [ + AC_MSG_RESULT([yes]) +], [ + AC_MSG_RESULT([no]) + sage_spkg_install_4ti2=yes +]) + CXXFLAGS=${BACKUP_CXXFLAGS} + LIBS=${BACKUP_LIBS} + ]) +]) From 354eaae0928a43c451e3c8eb75c44bc7f12511e4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Mar 2021 19:20:51 -0700 Subject: [PATCH 029/355] build/pkgs/4ti2/spkg-configure.m4: Fix quoting --- build/pkgs/4ti2/spkg-configure.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index 3501939c875..43b23b3de6a 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -2,10 +2,10 @@ SAGE_SPKG_CONFIGURE([4ti2], [ SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [ dnl Debian installs these programs with an executable prefix "4ti2-" dnl but polymake and our own code do not handle this yet (Singular does). - m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], + m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [ AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog) AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) - ) + ]) dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4 AC_MSG_CHECKING(for library 4ti2gmp) BACKUP_CXXFLAGS=${CXXFLAGS} From 8c49201ddfd8ee4950dfd74a91f550ca4a80f088 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Jun 2021 16:54:51 -0700 Subject: [PATCH 030/355] build/pkgs/4ti2/spkg-configure.m4: Check for executables with prefix '4ti2-' too --- build/pkgs/4ti2/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index 43b23b3de6a..da4ea9dd9fe 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -3,7 +3,7 @@ SAGE_SPKG_CONFIGURE([4ti2], [ dnl Debian installs these programs with an executable prefix "4ti2-" dnl but polymake and our own code do not handle this yet (Singular does). m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [ - AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog) + AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog) AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) ]) dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4 From 641f6876d3e0323d2b3570408433ce276b60e48c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Jun 2021 16:57:29 -0700 Subject: [PATCH 031/355] build/pkgs/sage_conf/src/sage_conf.py.in, src/sage/env.py: Add FOURTITWO... variables --- pkgs/sage-conf/sage_conf.py.in | 11 +++++++++++ src/sage/env.py | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/pkgs/sage-conf/sage_conf.py.in b/pkgs/sage-conf/sage_conf.py.in index d156a274250..86375d2f286 100644 --- a/pkgs/sage-conf/sage_conf.py.in +++ b/pkgs/sage-conf/sage_conf.py.in @@ -27,6 +27,17 @@ ECL_CONFIG = "@SAGE_ECL_CONFIG@".replace('${prefix}', SAGE_LOCAL) SAGE_NAUTY_BINS_PREFIX = "@SAGE_NAUTY_BINS_PREFIX@" +# Names or paths of the 4ti2 executables +FOURTITWO_HILBERT = "@FOURTITWO_HILBERT@" +FOURTITWO_MARKOV = "@FOURTITWO_MARKOV@" +FOURTITWO_GRAVER = "@FOURTITWO_GRAVER@" +FOURTITWO_ZSOLVE = "@FOURTITWO_ZSOLVE@" +FOURTITWO_QSOLVE = "@FOURTITWO_QSOLVE@" +FOURTITWO_RAYS = "@FOURTITWO_RAYS@" +FOURTITWO_PPI = "@FOURTITWO_PPI@" +FOURTITWO_CIRCUITS = "@FOURTITWO_CIRCUITS@" +FOURTITWO_GROEBNER = "@FOURTITWO_GROEBNER@" + # Colon-separated list of pkg-config modules to search for cblas functionality. # We hard-code it here as cblas because configure (build/pkgs/openblas/spkg-configure.m4) # always provides cblas.pc, if necessary by creating a facade pc file for a system BLAS. diff --git a/src/sage/env.py b/src/sage/env.py index 95980cc2df6..ecf20baf8b3 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -212,6 +212,15 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st MAXIMA_FAS = var("MAXIMA_FAS") KENZO_FAS = var("KENZO_FAS") SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "") +FOURTITWO_HILBERT = var("FOURTITWO_HILBERT", "hilbert") +FOURTITWO_MARKOV = var("FOURTITWO_MARKOV", "markov") +FOURTITWO_GRAVER = var("FOURTITWO_GRAVER", "graver") +FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE", "zsolve") +FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE", "qsolve") +FOURTITWO_RAYS = var("FOURTITWO_RAYS", "rays") +FOURTITWO_PPI = var("FOURTITWO_PPI", "ppi") +FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS", "circuits") +FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER", "groebner") ARB_LIBRARY = var("ARB_LIBRARY", "arb") CBLAS_PC_MODULES = var("CBLAS_PC_MODULES", "cblas:openblas:blas") ECL_CONFIG = var("ECL_CONFIG", "ecl-config") From fccb97323d0b1cfc0a6d536d8fbc7aea3b01800f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Jun 2021 18:35:46 -0700 Subject: [PATCH 032/355] build/pkgs/4ti2/spkg-configure.m4: Add AC_SUBST --- build/pkgs/4ti2/spkg-configure.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index da4ea9dd9fe..291997e6a1a 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -5,6 +5,7 @@ SAGE_SPKG_CONFIGURE([4ti2], [ m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [ AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog) AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) + AC_SUBST([FOURTITWO_]m4_toupper(prog)) ]) dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4 AC_MSG_CHECKING(for library 4ti2gmp) From 3c32540acb8ee1f1cceb3279c7def02ea3b185e8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Jun 2021 18:36:16 -0700 Subject: [PATCH 033/355] src/sage/env.py: No fallbacks for FOURTITWO... here --- src/sage/env.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index ecf20baf8b3..b488aa44c2e 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -212,15 +212,15 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st MAXIMA_FAS = var("MAXIMA_FAS") KENZO_FAS = var("KENZO_FAS") SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "") -FOURTITWO_HILBERT = var("FOURTITWO_HILBERT", "hilbert") -FOURTITWO_MARKOV = var("FOURTITWO_MARKOV", "markov") -FOURTITWO_GRAVER = var("FOURTITWO_GRAVER", "graver") -FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE", "zsolve") -FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE", "qsolve") -FOURTITWO_RAYS = var("FOURTITWO_RAYS", "rays") -FOURTITWO_PPI = var("FOURTITWO_PPI", "ppi") -FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS", "circuits") -FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER", "groebner") +FOURTITWO_HILBERT = var("FOURTITWO_HILBERT") +FOURTITWO_MARKOV = var("FOURTITWO_MARKOV") +FOURTITWO_GRAVER = var("FOURTITWO_GRAVER") +FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE") +FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE") +FOURTITWO_RAYS = var("FOURTITWO_RAYS") +FOURTITWO_PPI = var("FOURTITWO_PPI") +FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS") +FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER") ARB_LIBRARY = var("ARB_LIBRARY", "arb") CBLAS_PC_MODULES = var("CBLAS_PC_MODULES", "cblas:openblas:blas") ECL_CONFIG = var("ECL_CONFIG", "ecl-config") From ea548d7db98083c0cb8c516d9777e031656b693f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Jun 2021 18:37:07 -0700 Subject: [PATCH 034/355] sage.features.four_ti_2: New, use it in sage.interfaces.four_ti_2, sage.sandpiles --- src/sage/features/four_ti_2.py | 13 +++++++++++++ src/sage/interfaces/four_ti_2.py | 28 +++++++++++++++++----------- src/sage/sandpiles/sandpile.py | 13 ++++--------- 3 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/sage/features/four_ti_2.py diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py new file mode 100644 index 00000000000..bdc6399b82e --- /dev/null +++ b/src/sage/features/four_ti_2.py @@ -0,0 +1,13 @@ +from sage.env import SAGE_ENV + +from sage.features import Executable + +class FourTi2Executable(Executable): + r""" + Feature for the 4ti2 executables. + """ + def __init__(self, name): + Executable.__init__(self, + name="4ti2-" + name, + executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, + spkg="4ti2") diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 067535f2d40..dcf240a74d0 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -36,6 +36,8 @@ #***************************************************************************** from sage.rings.integer_ring import ZZ +from sage.features.four_ti_2 import FourTi2Executable + import os @@ -271,7 +273,7 @@ def _process_input(self, kwds): # Commands # ############ - def call(self, command, project, verbose=True): + def call(self, command, project, verbose=True, *, options=()): r""" Run the 4ti2 program ``command`` on the project named ``project`` in the directory ``directory()``. @@ -281,6 +283,7 @@ def call(self, command, project, verbose=True): - command -- The 4ti2 program to run. - project -- The file name of the project to run on. - verbose -- Display the output of 4ti2 if ``True``. + - options -- A list of strings to pass to the program. EXAMPLES:: @@ -292,8 +295,11 @@ def call(self, command, project, verbose=True): [-5 3 0] """ import subprocess - - cmd = '%s %s' % (command, project) + feature = FourTi2Executable(command) + feature.require() + executable = feature.executable + options = " ".join(options) + cmd = f'{executable} {options} {project}' if verbose is False: cmd += " > /dev/null 2> /dev/null" subprocess.call(cmd, shell=True, cwd=self.directory()) @@ -326,7 +332,7 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None """ project = self._process_input(locals()) - self.call('zsolve -q', project) + self.call('zsolve', project, options=['-q']) return [self.read_matrix(project+'.'+ext) for ext in ['zinhom', 'zhom', 'zfree']] @@ -343,7 +349,7 @@ def qsolve(self, mat=None, rel=None, sign=None, project=None): [[], [ 1 -2 1]] """ project = self._process_input(locals()) - self.call('qsolve -q -parbitrary', project) + self.call('qsolve', project, options=['-q', '-parbitrary']) return [self.read_matrix(project+'.'+ext) for ext in ['qhom', 'qfree']] @@ -362,7 +368,7 @@ def rays(self, mat=None, project=None): [2 0 1 0 1 2 1 2 0] """ project = self._process_input(locals()) - self.call('rays -q -parbitrary', project) + self.call('rays', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.ray') def hilbert(self, mat=None, lat=None, project=None): @@ -385,7 +391,7 @@ def hilbert(self, mat=None, lat=None, project=None): [1 1 1] """ project = self._process_input(locals()) - self.call('hilbert -q', project) + self.call('hilbert', project, options=['-q']) return self.read_matrix(project+'.hil') def graver(self, mat=None, lat=None, project=None): @@ -409,7 +415,7 @@ def graver(self, mat=None, lat=None, project=None): [ 2 1 0] """ project = self._process_input(locals()) - self.call('graver -q', project) + self.call('graver', project, options=['-q']) return self.read_matrix(project+'.gra') def ppi(self, n): @@ -428,7 +434,7 @@ def ppi(self, n): [ 1 -2 1] """ - self.call('ppi 2> /dev/null', n) + self.call('ppi', f'{n} 2> /dev/null') return self.read_matrix('ppi%s.gra'%n) def circuits(self, mat=None, project=None): @@ -445,7 +451,7 @@ def circuits(self, mat=None, project=None): [ 3 0 -1] """ project = self._process_input(locals()) - self.call('circuits -q -parbitrary', project) + self.call('circuits', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.cir') def minimize(self, mat=None, lat=None): @@ -482,7 +488,7 @@ def groebner(self, mat=None, lat=None, project=None): [ 2 1 0] """ project = self._process_input(locals()) - self.call('groebner -q -parbitrary', project) + self.call('groebner', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.gro') def _magic3x3(self): diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index a03112b98b4..ef3303f90c2 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -322,13 +322,11 @@ from IPython.lib import pretty -import os # CHECK: possibly unnecessary after removing 4ti2-dependent methods from sage.calculus.functional import derivative from sage.combinat.integer_vector import integer_vectors_nk_fast_iter from sage.combinat.parking_functions import ParkingFunctions from sage.combinat.set_partition import SetPartitions from sage.combinat.vector_partition import IntegerVectorsIterator -from sage.env import SAGE_LOCAL from sage.functions.log import exp from sage.functions.other import binomial from sage.geometry.polyhedron.constructor import Polyhedron @@ -346,10 +344,7 @@ from sage.rings.all import Integer, PolynomialRing, QQ, ZZ from sage.symbolic.constants import I, pi from sage.symbolic.ring import SR - -# TODO: remove the following line once 4ti2 functions are removed -path_to_zsolve = os.path.join(SAGE_LOCAL, 'bin', 'zsolve') - +from sage.features.four_ti_2 import FourTi2Executable def _sandpile_help(cls, usage, verbose=True): @@ -5122,8 +5117,6 @@ def _set_linear_system(self): This method requires 4ti2. """ - # import os - L = self._sandpile._laplacian.transpose() n = self._sandpile.num_verts() @@ -5172,7 +5165,9 @@ def _set_linear_system(self): sign_file.write('\n') # compute try: - os.system(path_to_zsolve+' -q ' + lin_sys + ' > ' + lin_sys_log) + import os + path_to_zsolve = FourTi2Executable('zsolve').executable + os.system(path_to_zsolve + ' -q ' + lin_sys + ' > ' + lin_sys_log) # process the results zhom_file = open(lin_sys_zhom,'r') except IOError: From f826ded5eaf52bd863c250cadfddd0a56b98f938 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Jul 2021 14:23:53 -0700 Subject: [PATCH 035/355] build/pkgs/4ti2/spkg-configure.m4: Check for executable's with prefix 4ti2_ too --- build/pkgs/4ti2/spkg-configure.m4 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index 291997e6a1a..e01562c50da 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -1,9 +1,11 @@ SAGE_SPKG_CONFIGURE([4ti2], [ SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [ - dnl Debian installs these programs with an executable prefix "4ti2-" - dnl but polymake and our own code do not handle this yet (Singular does). + dnl Debian installs these programs with an executable prefix "4ti2-", + dnl OpenSUSE uses the prefix "4ti2_". + dnl Singular checks for unprefixed and prefixed with "4ti2-". + dnl Polymake does not check for prefixed binaries. m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [ - AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog) + AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog [4ti2_]prog) AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) AC_SUBST([FOURTITWO_]m4_toupper(prog)) ]) From 56016cee03601c3788407eded608138c1f676403 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 7 Jul 2021 22:57:00 +0100 Subject: [PATCH 036/355] use AC_LINK_IFELSE instead of obsolete AC_TRY_LINK --- build/pkgs/4ti2/spkg-configure.m4 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index e01562c50da..a16da8fc4b7 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -17,13 +17,12 @@ SAGE_SPKG_CONFIGURE([4ti2], [ FORTYTWO_LIBS="-l4ti2gmp -lzsolve" CXXFLAGS="${BACKUP_CXXFLAGS} ${FORTYTWO_CXXFLAGS} ${GMP_CFLAGS}" LIBS="${BACKUP_LIBS} ${FORTYTWO_LIBS} ${GMP_LIBS}" - AC_TRY_LINK([ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include "4ti2/4ti2.h" -], -[ _4ti2_rays_create_state(_4ti2_PREC_INT_ARB); -], [ +]], [[ _4ti2_rays_create_state(_4ti2_PREC_INT_ARB); +]])],[ AC_MSG_RESULT([yes]) -], [ +],[ AC_MSG_RESULT([no]) sage_spkg_install_4ti2=yes ]) From 2b45b77946483b06e853506c9013dfeae5d07902 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Jul 2021 10:57:00 -0700 Subject: [PATCH 037/355] sage.feature.join_feature: New, factored out from LatteFeature; use it to implement FourTi2Feature --- src/sage/features/four_ti_2.py | 22 ++++++++- src/sage/features/join_feature.py | 82 +++++++++++++++++++++++++++++++ src/sage/features/latte.py | 42 ++-------------- 3 files changed, 108 insertions(+), 38 deletions(-) create mode 100644 src/sage/features/join_feature.py diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index bdc6399b82e..2889ef24d25 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -1,6 +1,8 @@ from sage.env import SAGE_ENV -from sage.features import Executable +from . import Executable +from .join_feature import JoinFeature + class FourTi2Executable(Executable): r""" @@ -11,3 +13,21 @@ def __init__(self, name): name="4ti2-" + name, executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, spkg="4ti2") + + +class FourTi2(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of the ``4ti2`` executables. + + EXAMPLES:: + + sage: from sage.features.four_ti_2 import FourTi2 + sage: FourTi2().is_present() # optional - 4ti2 + FeatureTestResult('4ti2', True) + """ + def __init__(self): + JoinFeature.__init__(self, '4ti2', + [FourTi2Executable(x) + # same list is tested in build/pkgs/4ti2/spkg-configure.m4 + for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve', + 'rays', 'ppi', 'circuits', 'groebner')]) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py new file mode 100644 index 00000000000..f011b40a7f6 --- /dev/null +++ b/src/sage/features/join_feature.py @@ -0,0 +1,82 @@ +r""" +Join features +""" + +from . import Feature, FeatureTestResult + + +class JoinFeature(Feature): + r""" + Join of several :class:`sage.features.Feature` instances. + + EXAMPLES:: + + sage: from sage.features import Executable + sage: from sage.features.join_feature import JoinFeature + sage: F = JoinFeature("shell-boolean", + ....: (Executable('shell-true', 'true'), + ....: Executable('shell-false', 'false'))) + sage: F.is_present() + FeatureTestResult('shell-boolean', True) + sage: F = JoinFeature("asdfghjkl", + ....: (Executable('shell-true', 'true'), + ....: Executable('xxyyyy', 'xxyyyy-does-not-exist'))) + sage: F.is_present() + FeatureTestResult('xxyyyy', False) + """ + def __init__(self, name, features, spkg=None, url=None): + """ + TESTS: + + The empty join feature is present:: + + sage: from sage.features.join_feature import JoinFeature + sage: JoinFeature("empty", ()).is_present() + FeatureTestResult('empty', True) + """ + if spkg is None: + spkgs = set(f.spkg for f in features if f.spkg) + if len(spkgs) > 1: + raise ValueError('given features have more than one spkg; provide spkg argument') + elif len(spkgs) == 1: + spkg = next(iter(spkgs)) + if url is None: + urls = set(f.url for f in features if f.url) + if len(urls) > 1: + raise ValueError('given features have more than one url; provide url argument') + elif len(urls) == 1: + url = next(iter(urls)) + super().__init__(name, spkg=spkg, url=url) + self._features = features + + def _is_present(self): + r""" + Test for the presence of the join feature. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte()._is_present() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f._is_present() + if not test: + return test + return FeatureTestResult(self, True) + + def is_functional(self): + r""" + Test whether the join feature is functional. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte().is_functional() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f.is_functional() + if not test: + return test + return FeatureTestResult(self, True) diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 5462331177d..6abc450281c 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -3,6 +3,8 @@ Check for LattE """ from . import Executable, Feature, FeatureTestResult +from .join_feature import JoinFeature + LATTE_URL = "https://www.math.ucdavis.edu/~latte/software.php" @@ -27,7 +29,7 @@ def __init__(self): url=LATTE_URL) -class Latte(Feature): +class Latte(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of the ``LattE`` binaries which comes as a part of ``latte_int``. @@ -46,39 +48,5 @@ def __init__(self): sage: isinstance(Latte(), Latte) True """ - Feature.__init__(self, "LattE") - - def _is_present(self): - r""" - Test for the presence of LattE binaries. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte()._is_present() # optional - latte_int - FeatureTestResult('LattE', True) - """ - - test = (Latte_count()._is_present() and - Latte_integrate()._is_present()) - if not test: - return test - - return FeatureTestResult(self, True) - - def is_functional(self): - r""" - Test whether count and integrate are functionals. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte().is_functional() # optional - latte_int - FeatureTestResult('LattE', True) - """ - test = (Latte_count().is_functional() and - Latte_integrate().is_functional()) - if not test: - return test - - return FeatureTestResult(self, True) + JoinFeature.__init__(self, "LattE", + (Latte_count(), Latte_integrate())) From 5c23cc9dfb4d124bc588c3763bf26a2b87ba7cc6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Jul 2021 11:09:06 -0700 Subject: [PATCH 038/355] DocTestReporter: Fix 'sage -t --optional=all' --- src/sage/doctest/reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index 3752213e50a..1074ee8c7ea 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -141,7 +141,7 @@ def have_optional_tag(self, tag): False """ - if tag in self.controller.options.optional: + if self.controller.options.optional is True or tag in self.controller.options.optional: return True if 'external' in self.controller.options.optional: if tag in available_software.seen(): From 1b8634de22051a749b8e54f3684dc2930a713f39 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Jul 2021 11:55:24 -0700 Subject: [PATCH 039/355] sage.doctest.external: Add 4ti2 --- src/sage/doctest/external.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 125f5bdb204..41c9aa63c24 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -303,6 +303,19 @@ def has_rubiks(): from sage.features.rubiks import Rubiks return Rubiks().is_present() +def has_4ti2(): + """ + Test if the 4ti2 package is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_4ti2 + sage: has_4ti2() # optional -- 4ti2 + FeatureTestResult('4ti2', True) + """ + from sage.features.four_ti_2 import FourTi2 + return FourTi2().is_present() + def external_software(): """ Return the alphabetical list of external software supported by this module. @@ -345,7 +358,8 @@ class AvailableSoftware(object): sage: from sage.doctest.external import external_software, available_software sage: external_software - ['cplex', + ['4ti2', + 'cplex', 'ffmpeg', 'graphviz', 'gurobi', From 5557c7930d2627d75934db26962dac570d25a990 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 23 Jul 2021 10:44:17 +0200 Subject: [PATCH 040/355] Explicitely populate cache --- src/sage/schemes/curves/zariski_vankampen.py | 40 ++++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index b9a36734036..ff6d165f44a 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -526,6 +526,40 @@ def roots_interval_cached(f, x0): return result +def populate_roots_interval_cache(inputs): + r""" + Call func:`roots_interval` to the inputs that have not been computed previously, + and cache them. + + INPUT: + + - ``inputs`` -- a list of tuples (f, x0) + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import populate_roots_interval_cache, roots_interval_cache + sage: R. = QQ[] + sage: f = y^5 - x^2 + sage: (f, 3) in roots_interval_cache + False + sage: populate_roots_interval_cache([(f, 3)]) + sage: (f, 3) in roots_interval_cache + True + sage: roots_interval_cache[(f, 3)] + {-1.255469441943070? - 0.9121519421827974?*I: -2.? - 1.?*I, + -1.255469441943070? + 0.9121519421827974?*I: -2.? + 1.?*I, + 0.4795466549853897? - 1.475892845355996?*I: 1.? - 2.?*I, + 0.4795466549853897? + 1.475892845355996?*I: 1.? + 2.?*I, + 14421467174121563/9293107134194871: 2.? + 0.?*I} + + """ + global roots_interval_cache + tocompute = [inp for inp in inputs if inp not in roots_interval_cache] + result = roots_interval(tocompute) + for r in result: + roots_interval_cache[r[0][0]] = r[1] + + @parallel def braid_in_segment(g, x0, x1): """ @@ -901,10 +935,8 @@ def braid_monodromy(f): I = QQbar.gen() segs = [(a[0]+I*a[1], b[0]+I*b[1]) for (a, b) in segs] vertices = list(set(flatten(segs))) - noncachedverts = [(g, v) for v in vertices if (g, v) not in roots_interval_cache] - for noncachedvert in roots_interval(noncachedverts): - roots_interval_cache[noncachedvert[0][0]] = noncachedvert[1] - _ = [roots_interval_cached(g, v) for v in vertices] + tocacheverts = [(g, v) for v in vertices] + populate_roots_interval_cache(tocacheverts) gfac = g.factor() try: braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) From 3c9b80a2551994493f23640344e9ade63240cb01 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sat, 24 Jul 2021 00:52:51 +0200 Subject: [PATCH 041/355] Trac #29581: implement algorithms for chern, pontryagin and euler --- .../characteristic_cohomology_class.py | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/sage/manifolds/differentiable/characteristic_cohomology_class.py diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py new file mode 100644 index 00000000000..e8d52f7ffce --- /dev/null +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -0,0 +1,140 @@ +from sage.manifolds.differentiable.de_rham_cohomology import DeRhamCohomologyClass + +def CharacteristicCohomologyClass(): + pass + +class CharacteristicCohomologyClass_base(DeRhamCohomologyClass): + pass + +class CharacteristicCohomologyClass_complex(CharacteristicCohomologyClass_base): + pass + +class CharacteristicCohomologyClass_real_even(CharacteristicCohomologyClass_base): + pass + +class CharacteristicCohomologyClass_real_odd(CharacteristicCohomologyClass_base): + pass + +#***************************************************************************** +# ALGORITHMS +#***************************************************************************** + +from sage.misc.fast_methods import Singleton +from sage.structure.sage_object import SageObject +from sage.misc.cachefunc import cached_method +from sage.misc.abstract_method import abstract_method +from sage.manifolds.differentiable.affine_connection import AffineConnection +from sage.manifolds.differentiable.bundle_connection import BundleConnection + +class Algorithm_generic(SageObject): + r""" + Algorithm class to generate characteristic forms. + """ + @cached_method + def get(self, nabla): + r""" + Return the global characteristic form w.r.t. a given connection. + """ + if isinstance(nabla, AffineConnection): + vbundle = nabla._domain.tangent_bundle() + elif isinstance(nabla, BundleConnection): + vbundle = nabla._vbundle + else: + raise TypeError(f'{nabla} must be a connection') + dom = nabla._domain + res = dom.mixed_form() + for frame in dom._get_min_covering(nabla._coefficients): + cmatrix = [[nabla.curvature_form(i, j, frame) + for j in vbundle.irange()] + for i in vbundle.irange()] + res_loc = self.get_local(cmatrix) + res.set_restriction(res_loc) + return res + + @abstract_method + def get_local(self, cmat): + pass + +class ChernAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Chern forms. + """ + def get_local(self, cmat): + r""" + Return the local Chern forms for a given curvature matrix. + """ + from sage.symbolic.constants import pi + from sage.libs.pynac.pynac import I + + rk = len(cmat) + dim = cmat[0][0]._domain._dim + ran = min(rk, dim//2) + fac = I / (2*pi) + res = [] + m = cmat + for k in range(1, ran): + c = -sum(m[i][i] for i in range(rk)) / k + res.append(fac * c) + for i in range(rk): + m[i][i] += c + fac *= I / (2*pi) + m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + res -= fac * sum(m[i][i] for i in range(rk)) / ran + return res + + +class PontryaginAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Pontryagin forms. + """ + def get_local(self, cmat): + r""" + Return the local Pontryagin forms for a given curvature matrix. + """ + from sage.symbolic.constants import pi + + rk = len(cmat) + dim = cmat[0][0]._domain._dim + ran = min(rk//2, dim//4) + fac = -1 / (2*pi)**2 + res = [] + m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) + for l in range(rk)) + for j in range(rk)] for i in range(rk)] + for k in range(1, ran): + c = -sum(m[i][i] for i in range(rk)) / (2*k) + res.append(fac * c) + for i in range(rk): + m[i][i] += c + fac *= -1 / (2*pi)**2 + m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + res -= fac * sum(m[i][i] for i in range(rk)) / (2*ran) + return res + +class EulerAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Euler forms. + """ + def get_local(self, cmat): + r""" + Return the local Euler form for a given curvature matrix. + """ + from sage.symbolic.constants import pi + + rk = len(cmat) + ran = rk // 2 + m = a = [cmat[i].copy() for i in range(rk)] + for i in range(0, rk, 2): + m[i], m[i+1] = m[i+1], m[i] # swap entries + for k in range(rk): + m[k][i+1] = -m[k][i+1] + for k in range(1, ran): + c = -sum(m[i][i] for i in range(rk)) / (2*k) + for i in range(rk): + m[i][i] += c + m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + c = -sum(m[i][i] for i in range(rk)) / (2*rk) + return (-1/(2*pi))**rk * c From 03529f8919357f98b65ee033e8dc5c7d48b2fa42 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sat, 24 Jul 2021 02:03:17 +0200 Subject: [PATCH 042/355] Trac #29581: return mixed form --- .../characteristic_cohomology_class.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index e8d52f7ffce..1b4ae025270 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -66,15 +66,16 @@ def get_local(self, cmat): from sage.symbolic.constants import pi from sage.libs.pynac.pynac import I + dom = cmat[0][0]._domain rk = len(cmat) - dim = cmat[0][0]._domain._dim + dim = dom._dim ran = min(rk, dim//2) fac = I / (2*pi) - res = [] + res = dom.mixed_form_algebra().one() m = cmat for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / k - res.append(fac * c) + res += fac * c for i in range(rk): m[i][i] += c fac *= I / (2*pi) @@ -94,17 +95,18 @@ def get_local(self, cmat): """ from sage.symbolic.constants import pi + dom = cmat[0][0]._domain rk = len(cmat) - dim = cmat[0][0]._domain._dim + dim = dom._dim ran = min(rk//2, dim//4) fac = -1 / (2*pi)**2 - res = [] + res = dom.mixed_form_algebra().one() m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / (2*k) - res.append(fac * c) + res += fac * c for i in range(rk): m[i][i] += c fac *= -1 / (2*pi)**2 @@ -123,6 +125,8 @@ def get_local(self, cmat): """ from sage.symbolic.constants import pi + dom = cmat[0][0]._domain + A = dom.mixed_form_algebra() rk = len(cmat) ran = rk // 2 m = a = [cmat[i].copy() for i in range(rk)] @@ -137,4 +141,5 @@ def get_local(self, cmat): m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] c = -sum(m[i][i] for i in range(rk)) / (2*rk) - return (-1/(2*pi))**rk * c + c *= (-1/(2*pi))**rk # normalize + return A(c) From 646e182e65fc247d0d2da9aabcad5f892a471a89 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Jul 2021 13:50:31 -0700 Subject: [PATCH 043/355] src/sage/features/four_ti_2.py: Move import of SAGE_ENV inside the __init__ method, to remove confusion of sage.misc.dev_tools --- src/sage/features/four_ti_2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index 2889ef24d25..7f53a1135b9 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -1,5 +1,3 @@ -from sage.env import SAGE_ENV - from . import Executable from .join_feature import JoinFeature @@ -9,6 +7,7 @@ class FourTi2Executable(Executable): Feature for the 4ti2 executables. """ def __init__(self, name): + from sage.env import SAGE_ENV Executable.__init__(self, name="4ti2-" + name, executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, From 21bb3e3022c84ee821962dbe1bfcf59e08364a60 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 30 Jul 2021 10:17:46 +0200 Subject: [PATCH 044/355] initial version --- .../data_structures/coefficient_stream.py | 315 ++++++++++- src/sage/rings/all.py | 2 +- src/sage/rings/lazy_laurent_series.py | 493 +++++++++++++++++- src/sage/rings/lazy_laurent_series_ring.py | 260 ++++++++- 4 files changed, 1064 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index f5da2a09023..2633573915b 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -107,7 +107,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity - +from sage.arith.misc import divisors class CoefficientStream(): """ @@ -1146,6 +1146,175 @@ def iterate_coefficients(self): yield c n += 1 +class CoefficientStream_dirichlet_convolution(CoefficientStream_binary_commutative): + """Operator for the convolution of two coefficient streams. + + We are assuming commutativity of the coefficient ring here. + Moreover, the valuation must be non-negative. + + INPUT: + + - ``left`` -- stream of coefficients on the left side of the operator + - ``right`` -- stream of coefficients on the right side of the operator + + The coefficient of `n^{-s}` in the convolution of `l` and `r` + equals `\sum_{k | n} l_k r_{n/k}`. Note that `l[n]` yields the + coefficient of `(n+1)^{-s}`! + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_mul, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 0) + sage: g = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 0) + sage: h = CoefficientStream_dirichlet_convolution(f, g) + sage: [h[i] for i in range(1, 11)] + + sage: u = CoefficientStream_dirichlet_convolution(g, f) + sage: [u[i] for i in range(1, 11)] + + """ + def __init__(self, left, right): + """ + Initalize ``self``. + """ + if left._is_sparse != right._is_sparse: + raise NotImplementedError + + assert left._approximate_valuation > 0 and right._approximate_valuation > 0 + + vl = left._approximate_valuation + vr = right._approximate_valuation + a = vl * vr + super().__init__(left, right, left._is_sparse, a) + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + """ + c = ZZ.zero() + for k in divisors(n): + val = self._left[k] + if val: + c += val * self._right[n//k] + return c + + def iterate_coefficients(self): + """ + A generator for the coefficients of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_mul) + sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, False, 0) + sage: g = CoefficientStream_coefficient_function(lambda n: n^3, ZZ, False, 0) + sage: h = CoefficientStream_mul(f, g) + sage: n = h.iterate_coefficients() + sage: [next(n) for i in range(1, 11)] + [0, 1, 9, 36, 100, 225, 441, 784, 1296, 2025] + """ + n = self._offset + while True: + c = ZZ.zero() + for k in divisors(n): + val = self._left[k] + if val: + c += val * self._right[n//k] + yield c + n += 1 + +class CoefficientStream_dirichlet_inv(CoefficientStream_unary): + """ + Operator for multiplicative inverse of the stream. + + INPUT: + + - ``series`` -- a :class:`CoefficientStream` + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 1) + sage: g = CoefficientStream_inv(f) + sage: [g[i] for i in range(10)] + [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + """ + def __init__(self, series): + """ + Initialize. + + TESTS:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: -1, ZZ, True, 0) + sage: g = CoefficientStream_inv(f) + sage: [g[i] for i in range(10)] + [-1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + """ + assert series[1], "the Dirichlet inverse only exists if the coefficient with index 1 is non-zero" + super().__init__(series, series._is_sparse, 1) + + self._ainv = ~series[1] + self._zero = ZZ.zero() + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 1) + sage: g = CoefficientStream_inv(f) + sage: g.get_coefficient(5) + 0 + sage: [g.get_coefficient(i) for i in range(10)] + [-2, 1, 0, 0, 0, 0, 0, 0, 0, 0] + """ + if n == 1: + return self._ainv + c = self._zero + for k in divisors(n): + if k < n: + val = self._series[n//k] + if val: + c += self[k] * val + return -c * self._ainv + + def iterate_coefficients(self): + """ + A generator for the coefficients of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: n^2, ZZ, False, 1) + sage: g = CoefficientStream_inv(f) + sage: n = g.iterate_coefficients() + sage: [next(n) for i in range(10)] + [1, -4, 7, -8, 8, -8, 8, -8, 8, -8] + """ + n = 1 + yield self._ainv + while True: + n += 1 + c = self._zero + for k in divisors(n): + if k < n: + val = self._series[n//k] + if val: + c += self[k] * val + yield -c * self._ainv + + class CoefficientStream_div(CoefficientStream_binary): """ @@ -1415,6 +1584,7 @@ def iterate_coefficients(self): yield self._series[n] * self._scalar n += 1 + class CoefficientStream_neg(CoefficientStream_unary): """ Operator for negative of the stream. @@ -1575,7 +1745,7 @@ def iterate_coefficients(self): class CoefficientStream_apply_coeff(CoefficientStream_unary): """ - Return the stream with ``function`` applied to each coefficient of this series. + Return the series with ``function`` applied to each coefficient of this series. INPUT: @@ -1647,3 +1817,144 @@ def iterate_coefficients(self): yield c n += 1 +class CoefficientStream_exact(CoefficientStream): + r""" + A stream of eventually constant coefficients. + + INPUT: + + - ``initial_values`` -- a list of initial values + + - ``is_sparse`` -- a boolean, which specifies whether the + series is sparse + + - ``valuation`` -- (default: 0), an integer, determining the + degree of the first element of ``initial_values`` + + - ``degree`` -- (default: None), an integer, determining the + degree of the first element which is known to be equal to + ``constant`` + + - ``constant`` -- (default: 0), an integer, the coefficient + of every index larger than or equal to ``degree`` + """ + def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, valuation=None): + """ + Initialize a series that is known to be eventually geometric. + + TESTS:: + + sage: from sage.data_structures.coefficient_stream import CoefficientStream_exact + sage: CoefficientStream_exact([], False)[0] + 0 + + """ + if constant is None: + self._constant = ZZ.zero() + else: + self._constant = constant + if valuation is None: + valuation = 0 + if degree is None: + self._degree = valuation + len(initial_coefficients) + else: + self._degree = degree + + assert valuation + len(initial_coefficients) <= self._degree + + for i, v in enumerate(initial_coefficients): + if v: + valuation += i + initial_coefficients = initial_coefficients[i:] + for j, w in enumerate(reversed(initial_coefficients)): + if w: + break + initial_coefficients.pop() + self._initial_coefficients = tuple(initial_coefficients) + break + else: + valuation = self._degree + self._initial_coefficients = tuple() + + assert self._initial_coefficients or self._constant, "CoefficientStream_exact should only be used for non-zero streams" + + super().__init__(is_sparse, valuation) + + def __getitem__(self, n): + """ + Return the coefficient of the term with exponent ``n`` of the series. + + INPUT: + + - ``n`` -- integer, the degree for which the coefficient is required + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import CoefficientStream_exact + sage: s = CoefficientStream_exact([], False) + sage: [s[i] for i in range(-2, 5)] + [0, 0, 0, 0, 0, 0, 0] + + sage: s = CoefficientStream_exact([], False, constant=1) + sage: [s[i] for i in range(-2, 5)] + [0, 0, 1, 1, 1, 1, 1] + + sage: s = CoefficientStream_exact([2], False, constant=1) + sage: [s[i] for i in range(-2, 5)] + [0, 0, 2, 1, 1, 1, 1] + + sage: s = CoefficientStream_exact([2], False, valuation=-1, constant=1) + sage: [s[i] for i in range(-2, 5)] + [0, 2, 1, 1, 1, 1, 1] + + sage: s = CoefficientStream_exact([2], False, valuation=-1, degree=2, constant=1) + sage: [s[i] for i in range(-2, 5)] + [0, 2, 0, 0, 1, 1, 1] + + sage: t = CoefficientStream_exact([0, 2, 0], False, valuation=-2, degree=2, constant=1) + sage: t == s + True + """ + if n >= self._degree: + return self._constant + i = n - self._approximate_valuation + if i < 0 or i >= len(self._initial_coefficients): + return 0 + return self._initial_coefficients[i] + + def valuation(self): + return self._approximate_valuation + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = 1 + z + z^2 + z^3 + sage: {f: 1} + {1 + z + z^2 + z^3: 1} + """ + return hash((self._initial_coefficients, self._degree, self._constant)) + + def __eq__(self, other): + """ + Test the equality between ``self`` and ``other``. + + INPUT: + + - ``other`` -- a lazy Laurent series which is known to be eventaully geometric + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = 1 + z + z^2 + z^3 + sage: m = 1 + z + z^2 + z^3 + sage: f == m + True + """ + return (isinstance(other, type(self)) + and self._degree == other._degree + and self._initial_coefficients == other._initial_coefficients + and self._constant == other._constant) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 50f0a4e190c..02a6eb56f91 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,7 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', 'LazyLaurentSeriesRing') +lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 8e0c2801b22..0ea73e30549 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -92,9 +92,12 @@ CoefficientStream, CoefficientStream_inexact, CoefficientStream_zero, + CoefficientStream_exact, CoefficientStream_eventually_geometric, CoefficientStream_coefficient_function, - CoefficientStream_uninitialized + CoefficientStream_uninitialized, + CoefficientStream_dirichlet_convolution, + CoefficientStream_dirichlet_inv ) @@ -352,7 +355,9 @@ def __call__(self, g): P = g.parent() # g = 0 case - if (not isinstance(g, LazyLaurentSeries) and not g) or (isinstance(g, LazyLaurentSeries) and isinstance(g._coeff_stream, CoefficientStream_zero)): + if ((not isinstance(g, LazyLaurentSeries) and not g) + or (isinstance(g, LazyLaurentSeries) + and isinstance(g._coeff_stream, CoefficientStream_zero))): if self._coeff_stream._approximate_valuation >= 0: return P(self[0]) # Perhaps we just don't yet know if the valuation is non-negative @@ -1363,3 +1368,487 @@ def define(self, s): raise ValueError("series already defined") self._coeff_stream._target = s._coeff_stream +###################################################################### + +class LazyDirichletSeries(ModuleElement): + r""" + A Dirichlet series where the coefficients are computed lazily. + + INPUT: + + - ``parent`` -- The base ring for the series + + - ``coeff_stream`` -- The auxiliary class that handles the coefficient stream + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(constant=1)^2; f + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + sage: f.coefficient(100) == number_of_divisors(100) + True + + Lazy Dirichlet series is picklable:: + + sage: g = loads(dumps(f)) + sage: g + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + sage: g == f + True + """ + + def __init__(self, parent, coeff_stream): + """ + Initialize the series. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(QQbar, 'z') + sage: g = L(constant=1) + sage: TestSuite(g).run() + """ + ModuleElement.__init__(self, parent) + self._coeff_stream = coeff_stream + + def __getitem__(self, n): + """ + Return the coefficient of the term with exponent ``n`` of the series. + + INPUT: + + - ``n`` -- integer + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(lambda n: n) + sage: [f[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: f[1:11] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + """ + R = self.base_ring() + if isinstance(n, slice): + if n.stop is None: + raise NotImplementedError("cannot list an infinite set") + start = n.start if n.start is not None else self._coeff_stream.valuation() + step = n.step if n.step is not None else 1 + return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] + return R(self._coeff_stream[n]) + + def _mul_(self, other): + """ + Return the product of this series with ``other``. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L(constant=1); g + 1 + 1/(2^z) + 1/(3^z) + ... + sage: g*g + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + sage: [number_of_divisors(n) for n in range(1, 8)] + [1, 2, 2, 3, 2, 4, 2] + + sage: mu = L(moebius); mu + 1 + -1/2^z + -1/3^z + -1/5^z + 1/(6^z) + -1/7^z + ... + sage: g*mu + 1 + ... + sage: L.one() * mu is mu + True + sage: mu * L.one() is mu + True + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + coeff = CoefficientStream_dirichlet_convolution(left, right) + return P.element_class(P, coeff) + + def _add_(self, other): + """ + Return the sum of this series with ``other``. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) + and isinstance(right, CoefficientStream_exact)): + c = left._constant + right._constant + v = min(left.valuation(), right.valuation()) + d = max(left._degree(), right._degree()) + initial_coefficients = [left[i] + right[i] for i in range(v, d)] + if not any(initial_terms) and not c: + return P.zero() + return P.element_class(P, CoefficientStream_exact(initial_terms, P._sparse, + valuation=v, degree=d, constant=c)) + return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) + + def _rmul_(self, scalar): + """ + Return the scalar multiplication of this series by ``scalar``. + + INPUT: + + - ``scalar`` -- an element of the base ring + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L.gen(1) + sage: 2*g + 2/2^z + sage: -1*g + -1/2^z + sage: 0*g + 0 + sage: M = L(lambda n: n); M + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + sage: M * 3 + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: M = L(lambda n: n); M + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + sage: M * 3 + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + + TESTS:: + + sage: 1 * M is M + True + sage: M * 1 is M + True + """ + P = self.parent() + if not scalar: + return P.zero() + if scalar == 1: + return self + + if isinstance(self._coeff_stream, CoefficientStream_exact): + c = scalar * self._coeff_stream._constant + v = self._coeff_stream.valuation() + initial_coefficients = [scalar * v for v in self._coeff_stream._initial_coefficients] + return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + valuation=v, constant=c, + degree=self._coeff_stream._degree)) + + return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) + + _lmul_ = _rmul_ + + def __invert__(self): + """ + Return the multiplicative inverse of the element. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) + sage: ~L(constant=1) - L(moebius) + 0 + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: ~L(constant=1) - L(moebius) + 0 + + """ + P = self.parent() + return P.element_class(P, CoefficientStream_dirichlet_inv(self._coeff_stream)) + + + def coefficient(self, n): + """ + Return the coefficient of the term with exponent ``n`` of the series. + + INPUT: + + - ``n`` -- integer + + EXAMPLES:: + + TESTS:: + + """ + return self.__getitem__(n) + + def map_coefficients(self, func, ring=None): + """ + Return the series with ``func`` applied to each coefficient of this series. + + INPUT: + + - ``func`` -- Python function that takes in a coefficient and returns + a new coefficient + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + P = self.parent() + R = P.base_ring() + if isinstance(self._coeff_stream, CoefficientStream_exact): + p = p.map_coefficients(func) + c = func(c) + if not p and not c: + return P.zero() + return P.element_class(P, CoefficientStream_exact(p, self._coeff_stream._is_sparse, c, d)) + return P.element_class(P, CoefficientStream_apply_coeff(self._coeff_stream, func, R)) + + def change_ring(self, ring): + """ + Return this series with coefficients converted to elements of ``ring``. + + INPUT: + + - ``ring`` -- a ring + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) + """ + from .lazy_laurent_series_ring import LazyDirichletSeriesRing + Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) + return Q.element_class(Q, self._coeff_stream) + + def truncate(self, d): + """ + Return this series with its terms of degree >= ``d`` truncated. + + INPUT: + + - ``d`` -- integer + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) + """ + P = self.parent() + R = P._laurent_poly_ring + z = R.gen() + p = R.sum(self[i] * z**i for i in range(self._coeff_stream._approximate_valuation, d)) + return P.element_class(P, CoefficientStream_eventually_geometric(p, P._sparse, ZZ.zero(), d)) + + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer, the power to which to raise the series + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + if n == 0: + return self.parent().one() + + return generic_power(self, n) + + def prec(self): + """ + Return the precision of the series, which is infinity. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(1) + sage: f.prec() + +Infinity + """ + return infinity + + def valuation(self): + """ + Return the valuation of the series. + + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: mu = L(moebius); mu.valuation() + 1 + sage: (mu - mu).valuation() # known bug + +Infinity + sage: g = L(constant=1, valuation=2) + sage: g.valuation() + 2 + sage: (g*g).valuation() + 4 + """ + return self._coeff_stream.valuation() + + def _repr_(self): + """ + Return the string representation of this Dirichlet series. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return '0' + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return 'Uninitialized Lazy Dirichlet Series' + + atomic_repr = self.base_ring()._repr_option('element_is_atomic') + X = self.parent().variable_name() + v = self._coeff_stream._approximate_valuation + + if not isinstance(self._coeff_stream, CoefficientStream_exact): + m = v + 7 # long enough + else: + m = self._coeff_stream._degree + 3 + + # Use the symbolic ring printing + from sage.calculus.var import var + from sage.symbolic.ring import SR + variable = var(self.parent().variable_name()) + ret = " + ".join([repr(SR(self._coeff_stream[i])*i**(-variable)) + for i in range(v, m) if self._coeff_stream[i]]) + if not ret: + return "0" + # TODO: Better handling when ret == 0 but we have not checked up to the constant term + + if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: + return ret + return ret + ' + ...' + + def _richcmp_(self, other, op): + """ + Compare ``self` with ``other`` with respect to the comparison operator ``op``. + + Equality is verified if the corresponding coefficients of both series + can be checked for equality without computing coefficients + indefinitely. Otherwise an exception is raised to declare that + equality is not decidable. + + Inequality is not defined for lazy Dirichlet series. + + INPUT: + + - ``other`` -- another Dirichlet series + + - ``op`` -- comparison operator + + TESTS:: + + sage: L = LazyDirichletSeriesRing(QQ, "z") + """ + if op is op_EQ: + if isinstance(self._coeff_stream, CoefficientStream_zero): # self == 0 + return isinstance(other._coeff_stream, CoefficientStream_zero) + if isinstance(other._coeff_stream, CoefficientStream_zero): # self != 0 but other == 0 + return False + + if (not isinstance(self._coeff_stream, CoefficientStream_eventually_geometric) + or not isinstance(other._coeff_stream, CoefficientStream_eventually_geometric)): + # One of the lazy laurent series is not known to eventually be constant + # Implement the checking of the caches here. + n = min(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) + m = max(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) + for i in range(n, m): + if self[i] != other[i]: + return False + if self._coeff_stream == other._coeff_stream: + return True + raise ValueError("undecidable as lazy Dirichlet series") + + # Both are CoefficientStream_eventually_geometric, which implements a full check + return self._coeff_stream == other._coeff_stream + + if op is op_NE: + return not (self == other) + + return False + + def __hash__(self): + """ + Return the hash of ``self`` + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + """ + return hash(self._coeff_stream) + + def __bool__(self): + """ + Test whether ``self`` is not zero. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return False + + for a in self._coeff_stream._cache: + if a: + return True + if self[self._coeff_stream._approximate_valuation]: + return True + raise ValueError("undecidable as lazy Dirichlet series") + + def define(self, s): + r""" + Define an equation by ``self = s``. + + INPUT:: + + - ``s`` -- a Dirichlet series + + EXAMPLES: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L(constant=1, valuation=2) + sage: F = L(None); F.define(1 + g*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] + sage: oeis(_) # optional, internet + 0: A002033: Number of perfect partitions of n. + 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. + ... + + sage: F = L(None); F.define(1 + g*F*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] + + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: g = L(constant=1, valuation=2) + sage: e = L(None) + sage: e.define(1 + g*e) + sage: e.define(1 + g*e) + Traceback (most recent call last): + ... + ValueError: series already defined + """ + if not isinstance(self._coeff_stream, CoefficientStream_uninitialized) or self._coeff_stream._target is not None: + raise ValueError("series already defined") + self._coeff_stream._target = s._coeff_stream diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index 54a381026c7..c3b11abb71d 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -78,12 +78,14 @@ from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from .integer_ring import ZZ +from .infinity import infinity from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_generic -from .lazy_laurent_series import LazyLaurentSeries +from .lazy_laurent_series import LazyLaurentSeries, LazyDirichletSeries from sage.data_structures.coefficient_stream import ( CoefficientStream_zero, + CoefficientStream_exact, CoefficientStream_coefficient_function, CoefficientStream_eventually_geometric, CoefficientStream_uninitialized @@ -373,3 +375,259 @@ def zero(self): """ return self.element_class(self, CoefficientStream_zero(self._sparse)) + +###################################################################### + +class LazyDirichletSeriesRing(UniqueRepresentation, Parent): + """ + Lazy Dirichlet series ring. + + INPUT: + + - ``base_ring`` -- base ring of this Dirichlet series ring + + - ``names`` -- name of the generator of this Dirichlet series ring + + EXAMPLES:: + + sage: LazyDirichletSeriesRing(ZZ, 't') + Lazy Dirichlet Series Ring in t over Integer Ring + """ + Element = LazyDirichletSeries + + def __init__(self, base_ring, names, sparse=False, category=None): + """ + Initialize the ring. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, 't') + sage: TestSuite(L).run(skip='_test_elements') + """ + if base_ring.characteristic() > 0: + raise ValueError("positive characteristic not allowed for Dirichlet series") + + self._sparse = sparse + Parent.__init__(self, base=base_ring, names=names, + category=MagmasAndAdditiveMagmas().or_subcategory(category)) + + def _repr_(self): + """ + String representation of this Dirichlet series ring. + + EXAMPLES:: + + sage: LazyDirichletSeriesRing(QQbar, 'z') + Lazy Dirichlet Series Ring in z over Algebraic Field + """ + return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) + + @cached_method + def gen(self, n=0): + """ + Return the `n`-th generator of this Dirichlet series ring. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.gen() + 1 + sage: L.gen(3) + 1/(4^z) + + """ + assert n >= 0 + coeff_stream = CoefficientStream_exact([1], self._sparse, valuation=n+1, constant=ZZ.zero()) + return self.element_class(self, coeff_stream) + + def ngens(self): + """ + Return the number of generators of this Dirichlet series ring. + + This is always `\infty`. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "s") + sage: L.ngens() + +Infinity + """ + return infinity + + @cached_method + def gens(self): + """ + Return the tuple of the generator. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: L.gens() + Lazy family ((i))_{i in Positive integers} + sage: L.gens()[1] + 1/(2^z) + + """ + from sage.sets.family import Family + from sage.sets.positive_integers import PositiveIntegers + + return Family(PositiveIntegers(), lambda n: self.gen(n)) + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(QQ) + False + """ + if self.base_ring().has_coerce_map_from(S): + return True + + return False + + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None): + """ + Construct a Dirichlet series from ``x``. + + INPUT: + + - ``x`` -- a Dirichlet series, a Dirichlet polynomial, a Python function, or a list of elements in the base ring + + - ``constant`` -- either ``None`` (default: ``None``) or pair of an element of the base ring and an integer + + EXAMPLES:: + + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L(3) + 3 + sage: L(lambda i: i, constant=1, degree=6) + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + ... + + sage: X = L(constant=5, degree=3); X + 5/3^z + 5/4^z + 5/5^z + ... + sage: X.valuation() + 3 + sage: e = L(moebius); e + 1 + -1/2^z + -1/3^z + -1/5^z + 1/(6^z) + -1/7^z + ... + + sage: L([0], constant=1) + 1/(2^z) + 1/(3^z) + 1/(4^z) + ... + + sage: L(constant=1) + 1 + 1/(2^z) + 1/(3^z) + ... + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: + + sage: f = L([1,2,3,4], 4); f + 1/(4^z) + 2/5^z + 3/6^z + 4/7^z + sage: g = L([1,3,5,7,9], 6, -1); g + 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z + -1/11^z + -1/12^z + -1/13^z + ... + + TESTS:: + + sage: L = LazyDirichletSeriesRing(GF(2), 'z') + Traceback (most recent call last): + ... + ValueError: positive characteristic not allowed for Dirichlet series + + TODO:: + + Add a method to make a copy of self._sparse. + """ + if valuation is None: + valuation = 1 + assert valuation > 0, "the valuation of a Dirichlet series must be positive" + + if x is None: + return self.element_class(self, CoefficientStream_uninitialized(self._sparse, valuation)) + + BR = self.base_ring() + if constant is None: + constant = ZZ.zero() + elif isinstance(constant, (tuple, list)): + constant, degree = constant + constant = BR(constant) + + if x in BR: + x = BR(x) + if not x and not constant: + coeff_stream = CoefficientStream_zero(self._sparse) + return self.element_class(self, coeff_stream) + elif not x: + x = [] + else: + x = [x] + if isinstance(x, (tuple, list)): + coeff_stream = CoefficientStream_exact(x, self._sparse, + valuation=valuation, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + + if isinstance(x, LazyDirichletSeries): + if x._coeff_stream._is_sparse is self._sparse: + return self.element_class(self, x._coeff_stream) + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + if callable(x): + if degree is not None: + if constant is None: + constant = ZZ.zero() + x = [BR(x(i)) for i in range(1, degree)] + coeff_stream = CoefficientStream_exact(x, self._sparse, + valuation=valuation, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + coeff_stream = CoefficientStream_coefficient_function(x, BR, self._sparse, valuation) + return self.element_class(self, coeff_stream) + raise ValueError(f"unable to convert {x} into a lazy Dirichlet series") + + def _an_element_(self): + """ + Return a Dirichlet series in this ring. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.an_element() + 1/(4^z) + 1/(5^z) + 1/(6^z) + ... + """ + c = self.base_ring().an_element() + return self.element_class(self, CoefficientStream_exact([], self._sparse, constant=c, valuation=4)) + + @cached_method + def one(self): + """ + Return the constant series `1`. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.one() + 1 + """ + return self.element_class(self, CoefficientStream_exact([1], self._sparse, valuation=1)) + + @cached_method + def zero(self): + """ + Return the zero series. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, CoefficientStream_zero(self._sparse)) From a5e5aea6a5c609c58972486ea057d9dee79890d8 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 31 Jul 2021 21:42:42 +0200 Subject: [PATCH 045/355] fix doctests --- .../data_structures/coefficient_stream.py | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index ca08e93a4be..710563ca0dc 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -1161,14 +1161,18 @@ class CoefficientStream_dirichlet_convolution(CoefficientStream_binary_commutati EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_mul, CoefficientStream_coefficient_function) - sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 0) - sage: g = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 0) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_dirichlet_convolution, CoefficientStream_coefficient_function, CoefficientStream_exact) + sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 1) + sage: g = CoefficientStream_exact([0], True, constant=1) sage: h = CoefficientStream_dirichlet_convolution(f, g) - sage: [h[i] for i in range(1, 11)] + sage: [h[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] + sage: [sigma(n) for n in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] sage: u = CoefficientStream_dirichlet_convolution(g, f) - sage: [u[i] for i in range(1, 11)] + sage: [u[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] """ def __init__(self, left, right): @@ -1178,7 +1182,7 @@ def __init__(self, left, right): if left._is_sparse != right._is_sparse: raise NotImplementedError - assert left._approximate_valuation > 0 and right._approximate_valuation > 0 + assert left._approximate_valuation > 0 and right._approximate_valuation > 0, "Dirichlet convolution is only defined for coefficient streams with valuation at least 1" vl = left._approximate_valuation vr = right._approximate_valuation @@ -1204,16 +1208,6 @@ def get_coefficient(self, n): def iterate_coefficients(self): """ A generator for the coefficients of ``self``. - - EXAMPLES:: - - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_mul) - sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, False, 0) - sage: g = CoefficientStream_coefficient_function(lambda n: n^3, ZZ, False, 0) - sage: h = CoefficientStream_mul(f, g) - sage: n = h.iterate_coefficients() - sage: [next(n) for i in range(1, 11)] - [0, 1, 9, 36, 100, 225, 441, 784, 1296, 2025] """ n = self._offset while True: @@ -1235,11 +1229,13 @@ class CoefficientStream_dirichlet_inv(CoefficientStream_unary): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_dirichlet_inv, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 1) - sage: g = CoefficientStream_inv(f) + sage: g = CoefficientStream_dirichlet_inv(f) sage: [g[i] for i in range(10)] - [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + sage: [moebius(i) for i in range(10)] + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] """ def __init__(self, series): """ @@ -1247,11 +1243,12 @@ def __init__(self, series): TESTS:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) - sage: f = CoefficientStream_coefficient_function(lambda n: -1, ZZ, True, 0) - sage: g = CoefficientStream_inv(f) - sage: [g[i] for i in range(10)] - [-1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_exact, CoefficientStream_dirichlet_inv) + sage: f = CoefficientStream_exact([0, 0], True, constant=1) + sage: g = CoefficientStream_dirichlet_inv(f) + Traceback (most recent call last): + ... + AssertionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero """ assert series[1], "the Dirichlet inverse only exists if the coefficient with index 1 is non-zero" super().__init__(series, series._is_sparse, 1) @@ -1266,16 +1263,6 @@ def get_coefficient(self, n): INPUT: - ``n`` -- integer; the degree for the coefficient - - EXAMPLES:: - - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) - sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 1) - sage: g = CoefficientStream_inv(f) - sage: g.get_coefficient(5) - 0 - sage: [g.get_coefficient(i) for i in range(10)] - [-2, 1, 0, 0, 0, 0, 0, 0, 0, 0] """ if n == 1: return self._ainv @@ -1290,15 +1277,6 @@ def get_coefficient(self, n): def iterate_coefficients(self): """ A generator for the coefficients of ``self``. - - EXAMPLES:: - - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_inv, CoefficientStream_coefficient_function) - sage: f = CoefficientStream_coefficient_function(lambda n: n^2, ZZ, False, 1) - sage: g = CoefficientStream_inv(f) - sage: n = g.iterate_coefficients() - sage: [next(n) for i in range(10)] - [1, -4, 7, -8, 8, -8, 8, -8, 8, -8] """ n = 1 yield self._ainv @@ -1743,7 +1721,7 @@ def iterate_coefficients(self): class CoefficientStream_apply_coeff(CoefficientStream_unary): """ - Return the series with ``function`` applied to each coefficient of this series. + Return the stream with ``function`` applied to each coefficient of this series. INPUT: From 65210a30e710c1f53633a7403e9841f76e6b1be2 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 1 Aug 2021 11:38:26 +0200 Subject: [PATCH 046/355] factor out add --- src/sage/rings/lazy_laurent_series.py | 170 ++++++++++++++------------ 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index c2f235b5d72..54f758c64bb 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -99,8 +99,88 @@ CoefficientStream_dirichlet_inv ) +class LazySequencesModuleElement(ModuleElement): + def _add_(self, other): + """ + Return the sum of ``self`` and ``other``. -class LazyLaurentSeries(ModuleElement): + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: (1 - z)*(1 - z) + 1 - 2*z + z^2 + sage: (1 - z)*(1 - z)*(1 - z) + 1 - 3*z + 3*z^2 - z^3 + sage: z + z + 2*z + sage: z^2 + 3*z^2 + 4*z^2 + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M + N; P + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... + + sage: A = L(1, constant=2, degree=3) + sage: B = L(2, constant=-2, degree=5) + sage: A + B + 3 + 2*z^3 + 2*z^4 + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M + N; P + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: s = L(lambda n: n); s + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + sage: t = L(constant=1); t + 1 + 1/(2^z) + 1/(3^z) + ... + sage: s + t + 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + ... + + sage: r = L(constant=-1) + sage: r + t + 0 + + sage: r = L([1,2,3]) + sage: r + t + 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + ... + + sage: r = L([1,2,3], constant=-1) + sage: r + t + 2 + 3/2^z + 4/3^z + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) + and isinstance(right, CoefficientStream_exact)): + approximate_valuation = min(left.valuation(), right.valuation()) + degree = max(left._degree, right._degree) + initial_coefficients = [left[i] + right[i] for i in range(approximate_valuation, degree)] + constant = left._constant + right._constant + if not any(initial_coefficients) and not constant: + return P.zero() + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, + constant=constant, + degree=degree, + valuation=approximate_valuation) + return P.element_class(P, coeff_stream) + return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) + + +class LazyLaurentSeries(LazySequencesModuleElement): r""" A Laurent series where the coefficients are computed lazily. @@ -483,65 +563,23 @@ def _mul_(self, other): return self return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream)) - def _add_(self, other): - """ - Return the sum of this series with ``other``. - - INPUT: - - - ``other`` -- other series - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: (1 - z)*(1 - z) - 1 - 2*z + z^2 - sage: (1 - z)*(1 - z)*(1 - z) - 1 - 3*z + 3*z^2 - z^3 - sage: z + z - 2*z - sage: z^2 + 3*z^2 - 4*z^2 - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M + N; P - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... - - sage: A = L(1, constant=2, degree=3) - sage: B = L(2, constant=-2, degree=5) - sage: A + B - 3 + 2*z^3 + 2*z^4 - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M + N; P - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... - """ P = self.parent() left = self._coeff_stream right = other._coeff_stream if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): - R = P._laurent_poly_ring - z = R.gen() - pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)])) - pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)])) + and isinstance(right, CoefficientStream_exact)): c = left._constant + right._constant - d = max(left._degree, right._degree) - pl += R([left._constant]*(d-left._degree)).shift(left._degree) - pr += R([right._constant]*(d-right._degree)).shift(right._degree) - p = pl + pr - if not p and not c: + v = min(left.valuation(), right.valuation()) + d = max(left._degree(), right._degree()) + initial_coefficients = [left[i] + right[i] for i in range(v, d)] + if not any(initial_terms) and not c: return P.zero() - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=p.valuation(), constant=c, degree=d)) + return P.element_class(P, CoefficientStream_exact(initial_terms, P._sparse, + valuation=v, degree=d, constant=c)) return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) + + def _sub_(self, other): """ Return the series of this series minus ``other`` series. @@ -1412,7 +1450,7 @@ def define(self, s): ###################################################################### -class LazyDirichletSeries(ModuleElement): +class LazyDirichletSeries(LazySequencesModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. @@ -1519,32 +1557,6 @@ def _mul_(self, other): coeff = CoefficientStream_dirichlet_convolution(left, right) return P.element_class(P, coeff) - def _add_(self, other): - """ - Return the sum of this series with ``other``. - - INPUT: - - - ``other`` -- other series - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream - if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): - c = left._constant + right._constant - v = min(left.valuation(), right.valuation()) - d = max(left._degree(), right._degree()) - initial_coefficients = [left[i] + right[i] for i in range(v, d)] - if not any(initial_terms) and not c: - return P.zero() - return P.element_class(P, CoefficientStream_exact(initial_terms, P._sparse, - valuation=v, degree=d, constant=c)) - return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) def _rmul_(self, scalar): """ From 346e2b62e708c96343ec9ff8ab394840eb816913 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 1 Aug 2021 11:52:00 +0200 Subject: [PATCH 047/355] factor out _lmul_ --- src/sage/rings/lazy_laurent_series.py | 194 ++++++++++++-------------- 1 file changed, 87 insertions(+), 107 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 54f758c64bb..d1b41197926 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -180,6 +180,93 @@ def _add_(self, other): return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) + def _lmul_(self, scalar): + """ + Scalar multiplication for module elements with the module + element on the left and the scalar on the right. + + INPUT: + + - ``scalar`` -- an element of the base ring + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: 2*z + 2*z + sage: -1*z + -z + sage: 0*z + 0 + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M * 3 + 3*z + 6*z^2 + 9*z^3 + 12*z^4 + 15*z^5 + 18*z^6 + ... + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M * 3 + 3*z + 6*z^2 + 9*z^3 + 12*z^4 + 15*z^5 + 18*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: N * 4 + 4 + 4*z + 4*z^2 + 4*z^3 + 4*z^4 + 4*z^5 + 4*z^6 + ... + + sage: 1 * M is M + True + sage: M * 1 is M + True + + sage: from sage.data_structures.coefficient_stream import CoefficientStream_scalar + sage: isinstance((M*3)._coeff_stream, CoefficientStream_scalar) + True + sage: isinstance((3*M)._coeff_stream, CoefficientStream_scalar) + True + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L.gen(1) + sage: 2*g + 2/2^z + sage: -1*g + -1/2^z + sage: 0*g + 0 + sage: M = L(lambda n: n); M + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + sage: M * 3 + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: M = L(lambda n: n); M + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + sage: M * 3 + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + + sage: 1 * M is M + True + sage: M * 1 is M + True + """ + P = self.parent() + if not scalar: + return P.zero() + if scalar == 1: + return self + + if isinstance(self._coeff_stream, CoefficientStream_exact): + c = scalar * self._coeff_stream._constant + v = self._coeff_stream.valuation() + initial_coefficients = [scalar * v for v in self._coeff_stream._initial_coefficients] + return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + valuation=v, constant=c, + degree=self._coeff_stream._degree)) + + return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) + + class LazyLaurentSeries(LazySequencesModuleElement): r""" A Laurent series where the coefficients are computed lazily. @@ -697,59 +784,6 @@ def _div_(self, other): return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - def _rmul_(self, scalar): - """ - Return the scalar multiplication of this series by ``scalar``. - - INPUT: - - - ``scalar`` -- an element of the base ring - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: 2*z - 2*z - sage: -1*z - -z - sage: 0*z - 0 - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M * 3 - 3*z + 6*z^2 + 9*z^3 + 12*z^4 + 15*z^5 + 18*z^6 + ... - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M * 3 - 3*z + 6*z^2 + 9*z^3 + 12*z^4 + 15*z^5 + 18*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: N * 4 - 4 + 4*z + 4*z^2 + 4*z^3 + 4*z^4 + 4*z^5 + 4*z^6 + ... - - sage: 1 * M is M - True - sage: M * 1 is M - True - """ - P = self.parent() - if not scalar: - return P.zero() - if scalar == 1: - return self - - if isinstance(self._coeff_stream, CoefficientStream_exact): - R = P._laurent_poly_ring - z = R.gen() - c = scalar * self._coeff_stream._constant - pl = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - p = scalar * pl - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=p.valuation(), constant=c, degree=self._coeff_stream._degree)) - - return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) def _neg_(self): """ @@ -1558,60 +1592,6 @@ def _mul_(self, other): return P.element_class(P, coeff) - def _rmul_(self, scalar): - """ - Return the scalar multiplication of this series by ``scalar``. - - INPUT: - - - ``scalar`` -- an element of the base ring - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: g = L.gen(1) - sage: 2*g - 2/2^z - sage: -1*g - -1/2^z - sage: 0*g - 0 - sage: M = L(lambda n: n); M - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... - sage: M * 3 - 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... - - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: M = L(lambda n: n); M - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... - sage: M * 3 - 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... - - TESTS:: - - sage: 1 * M is M - True - sage: M * 1 is M - True - """ - P = self.parent() - if not scalar: - return P.zero() - if scalar == 1: - return self - - if isinstance(self._coeff_stream, CoefficientStream_exact): - c = scalar * self._coeff_stream._constant - v = self._coeff_stream.valuation() - initial_coefficients = [scalar * v for v in self._coeff_stream._initial_coefficients] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - valuation=v, constant=c, - degree=self._coeff_stream._degree)) - - return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) - - _lmul_ = _rmul_ - def __invert__(self): """ Return the multiplicative inverse of the element. From 2015cfe89372a4718eb554023c1eb22856613791 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 1 Aug 2021 13:00:43 +0200 Subject: [PATCH 048/355] factor out remaining common methods --- src/sage/rings/lazy_laurent_series.py | 1435 ++++++++++--------------- 1 file changed, 586 insertions(+), 849 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index d1b41197926..58419b5d43d 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -99,7 +99,445 @@ CoefficientStream_dirichlet_inv ) -class LazySequencesModuleElement(ModuleElement): +class LazySequenceElement(ModuleElement): + def __getitem__(self, n): + """ + Return the coefficient of the term with exponent ``n`` of the series. + + INPUT: + + - ``n`` -- integer + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = z/(1 - 2*z^3) + sage: [f[n] for n in range(20)] + [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + sage: f[0:20] + [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + + sage: M = L(lambda n: n) + sage: [M[n] for n in range(20)] + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n) + sage: [M[n] for n in range(20)] + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(lambda n: n) + sage: [f[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: f[1:11] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + """ + R = self.base_ring() + if isinstance(n, slice): + if n.stop is None: + raise NotImplementedError("cannot list an infinite set") + start = n.start if n.start is not None else self._coeff_stream.valuation() + step = n.step if n.step is not None else 1 + return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] + return R(self._coeff_stream[n]) + + coefficient = __getitem__ + + def map_coefficients(self, func, ring=None): + """ + Return the series with ``func`` applied to each nonzero coefficient of ``self``. + + INPUT: + + - ``func`` -- function that takes in a coefficient and returns + a new coefficient + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: s = z/(1 - 2*z^2) + sage: t = s.map_coefficients(lambda c: c + 1) + sage: s + z + 2*z^3 + 4*z^5 + 8*z^7 + ... + sage: t + 2*z + 3*z^3 + 5*z^5 + 9*z^7 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M.map_coefficients(lambda c: c + 1); N + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M.map_coefficients(lambda c: c + 1); N + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: s = L(lambda n: n-1); s + 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + ... + sage: s = s.map_coefficients(lambda c: c + 1); s + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + + """ + P = self.parent() + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, CoefficientStream_exact): + initial_values = [func(i) if i else 0 for i in coeff_stream._initial_values] + c = func(coeffs._constant) if coeffs._constant else 0 + if not any(initial_values) and not c: + return P.zero() + coeff_stream = CoefficientStream_exact(p_list, self._coeff_stream._is_sparse, + valuation=coeff_stream._approximate_valuation, + degree=coeff_stream._degree, + constant=c) + return P.element_class(P, coeff_stream) + return P.element_class(P, CoefficientStream_apply_coeff(self._coeff_stream, func, P.base_ring())) + + def truncate(self, d): + """ + Return this series with its terms of degree >= ``d`` truncated. + + INPUT: + + - ``d`` -- integer + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: alpha = 1/(1-z) + sage: alpha + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: beta = alpha.truncate(5) + sage: beta + 1 + z + z^2 + z^3 + z^4 + sage: alpha - beta + z^5 + z^6 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M.truncate(4) + z + 2*z^2 + 3*z^3 + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M.truncate(4) + z + 2*z^2 + 3*z^3 + """ + P = self.parent() + coeff_stream = self._coeff_stream + initial_values = [coeff_stream[i] for i in range(coeff_stream._approximate_valuation, d)] + return P.element_class(P, CoefficientStream_exact(initial_values, P._sparse, + valuation=coeff_stream._approximate_valuation)) + + def prec(self): + """ + Return the precision of the series, which is infinity. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = 1/(1 - z) + sage: f.prec() + +Infinity + """ + return infinity + + def valuation(self): + r""" + Return the valuation of ``self``. + + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: s = 1/(1 - z) - 1/(1 - 2*z) + sage: s.valuation() + 1 + sage: t = z - z + sage: t.valuation() + +Infinity + sage: M = L(lambda n: n^2, 0) + sage: M.valuation() + 1 + sage: (M - M).valuation() + +Infinity + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: mu = L(moebius); mu.valuation() + 1 + sage: (mu - mu).valuation() + +Infinity + sage: g = L(constant=1, valuation=2) + sage: g.valuation() + 2 + sage: (g*g).valuation() + 4 + + """ + return self._coeff_stream.valuation() + + def _richcmp_(self, other, op): + r""" + Compare ``self` with ``other`` with respect to the comparison + operator ``op``. + + Equality is verified if the corresponding coefficients of both series + can be checked for equality without computing coefficients + indefinitely. Otherwise an exception is raised to declare that + equality is not decidable. + + Inequality is not defined for lazy Laurent series. + + INPUT: + + - ``other`` -- another Laurent series + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: z + z^2 == z^2 + z + True + sage: z + z^2 != z^2 + z + False + sage: z + z^2 > z^2 + z + False + sage: z + z^2 < z^2 + z + False + """ + if op is op_EQ: + if isinstance(self._coeff_stream, CoefficientStream_zero): # self == 0 + return isinstance(other._coeff_stream, CoefficientStream_zero) + if isinstance(other._coeff_stream, CoefficientStream_zero): # self != 0 but other == 0 + return False + + if (not isinstance(self._coeff_stream, CoefficientStream_exact) + or not isinstance(other._coeff_stream, CoefficientStream_exact)): + # One of the lazy laurent series is not known to eventually be constant + # Implement the checking of the caches here. + n = min(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) + m = max(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) + for i in range(n, m): + if self[i] != other[i]: + return False + if self._coeff_stream == other._coeff_stream: + return True + raise ValueError("undecidable") + + # Both are CoefficientStream_exact, which implements a full check + return self._coeff_stream == other._coeff_stream + + if op is op_NE: + return not (self == other) + + return False + + def __hash__(self): + """ + Return the hash of ``self`` + + TESTS:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: f = L([1,2,3,4], -5) + sage: g = (1 + f)/(1 - f)^2 + sage: {g: 1} + {z^5 - 2*z^6 + z^7 + 5*z^9 - 11*z^10 + z^11 + ...: 1} + """ + return hash(self._coeff_stream) + + def __bool__(self): + """ + Test whether ``self`` is not zero. + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(GF(2)) + sage: (z-z).is_zero() + True + sage: f = 1/(1 - z) + sage: f.is_zero() + False + sage: M = L(lambda n: n, 0); M + z + z^3 + z^5 + ... + sage: M.is_zero() + False + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return False + if isinstance(self._coeff_stream, CoefficientStream_exact): + return True + for a in self._coeff_stream._cache: + if a: + return True + if self[self._coeff_stream._approximate_valuation]: + return True + raise ValueError("undecidable as lazy Laurent series") + + def define(self, s): + r""" + Define an equation by ``self = s``. + + INPUT:: + + - ``s`` -- a Laurent polynomial + + EXAMPLES: + + We begin by constructing the Catalan numbers:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: C = L(None) + sage: C.define(1 + z*C^2) + sage: C + 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + ... + + The Catalan numbers but with a valuation 1:: + + sage: B = L(None, 1) + sage: B.define(z + B^2) + sage: B + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + ... + + We can define multiple series that are linked:: + + sage: s = L(None) + sage: t = L(None) + sage: s.define(1 + z*t^3) + sage: t.define(1 + z*s^2) + sage: s[:9] + [1, 1, 3, 9, 34, 132, 546, 2327, 10191] + sage: t[:9] + [1, 1, 2, 7, 24, 95, 386, 1641, 7150] + + An bigger example:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: A = L(None, 5) + sage: B = L(None) + sage: C = L(None, 2) + sage: A.define(z^5 + B^2) + sage: B.define(z^5 + C^2) + sage: C.define(z^2 + C^2 + A^2) + sage: A[0:15] + [0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 5, 4, 14, 10, 48] + sage: B[0:15] + [0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138] + sage: C[0:15] + [0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142] + + Counting binary trees:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: s = L(None, valuation=1) + sage: s.define(z + (s^2+s(z^2))/2) + sage: [s[i] for i in range(9)] + [0, 1, 1, 1, 2, 3, 6, 11, 23] + + The `q`-Catalan numbers:: + + sage: R. = ZZ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: s = L(None) + sage: s.define(1+z*s*s(q*z)) + sage: s + 1 + z + (q + 1)*z^2 + (q^3 + q^2 + 2*q + 1)*z^3 + + (q^6 + q^5 + 2*q^4 + 3*q^3 + 3*q^2 + 3*q + 1)*z^4 + + (q^10 + q^9 + 2*q^8 + 3*q^7 + 5*q^6 + 5*q^5 + 7*q^4 + 7*q^3 + 6*q^2 + 4*q + 1)*z^5 + + (q^15 + q^14 + 2*q^13 + 3*q^12 + 5*q^11 + 7*q^10 + 9*q^9 + 11*q^8 + + 14*q^7 + 16*q^6 + 16*q^5 + 17*q^4 + 14*q^3 + 10*q^2 + 5*q + 1)*z^6 + ... + + We count unlabeled ordered trees by total number of nodes + and number of internal nodes:: + + sage: R. = QQ[] + sage: Q. = LazyLaurentSeriesRing(R) + sage: leaf = z + sage: internal_node = q * z + sage: L = Q(constant=1, degree=1) + sage: T = Q(None, 1) + sage: T.define(leaf + internal_node * L(T)) + sage: [T[i] for i in range(6)] + [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L(constant=1, valuation=2) + sage: F = L(None); F.define(1 + g*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] + sage: oeis(_) # optional, internet + 0: A002033: Number of perfect partitions of n. + 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. + ... + + sage: F = L(None); F.define(1 + g*F*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: s = L(None) + sage: s.define(1 + z*s^3) + sage: s[:10] + [1, 1, 3, 12, 55, 273, 1428, 7752, 43263, 246675] + + sage: e = L(None) + sage: e.define(1 + z*e) + sage: e.define(1 + z*e) + Traceback (most recent call last): + ... + ValueError: series already defined + sage: z.define(1 + z^2) + Traceback (most recent call last): + ... + ValueError: series already defined + + """ + if not isinstance(self._coeff_stream, CoefficientStream_uninitialized) or self._coeff_stream._target is not None: + raise ValueError("series already defined") + self._coeff_stream._target = s._coeff_stream + + +class LazySequencesModuleElement(LazySequenceElement): + def __init__(self, parent, coeff_stream): + """ + Initialize the series. + + TESTS:: + + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: z = L.gen() + sage: TestSuite(z).run() + + sage: L = LazyDirichletSeriesRing(QQbar, 'z') + sage: g = L(constant=1) + sage: TestSuite(g).run() + """ + ModuleElement.__init__(self, parent) + self._coeff_stream = coeff_stream + def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -165,7 +603,7 @@ def _add_(self, other): left = self._coeff_stream right = other._coeff_stream if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): + and isinstance(right, CoefficientStream_exact)): approximate_valuation = min(left.valuation(), right.valuation()) degree = max(left._degree, right._degree) initial_coefficients = [left[i] + right[i] for i in range(approximate_valuation, degree)] @@ -179,6 +617,66 @@ def _add_(self, other): return P.element_class(P, coeff_stream) return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) + def _sub_(self, other): + """ + Return the series of this series minus ``other`` series. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z - z + 0 + sage: 3*z - 2*z + z + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M - N; P + -1 + z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + ... + + sage: A = L(1, constant=2, degree=3) + sage: B = L(2, constant=3, degree=5) + sage: A - B + -1 + 2*z^3 + 2*z^4 - z^5 - z^6 - z^7 + ... + + sage: A = L(1, constant=2, degree=3) + sage: B = L([1,0,0,2,2], constant=2) + sage: X = A - B; X + 0 + sage: type(X._coeff_stream) + + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M - N; P + -1 + z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + ... + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) and isinstance(right, CoefficientStream_exact)): + approximate_valuation = min(left.valuation(), right.valuation()) + degree = max(left._degree, right._degree) + initial_coefficients = [left[i] - right[i] for i in range(approximate_valuation, degree)] + constant = left._constant - right._constant + if not any(initial_coefficients) and not constant: + return P.zero() + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, + constant=constant, + degree=degree, + valuation=approximate_valuation) + return P.element_class(P, coeff_stream) + if left == right: + return P.zero() + return P.element_class(P, CoefficientStream_sub(self._coeff_stream, other._coeff_stream)) def _lmul_(self, scalar): """ @@ -266,6 +764,43 @@ def _lmul_(self, scalar): return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) + def _neg_(self): + """ + Return the negative of this series. + + TESTS:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: z = L.gen() + sage: -(1 - z) + -1 + z + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: P = -M; P + -z - 2*z^2 - 3*z^3 - 4*z^4 - 5*z^5 - 6*z^6 + ... + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: P = -M; P + -z - 2*z^2 - 3*z^3 - 4*z^4 - 5*z^5 - 6*z^6 + ... + sage: -(z^2 + 3*z - 4*z^3) + -3*z - z^2 + 4*z^3 + """ + P = self.parent() + coeff_stream = self._coeff_stream + if isinstance(self._coeff_stream, CoefficientStream_exact): + initial_coefficients = [-v for v in coeff_stream._initial_coefficients] + constant = -coeff_stream._constant + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, + constant=constant, + valuation=coeff_stream.valuation()) + return P.element_class(P, coeff_stream) + # -(-f) = f + if isinstance(coeff_stream, CoefficientStream_neg): + return P.element_class(P, coeff_stream._series) + return P.element_class(P, CoefficientStream_neg(coeff_stream)) + class LazyLaurentSeries(LazySequencesModuleElement): r""" @@ -294,58 +829,43 @@ class LazyLaurentSeries(LazySequencesModuleElement): sage: g == f True """ - - def __init__(self, parent, coeff_stream): - """ - Initialize ``self``. - - INPUT: - - - ``parent`` -- the base ring for the series - - ``coeff_stream`` -- the coefficient stream defining the series - - TESTS:: - - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: z = L.gen() - sage: TestSuite(z).run() - """ - ModuleElement.__init__(self, parent) - self._coeff_stream = coeff_stream - - def __getitem__(self, n): + def change_ring(self, ring): """ - Return the coefficient of the term with exponent ``n`` of the series. + Return this series with coefficients converted to elements of ``ring``. INPUT: - - ``n`` -- integer + - ``ring`` -- a ring EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = z/(1 - 2*z^3) - sage: [f[n] for n in range(20)] - [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] - sage: f[0:20] - [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring - sage: M = L(lambda n: n) - sage: [M[n] for n in range(20)] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n) - sage: [M[n] for n in range(20)] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M ^-1 + z^-1 - 2 + z + ... """ - R = self.base_ring() - if isinstance(n, slice): - if n.stop is None: - raise NotImplementedError("cannot list an infinite set") - start = n.start if n.start is not None else self._coeff_stream.valuation() - step = n.step if n.step is not None else 1 - return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] - return R(self._coeff_stream[n]) + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) + return Q.element_class(Q, self._coeff_stream) def __call__(self, g): r""" @@ -665,71 +1185,6 @@ def _mul_(self, other): valuation=v, degree=d, constant=c)) return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) - - - def _sub_(self, other): - """ - Return the series of this series minus ``other`` series. - - INPUT: - - - ``other`` -- other series - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: z - z - 0 - sage: 3*z - 2*z - z - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M - N; P - -1 + z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + ... - - sage: A = L(1, constant=2, degree=3) - sage: B = L(2, constant=3, degree=5) - sage: A - B - -1 + 2*z^3 + 2*z^4 - z^5 - z^6 - z^7 + ... - - sage: A = L(1, constant=2, degree=3) - sage: B = L([1,0,0,2,2], constant=2) - sage: X = A - B; X - 0 - sage: type(X._coeff_stream) - - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M - N; P - -1 + z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + ... - """ - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream - if (isinstance(left, CoefficientStream_exact) and isinstance(right, CoefficientStream_exact)): - R = P._laurent_poly_ring - z = R.gen() - c = left._constant - right._constant - pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)])) - pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)])) - d = max(left._degree, right._degree) - pl += R([left._constant]*(d-left._degree)).shift(left._degree) - pr += R([right._constant]*(d-right._degree)).shift(right._degree) - p = pl - pr - if not p and not c: - return P.zero() - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=p.valuation(), constant=c, degree=d)) - if left == right: - return P.zero() - return P.element_class(P, CoefficientStream_sub(self._coeff_stream, other._coeff_stream)) - def _div_(self, other): """ Return ``self`` divided by ``other``. @@ -784,45 +1239,6 @@ def _div_(self, other): return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - - def _neg_(self): - """ - Return the negative of this series. - - TESTS:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: z = L.gen() - sage: -(1 - z) - -1 + z - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: P = -M; P - -z - 2*z^2 - 3*z^3 - 4*z^4 - 5*z^5 - 6*z^6 + ... - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: P = -M; P - -z - 2*z^2 - 3*z^3 - 4*z^4 - 5*z^5 - 6*z^6 + ... - sage: -(z^2 + 3*z - 4*z^3) - -3*z - z^2 + 4*z^3 - """ - P = self.parent() - if isinstance(self._coeff_stream, CoefficientStream_exact): - R = P._laurent_poly_ring - z = R.gen() - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - p = -poly - c = -self._coeff_stream._constant - d = self._coeff_stream._degree - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=p.valuation(), constant=c, degree=d)) - # -(-f) = f - if isinstance(self._coeff_stream, CoefficientStream_neg): - return P.element_class(P, self._coeff_stream._series) - return P.element_class(P, CoefficientStream_neg(self._coeff_stream)) - def __invert__(self): """ Return the multiplicative inverse of the element. @@ -843,190 +1259,22 @@ def __invert__(self): z^-1 - 2 + z + ... sage: ~(~(1 - z)) - 1 - z - """ - P = self.parent() - R = P._laurent_poly_ring - z = R.gen() - if isinstance(self._coeff_stream, CoefficientStream_exact): - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - if poly == R.gen(): - ret = 1 / poly - p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=self._coeff_stream._constant)) - # (f^-1)^-1 = f - if isinstance(self._coeff_stream, CoefficientStream_cauchy_inverse): - return P.element_class(P, self._coeff_stream._series) - return P.element_class(P, CoefficientStream_cauchy_inverse(self._coeff_stream)) - - def coefficient(self, n): - """ - Return the coefficient of the term with exponent ``n`` of the series. - - INPUT: - - - ``n`` -- integer - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: F = L(None) - sage: F.define(1 + z*F^2) - sage: F.coefficient(10) - 16796 - sage: F - 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + ... - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: e = L(None) - sage: e.define(1 + z*e^2) - sage: e - 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + ... - sage: e._coeff_stream._cache - [1, 1, 2, 5, 14, 42, 132] - sage: e.coefficient(10) - 16796 - sage: e._coeff_stream._cache - [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796] - sage: M = L(lambda n: n^2); M - z + 4*z^2 + 9*z^3 + 16*z^4 + 25*z^5 + 36*z^6 + ... - sage: M._coeff_stream._cache - [0, 1, 4, 9, 16, 25, 36] - sage: M.coefficient(9) - 81 - sage: M._coeff_stream._cache - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - - sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=True) - sage: M = L(lambda n: n^2); M - z + 4*z^2 + 9*z^3 + 16*z^4 + 25*z^5 + 36*z^6 + ... - sage: M._coeff_stream._cache - {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36} - sage: M.coefficient(10) - 100 - sage: M._coeff_stream._cache - {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 10: 100} - """ - return self.__getitem__(n) - - def map_coefficients(self, func, ring=None): - """ - Return the series with ``func`` applied to each coefficient of ``self``. - - INPUT: - - - ``func`` -- function that takes in a coefficient and returns - a new coefficient - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = z/(1 - 2*z) - sage: t = s.map_coefficients(lambda c: c + 1) - sage: s - z + 2*z^2 + 4*z^3 + 8*z^4 + 16*z^5 + 32*z^6 + 64*z^7 + ... - sage: t - 2*z + 3*z^2 + 5*z^3 + 9*z^4 + 17*z^5 + 33*z^6 + 65*z^7 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M.map_coefficients(lambda c: c + 1); N - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M.map_coefficients(lambda c: c + 1); N - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... - """ - P = self.parent() - if isinstance(self._coeff_stream, CoefficientStream_exact): - R = P._laurent_poly_ring - z = R.gen() - p = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - p = p.map_coefficients(func) - c = func(self._coeff_stream._constant) - if not p and not c: - return P.zero() - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, self._coeff_stream._is_sparse, valuation=p.valuation(), constant=c)) - return P.element_class(P, CoefficientStream_apply_coeff(self._coeff_stream, func, P.base_ring())) - - def change_ring(self, ring): - """ - Return this series with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: s = 2 + z - sage: t = s.change_ring(QQ) - sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M ^-1 - z^-1 - 2 + z + ... - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - - def truncate(self, d): - """ - Return this series with its terms of degree >= ``d`` truncated. - - INPUT: - - - ``d`` -- integer - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: alpha = 1/(1-z) - sage: alpha - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: beta = alpha.truncate(5) - sage: beta - 1 + z + z^2 + z^3 + z^4 - sage: alpha - beta - z^5 + z^6 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M.truncate(4) - z + 2*z^2 + 3*z^3 - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M.truncate(4) - z + 2*z^2 + 3*z^3 + 1 - z """ P = self.parent() R = P._laurent_poly_ring z = R.gen() - p = R.sum(self[i] * z**i for i in range(self._coeff_stream._approximate_valuation, d)) - p_list = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=p.valuation(), constant=ZZ.zero(), degree=d)) + if isinstance(self._coeff_stream, CoefficientStream_exact): + poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) + if poly == R.gen(): + ret = 1 / poly + p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=self._coeff_stream._constant)) + # (f^-1)^-1 = f + if isinstance(self._coeff_stream, CoefficientStream_cauchy_inverse): + return P.element_class(P, self._coeff_stream._series) + return P.element_class(P, CoefficientStream_cauchy_inverse(self._coeff_stream)) + def __pow__(self, n): """ @@ -1110,19 +1358,6 @@ def approximate_series(self, prec, name=None): R = PowerSeriesRing(S.base_ring(), name=name) return R([self[i] for i in range(prec)]).add_bigoh(prec) - def prec(self): - """ - Return the precision of the series, which is infinity. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1/(1 - z) - sage: f.prec() - +Infinity - """ - return infinity - def polynomial(self, degree=None, name=None): r""" Return the polynomial or Laurent polynomial if the series is actually so. @@ -1207,32 +1442,6 @@ def polynomial(self, degree=None, name=None): R = PolynomialRing(S.base_ring(), name=name) return R([self[i] for i in range(m)]) - def valuation(self): - r""" - Return the valuation of ``self``. - - This method determines the valuation of the series by looking for a - nonzero coefficient. Hence if the series happens to be zero, then it - may run forever. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = 1/(1 - z) - 1/(1 - 2*z) - sage: s.valuation() - 1 - sage: t = z - z - sage: t.valuation() - +Infinity - sage: M = L(lambda n: n^2, 0) - sage: M.valuation() - 1 - sage: M = L(lambda n: n^2, 0) - sage: M.valuation() - 1 - """ - return self._coeff_stream.valuation() - def _repr_(self): """ Return the string representation of this Laurent series. @@ -1256,233 +1465,18 @@ def _repr_(self): m = v + 7 # long enough elif not self._coeff_stream._constant: # Just a polynonial, so let that print itself - R = self.parent()._laurent_poly_ring - z = R.gen() - return repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, self._coeff_stream._degree))) - else: - m = self._coeff_stream._degree + 3 - - # Use the polynomial printing - R = self.parent()._laurent_poly_ring - ret = repr(R([self._coeff_stream[i] for i in range(v, m)]).shift(v)) - # TODO: Better handling when ret == 0 but we have not checked up to the constant term - return ret + ' + ...' - - def _richcmp_(self, other, op): - r""" - Compare ``self` with ``other`` with respect to the comparison - operator ``op``. - - Equality is verified if the corresponding coefficients of both series - can be checked for equality without computing coefficients - indefinitely. Otherwise an exception is raised to declare that - equality is not decidable. - - Inequality is not defined for lazy Laurent series. - - INPUT: - - - ``other`` -- another Laurent series - - - ``op`` -- comparison operator - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: z + z^2 == z^2 + z - True - sage: z + z^2 != z^2 + z - False - sage: z + z^2 > z^2 + z - False - sage: z + z^2 < z^2 + z - False - """ - if op is op_EQ: - if isinstance(self._coeff_stream, CoefficientStream_zero): # self == 0 - return isinstance(other._coeff_stream, CoefficientStream_zero) - if isinstance(other._coeff_stream, CoefficientStream_zero): # self != 0 but other == 0 - return False - - if (not isinstance(self._coeff_stream, CoefficientStream_exact) - or not isinstance(other._coeff_stream, CoefficientStream_exact)): - # One of the lazy laurent series is not known to eventually be constant - # Implement the checking of the caches here. - n = min(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) - m = max(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) - for i in range(n, m): - if self[i] != other[i]: - return False - if self._coeff_stream == other._coeff_stream: - return True - raise ValueError("undecidable as lazy Laurent series") - - # Both are CoefficientStream_exact, which implements a full check - return self._coeff_stream == other._coeff_stream - - if op is op_NE: - return not (self == other) - - return False - - def __hash__(self): - """ - Return the hash of ``self`` - - TESTS:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: f = L([1,2,3,4], -5) - sage: g = (1 + f)/(1 - f)^2 - sage: {g: 1} - {z^5 - 2*z^6 + z^7 + 5*z^9 - 11*z^10 + z^11 + ...: 1} - """ - return hash(self._coeff_stream) - - def __bool__(self): - """ - Test whether ``self`` is not zero. - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(GF(2)) - sage: (z-z).is_zero() - True - sage: f = 1/(1 - z) - sage: f.is_zero() - False - sage: M = L(lambda n: n, 0); M - z + z^3 + z^5 + ... - sage: M.is_zero() - False - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return False - if isinstance(self._coeff_stream, CoefficientStream_exact): - # This should always end up being True, but let's be careful about it for now... - P = self.paren() - R = P._laurent_poly_ring - z = R.gen() - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - return poly or self._coeff_stream._constant - - for a in self._coeff_stream._cache: - if a: - return True - if self[self._coeff_stream._approximate_valuation]: - return True - raise ValueError("undecidable as lazy Laurent series") - - def define(self, s): - r""" - Define an equation by ``self = s``. - - INPUT:: - - - ``s`` -- a Laurent polynomial - - EXAMPLES: - - We begin by constructing the Catalan numbers:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: C = L(None) - sage: C.define(1 + z*C^2) - sage: C - 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + ... - - The Catalan numbers but with a valuation 1:: - - sage: B = L(None, 1) - sage: B.define(z + B^2) - sage: B - z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + ... - - We can define multiple series that are linked:: - - sage: s = L(None) - sage: t = L(None) - sage: s.define(1 + z*t^3) - sage: t.define(1 + z*s^2) - sage: s[:9] - [1, 1, 3, 9, 34, 132, 546, 2327, 10191] - sage: t[:9] - [1, 1, 2, 7, 24, 95, 386, 1641, 7150] - - An bigger example:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: A = L(None, 5) - sage: B = L(None) - sage: C = L(None, 2) - sage: A.define(z^5 + B^2) - sage: B.define(z^5 + C^2) - sage: C.define(z^2 + C^2 + A^2) - sage: A[0:15] - [0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 5, 4, 14, 10, 48] - sage: B[0:15] - [0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138] - sage: C[0:15] - [0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142] - - Counting binary trees:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: s = L(None, valuation=1) - sage: s.define(z + (s^2+s(z^2))/2) - sage: [s[i] for i in range(9)] - [0, 1, 1, 1, 2, 3, 6, 11, 23] - - The `q`-Catalan numbers:: - - sage: R. = ZZ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: s = L(None) - sage: s.define(1+z*s*s(q*z)) - sage: s - 1 + z + (q + 1)*z^2 + (q^3 + q^2 + 2*q + 1)*z^3 - + (q^6 + q^5 + 2*q^4 + 3*q^3 + 3*q^2 + 3*q + 1)*z^4 - + (q^10 + q^9 + 2*q^8 + 3*q^7 + 5*q^6 + 5*q^5 + 7*q^4 + 7*q^3 + 6*q^2 + 4*q + 1)*z^5 - + (q^15 + q^14 + 2*q^13 + 3*q^12 + 5*q^11 + 7*q^10 + 9*q^9 + 11*q^8 - + 14*q^7 + 16*q^6 + 16*q^5 + 17*q^4 + 14*q^3 + 10*q^2 + 5*q + 1)*z^6 + ... - - We count unlabeled ordered trees by total number of nodes - and number of internal nodes:: - - sage: R. = QQ[] - sage: Q. = LazyLaurentSeriesRing(R) - sage: leaf = z - sage: internal_node = q * z - sage: L = Q(constant=1, degree=1) - sage: T = Q(None, 1) - sage: T.define(leaf + internal_node * L(T)) - sage: [T[i] for i in range(6)] - [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: s = L(None) - sage: s.define(1 + z*s^3) - sage: s[:10] - [1, 1, 3, 12, 55, 273, 1428, 7752, 43263, 246675] + R = self.parent()._laurent_poly_ring + z = R.gen() + return repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, self._coeff_stream._degree))) + else: + m = self._coeff_stream._degree + 3 - sage: e = L(None) - sage: e.define(1 + z*e) - sage: e.define(1 + z*e) - Traceback (most recent call last): - ... - ValueError: series already defined - sage: z.define(1 + z^2) - Traceback (most recent call last): - ... - ValueError: series already defined - """ - if not isinstance(self._coeff_stream, CoefficientStream_uninitialized) or self._coeff_stream._target is not None: - raise ValueError("series already defined") - self._coeff_stream._target = s._coeff_stream + # Use the polynomial printing + R = self.parent()._laurent_poly_ring + ret = repr(R([self._coeff_stream[i] for i in range(v, m)]).shift(v)) + # TODO: Better handling when ret == 0 but we have not checked up to the constant term + return ret + ' + ...' -###################################################################### class LazyDirichletSeries(LazySequencesModuleElement): r""" @@ -1510,54 +1504,6 @@ class LazyDirichletSeries(LazySequencesModuleElement): sage: g == f True """ - - def __init__(self, parent, coeff_stream): - """ - Initialize the series. - - TESTS:: - - sage: L = LazyDirichletSeriesRing(QQbar, 'z') - sage: g = L(constant=1) - sage: TestSuite(g).run() - """ - ModuleElement.__init__(self, parent) - self._coeff_stream = coeff_stream - - def __getitem__(self, n): - """ - Return the coefficient of the term with exponent ``n`` of the series. - - INPUT: - - - ``n`` -- integer - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: f = L(lambda n: n) - sage: [f[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: f[1:11] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - sage: M = L(lambda n: n) - sage: [M[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: M = L(lambda n: n) - sage: [M[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - """ - R = self.base_ring() - if isinstance(n, slice): - if n.stop is None: - raise NotImplementedError("cannot list an infinite set") - start = n.start if n.start is not None else self._coeff_stream.valuation() - step = n.step if n.step is not None else 1 - return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] - return R(self._coeff_stream[n]) - def _mul_(self, other): """ Return the product of this series with ``other``. @@ -1609,45 +1555,6 @@ def __invert__(self): P = self.parent() return P.element_class(P, CoefficientStream_dirichlet_inv(self._coeff_stream)) - - def coefficient(self, n): - """ - Return the coefficient of the term with exponent ``n`` of the series. - - INPUT: - - - ``n`` -- integer - - EXAMPLES:: - - TESTS:: - - """ - return self.__getitem__(n) - - def map_coefficients(self, func, ring=None): - """ - Return the series with ``func`` applied to each coefficient of this series. - - INPUT: - - - ``func`` -- Python function that takes in a coefficient and returns - a new coefficient - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ - P = self.parent() - R = P.base_ring() - if isinstance(self._coeff_stream, CoefficientStream_exact): - p = p.map_coefficients(func) - c = func(c) - if not p and not c: - return P.zero() - return P.element_class(P, CoefficientStream_exact(p, self._coeff_stream._is_sparse, c, d)) - return P.element_class(P, CoefficientStream_apply_coeff(self._coeff_stream, func, R)) - def change_ring(self, ring): """ Return this series with coefficients converted to elements of ``ring``. @@ -1664,24 +1571,6 @@ def change_ring(self, ring): Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) - def truncate(self, d): - """ - Return this series with its terms of degree >= ``d`` truncated. - - INPUT: - - - ``d`` -- integer - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) - """ - P = self.parent() - R = P._laurent_poly_ring - z = R.gen() - p = R.sum(self[i] * z**i for i in range(self._coeff_stream._approximate_valuation, d)) - return P.element_class(P, CoefficientStream_exact(p, P._sparse, ZZ.zero(), d)) - def __pow__(self, n): """ Return the ``n``-th power of the series. @@ -1699,42 +1588,6 @@ def __pow__(self, n): return generic_power(self, n) - def prec(self): - """ - Return the precision of the series, which is infinity. - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: f = L(1) - sage: f.prec() - +Infinity - """ - return infinity - - def valuation(self): - """ - Return the valuation of the series. - - This method determines the valuation of the series by looking for a - nonzero coefficient. Hence if the series happens to be zero, then it - may run forever. - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: mu = L(moebius); mu.valuation() - 1 - sage: (mu - mu).valuation() # known bug - +Infinity - sage: g = L(constant=1, valuation=2) - sage: g.valuation() - 2 - sage: (g*g).valuation() - 4 - """ - return self._coeff_stream.valuation() - def _repr_(self): """ Return the string representation of this Dirichlet series. @@ -1770,119 +1623,3 @@ def _repr_(self): if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: return ret return ret + ' + ...' - - def _richcmp_(self, other, op): - """ - Compare ``self` with ``other`` with respect to the comparison operator ``op``. - - Equality is verified if the corresponding coefficients of both series - can be checked for equality without computing coefficients - indefinitely. Otherwise an exception is raised to declare that - equality is not decidable. - - Inequality is not defined for lazy Dirichlet series. - - INPUT: - - - ``other`` -- another Dirichlet series - - - ``op`` -- comparison operator - - TESTS:: - - sage: L = LazyDirichletSeriesRing(QQ, "z") - """ - if op is op_EQ: - if isinstance(self._coeff_stream, CoefficientStream_zero): # self == 0 - return isinstance(other._coeff_stream, CoefficientStream_zero) - if isinstance(other._coeff_stream, CoefficientStream_zero): # self != 0 but other == 0 - return False - - if (not isinstance(self._coeff_stream, CoefficientStream_exact) - or not isinstance(other._coeff_stream, CoefficientStream_exact)): - # One of the lazy laurent series is not known to eventually be constant - # Implement the checking of the caches here. - n = min(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) - m = max(self._coeff_stream._approximate_valuation, other._coeff_stream._approximate_valuation) - for i in range(n, m): - if self[i] != other[i]: - return False - if self._coeff_stream == other._coeff_stream: - return True - raise ValueError("undecidable as lazy Dirichlet series") - - # Both are CoefficientStream_exact, which implements a full check - return self._coeff_stream == other._coeff_stream - - if op is op_NE: - return not (self == other) - - return False - - def __hash__(self): - """ - Return the hash of ``self`` - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, 'z') - """ - return hash(self._coeff_stream) - - def __bool__(self): - """ - Test whether ``self`` is not zero. - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return False - - for a in self._coeff_stream._cache: - if a: - return True - if self[self._coeff_stream._approximate_valuation]: - return True - raise ValueError("undecidable as lazy Dirichlet series") - - def define(self, s): - r""" - Define an equation by ``self = s``. - - INPUT:: - - - ``s`` -- a Dirichlet series - - EXAMPLES: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: g = L(constant=1, valuation=2) - sage: F = L(None); F.define(1 + g*F) - sage: [F[i] for i in range(1, 16)] - [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] - sage: oeis(_) # optional, internet - 0: A002033: Number of perfect partitions of n. - 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. - ... - - sage: F = L(None); F.define(1 + g*F*F) - sage: [F[i] for i in range(1, 16)] - [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] - - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: g = L(constant=1, valuation=2) - sage: e = L(None) - sage: e.define(1 + g*e) - sage: e.define(1 + g*e) - Traceback (most recent call last): - ... - ValueError: series already defined - """ - if not isinstance(self._coeff_stream, CoefficientStream_uninitialized) or self._coeff_stream._target is not None: - raise ValueError("series already defined") - self._coeff_stream._target = s._coeff_stream From ca73f8490dd598108a5cbe231f8d69d0d070f55d Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 2 Aug 2021 09:18:26 +0200 Subject: [PATCH 049/355] initial version, wip --- src/sage/rings/all.py | 2 +- src/sage/rings/lazy_laurent_series.py | 728 +++++++++++++++++++-- src/sage/rings/lazy_laurent_series_ring.py | 342 +++++++++- 3 files changed, 1028 insertions(+), 44 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 02a6eb56f91..34aea7ce7b6 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,7 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) +lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing', 'LazyTaylorSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 58419b5d43d..9d5b853e445 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -93,13 +93,29 @@ CoefficientStream_inexact, CoefficientStream_zero, CoefficientStream_exact, - CoefficientStream_coefficient_function, CoefficientStream_uninitialized, CoefficientStream_dirichlet_convolution, CoefficientStream_dirichlet_inv ) class LazySequenceElement(ModuleElement): + def __init__(self, parent, coeff_stream): + """ + Initialize the series. + + TESTS:: + + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: z = L.gen() + sage: TestSuite(z).run() + + sage: L = LazyDirichletSeriesRing(QQbar, 'z') + sage: g = L(constant=1) + sage: TestSuite(g).run() + """ + ModuleElement.__init__(self, parent) + self._coeff_stream = coeff_stream + def __getitem__(self, n): """ Return the coefficient of the term with exponent ``n`` of the series. @@ -143,7 +159,7 @@ def __getitem__(self, n): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] """ - R = self.base_ring() + R = self.parent()._coeff_ring if isinstance(n, slice): if n.stop is None: raise NotImplementedError("cannot list an infinite set") @@ -204,7 +220,8 @@ def map_coefficients(self, func, ring=None): degree=coeff_stream._degree, constant=c) return P.element_class(P, coeff_stream) - return P.element_class(P, CoefficientStream_apply_coeff(self._coeff_stream, func, P.base_ring())) + coeff_stream = CoefficientStream_apply_coeff(self._coeff_stream, func, P._coeff_ring) + return P.element_class(P, coeff_stream) def truncate(self, d): """ @@ -237,10 +254,11 @@ def truncate(self, d): z + 2*z^2 + 3*z^3 """ P = self.parent() - coeff_stream = self._coeff_stream - initial_values = [coeff_stream[i] for i in range(coeff_stream._approximate_valuation, d)] - return P.element_class(P, CoefficientStream_exact(initial_values, P._sparse, - valuation=coeff_stream._approximate_valuation)) + initial_values = [self._coeff_stream[i] + for i in range(coeff_stream._approximate_valuation, d)] + coeff_stream = CoefficientStream_exact(initial_values, P._sparse, + valuation=coeff_stream._approximate_valuation) + return P.element_class(P, coeff_stream) def prec(self): """ @@ -521,23 +539,6 @@ def define(self, s): class LazySequencesModuleElement(LazySequenceElement): - def __init__(self, parent, coeff_stream): - """ - Initialize the series. - - TESTS:: - - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: z = L.gen() - sage: TestSuite(z).run() - - sage: L = LazyDirichletSeriesRing(QQbar, 'z') - sage: g = L(constant=1) - sage: TestSuite(g).run() - """ - ModuleElement.__init__(self, parent) - self._coeff_stream = coeff_stream - def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -1170,21 +1171,6 @@ def _mul_(self, other): return self return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream)) - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream - if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): - c = left._constant + right._constant - v = min(left.valuation(), right.valuation()) - d = max(left._degree(), right._degree()) - initial_coefficients = [left[i] + right[i] for i in range(v, d)] - if not any(initial_terms) and not c: - return P.zero() - return P.element_class(P, CoefficientStream_exact(initial_terms, P._sparse, - valuation=v, degree=d, constant=c)) - return P.element_class(P, CoefficientStream_add(self._coeff_stream, other._coeff_stream)) - def _div_(self, other): """ Return ``self`` divided by ``other``. @@ -1477,6 +1463,670 @@ def _repr_(self): # TODO: Better handling when ret == 0 but we have not checked up to the constant term return ret + ' + ...' +class LazyTaylorSeries(LazySequencesModuleElement): + r""" + A Taylor series where the coefficients are computed lazily. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(lambda i: i, valuation=-3, constant=(-1,3)) + -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + ... + sage: L(lambda i: i, valuation=-3, constant=-1, degree=3) + -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + ... + + :: + + sage: f = 1 / (1 - z - z^2); f + 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + ... + sage: f.coefficient(100) + 573147844013817084101 + + Lazy Taylor series is picklable:: + + sage: g = loads(dumps(f)) + sage: g + 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + ... + sage: g == f + True + """ + def change_ring(self, ring): + """ + Return this series with coefficients converted to elements of ``ring``. + + INPUT: + + - ``ring`` -- a ring + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=False) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Taylor Series Ring in z over Rational Field + sage: M.parent() + Lazy Taylor Series Ring in z over Integer Ring + + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M.parent() + Lazy Taylor Series Ring in z over Integer Ring + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Taylor Series Ring in z over Rational Field + sage: M ^-1 + z^-1 - 2 + z + ... + """ + from .lazy_laurent_series_ring import LazyTaylorSeriesRing + Q = LazyTaylorSeriesRing(ring, names=self.parent().variable_names()) + return Q.element_class(Q, self._coeff_stream) + + def __call__(self, g): + r""" + Return the composition of ``self`` with ``g``. + + Given two Taylor Series `f` and `g` over the same base ring, the + composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + + - `g = 0` and `val(f) >= 0`, + - `g` is non-zero and `f` has only finitely many non-zero coefficients, + - `g` is non-zero and `val(g) > 0`. + + INPUT: + + - ``g`` -- other series + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: f = z^2 + 1 + z + sage: f(0) + 1 + sage: f(L(0)) + 1 + sage: f(f) + 3 + 3*z + 4*z^2 + 2*z^3 + z^4 + sage: g = z^-3/(1-2*z); g + z^-3 + 2*z^-2 + 4*z^-1 + 8 + 16*z + 32*z^2 + 64*z^3 + ... + sage: f(g) + z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + ... + sage: g^2 + 1 + g + z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + ... + + sage: f = z^-2 + z + 4*z^3 + sage: f(f) + 4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + ... + sage: f^-2 + f + 4*f^3 + 4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + ... + sage: f(g) + 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + ... + sage: g^-2 + g + 4*g^3 + 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + ... + + sage: f = z^-3 + z^-2 + 1 / (1 + z^2); f + z^-3 + z^-2 + 1 - z^2 + ... + sage: g = z^3 / (1 + z - z^3); g + z^3 - z^4 + z^5 - z^7 + 2*z^8 - 2*z^9 + ... + sage: f(g) + z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + ... + sage: g^-3 + g^-2 + 1 / (1 + g^2) + z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + ... + + sage: f = L(lambda n: n); f + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: f(z^2) + z^2 + 2*z^4 + 3*z^6 + ... + + sage: f = L(lambda n: n, -2); f + -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + ... + sage: f3 = f(z^3); f3 + -2*z^-6 - z^-3 + ... + sage: [f3[i] for i in range(-6,13)] + [-2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4] + + We compose a Taylor polynomial with a generic element:: + + sage: R. = QQ[] + sage: f = z^2 + 1 + z^-1 + sage: g = x^2 + x + 3 + sage: f(g) + (x^6 + 3*x^5 + 12*x^4 + 19*x^3 + 37*x^2 + 28*x + 31)/(x^2 + x + 3) + sage: f(g) == g^2 + 1 + g^-1 + True + + We compose with another lazy Taylor series:: + + sage: LS. = LazyTaylorSeriesRing(QQ) + sage: f = z^2 + 1 + z^-1 + sage: fy = f(y); fy + y^-1 + 1 + y^2 + sage: fy.parent() is LS + True + sage: g = y - y + sage: f(g) + Traceback (most recent call last): + ... + ZeroDivisionError: the valuation of the series must be nonnegative + + sage: g = 1 - y + sage: f(g) + 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + ... + sage: g^2 + 1 + g^-1 + 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + ... + + sage: f = L(lambda n: n, 0); f + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: f(0) + 0 + sage: f(y) + y + 2*y^2 + 3*y^3 + 4*y^4 + 5*y^5 + 6*y^6 + ... + sage: fp = f(y - y) + sage: fp == 0 + True + sage: fp.parent() is LS + True + + sage: f = z^2 + 3 + z + sage: f(y - y) + 3 + + With both of them sparse:: + + sage: L. = LazyTaylorSeriesRing(QQ, sparse=True) + sage: LS. = LazyTaylorSeriesRing(QQ, sparse=True) + sage: f = L(lambda n: 1); f + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: f(y^2) + 1 + y^2 + y^4 + y^6 + ... + + sage: fp = f - 1 + z^-2; fp + z^-2 + z + z^2 + z^3 + z^4 + ... + sage: fpy = fp(y^2); fpy + y^-4 + y^2 + ... + sage: [fpy[i] for i in range(-4,11)] + [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] + + sage: g = LS(valuation=2, constant=1); g + y^2 + y^3 + y^4 + ... + sage: fg = f(g); fg + 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + ... + sage: 1 + g + g^2 + g^3 + g^4 + g^5 + g^6 + 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + ... + + sage: h = LS(lambda n: 1 if n % 2 else 0, 2); h + y^3 + y^5 + y^7 + ... + sage: fgh = fg(h); fgh + 1 + y^6 + ... + sage: [fgh[i] for i in range(0, 15)] + [1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13] + sage: t = 1 + h^2 + h^3 + 2*h^4 + 3*h^5 + 5*h^6 + sage: [t[i] for i in range(0, 15)] + [1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13] + + We look at mixing the sparse and the dense:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: f = L(lambda n: 1); f + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: g = LS(lambda n: 1, 1); g + y + y^2 + y^3 + y^4 + y^5 + y^6 + y^7 + ... + sage: f(g) + 1 + y + 2*y^2 + 4*y^3 + 8*y^4 + 16*y^5 + 32*y^6 + ... + + sage: f = z^-2 + 1 + z + sage: g = 1/(y*(1-y)); g + y^-1 + 1 + y + y^2 + y^3 + y^4 + y^5 + ... + sage: f(g) + y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + ... + sage: g^-2 + 1 + g + y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + ... + + sage: f = z^-3 + z^-2 + 1 + sage: g = 1/(y^2*(1-y)); g + y^-2 + y^-1 + 1 + y + y^2 + y^3 + y^4 + ... + sage: f(g) + 1 + y^4 - 2*y^5 + 2*y^6 + ... + sage: g^-3 + g^-2 + 1 + 1 + y^4 - 2*y^5 + 2*y^6 + ... + sage: z(y) + y + """ + # f = self and compute f(g) + P = g.parent() + + # g = 0 case + if ((not isinstance(g, LazyTaylorSeries) and not g) + or (isinstance(g, LazyTaylorSeries) + and isinstance(g._coeff_stream, CoefficientStream_zero))): + if self._coeff_stream._approximate_valuation >= 0: + return P(self[0]) + # Perhaps we just don't yet know if the valuation is non-negative + if any(self._coeff_stream[i] for i in range(self._coeff_stream._approximate_valuation, 0)): + raise ZeroDivisionError("the valuation of the series must be nonnegative") + self._coeff_stream._approximate_valuation = 0 + return P(self[0]) + + # f has finite length + if isinstance(self._coeff_stream, CoefficientStream_zero): # constant 0 + return self + if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: + # constant polynomial + R = self.parent()._poly_ring + z = R.gen() + poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) + if poly.is_constant(): + return self + if not isinstance(g, LazyTaylorSeries): + return poly(g) + # g also has finite length, compose the polynomials + if isinstance(g._coeff_stream, CoefficientStream_exact) and not g._coeff_stream._constant: + try: + R = P._poly_ring + g_poly = R(sum([g._coeff_stream[i] * z**i for i in range(g._coeff_stream._approximate_valuation, g._coeff_stream._degree)])) + ret = poly(g_poly) + if ret.parent() is R: + p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, CoefficientStream_exact(p_list, self._coeff_stream._is_sparse, valuation=ret.valuation())) + except TypeError: # the result is not a Taylor polynomial + pass + + # Return the sum since g is not known to be finite or we do not get a Taylor polynomial + # TODO: Optimize when f has positive valuation + ret = P.zero() + gp = P.one() + # We build this iteratively so each power can benefit from the caching + # Equivalent to P.sum(poly[i] * g**i for i in range(poly.valuation(), poly.degree()+1)) + # We could just do "return poly(g)" if we don't care about speed + deg = poly.degree() + for i in range(deg): + ret += poly[i] * gp + gp *= g + ret += poly[deg] * gp + gi = ~g + gp = P.one() + for i in range(-1, poly.valuation()-1, -1): + gp *= gi + ret += poly[i] * gp + return ret + + # g != 0 and val(g) > 0 + if not isinstance(g, LazyTaylorSeries): + try: + g = self.parent()(g) + except (TypeError, ValueError): + raise NotImplementedError("can only compose with a lazy Taylor series") + # Perhaps we just don't yet know if the valuation is positive + if g._coeff_stream._approximate_valuation <= 0: + if any(g._coeff_stream[i] for i in range(self._coeff_stream._approximate_valuation)): + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_valuation = 1 + + return P.element_class(P, CoefficientStream_composition(self._coeff_stream, g._coeff_stream)) + + def _mul_(self, other): + """ + Return the product of this series with ``other``. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: (1 - z)*(1 - z) + 1 - 2*z + z^2 + sage: (1 - z)*(1 - z)*(1 - z) + 1 - 3*z + 3*z^2 - z^3 + sage: M = L(lambda n: n) + sage: M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M * (1 - M) + sage: N + z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ... + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: M * N + z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + ... + + sage: L.one() * M is M + True + sage: M * L.one() is M + True + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if isinstance(left, CoefficientStream_zero) or isinstance(right, CoefficientStream_zero): + return P.zero() + + R = P._poly_ring + z = R.gen() + if isinstance(left, CoefficientStream_exact): + if not left._constant: + if left._initial_coefficients == (P._coeff_ring.one(),) and not left.valuation(): + return other # self == 1 + if isinstance(right, CoefficientStream_exact): + if not right._constant: + # left and right polynomials + il = left._initial_coefficients + ir = right._initial_coefficients + initial_coefficients = [sum(il[k]*ir[n-k] + for k in range(max(n-len(ir)+1, 0), + min(len(il)-1, n) + 1)) + for n in range(len(il) + len(ir))] + v = left.valuation() + right.valuation() + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v) + return P.element_class(P, coeff_stream) + elif isinstance(right, CoefficientStream_exact): + if not right._constant: + if right._initial_coefficients == (P._coeff_ring.one(),) and not right.valuation(): + return self # other == 1 + return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream)) + + def _div_(self, other): + """ + Return ``self`` divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: z/(1 - z) + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + """ + if isinstance(other._coeff_stream, CoefficientStream_zero): + raise ZeroDivisionError("cannot divide by 0") + + P = self.parent() + left = self._coeff_stream + if isinstance(left, CoefficientStream_zero): + return P.zero() + right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) + and isinstance(right, CoefficientStream_exact)): + if not left._constant and not right._constant: + R = P._poly_ring + z = R.gen() + pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)])) + pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)])) + ret = pl / pr + try: + ret = P._poly_ring(ret) + p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=left._constant)) + except (TypeError, ValueError): + # We cannot divide the polynomials, so the result must be a series + pass + + return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) + + def __invert__(self): + """ + Return the multiplicative inverse of the element. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=False) + sage: ~(1 - z) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: P = ~M; P + z^-1 - 2 + z + ... + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: P = ~M; P + z^-1 - 2 + z + ... + + sage: ~(~(1 - z)) + 1 - z + """ + P = self.parent() + R = P._poly_ring + z = R.gen() + if isinstance(self._coeff_stream, CoefficientStream_exact): + poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) + if poly == R.gen(): + ret = 1 / poly + p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=self._coeff_stream._constant)) + # (f^-1)^-1 = f + if isinstance(self._coeff_stream, CoefficientStream_cauchy_inverse): + return P.element_class(P, self._coeff_stream._series) + return P.element_class(P, CoefficientStream_cauchy_inverse(self._coeff_stream)) + + + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: (1 - z)^-1 + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: (1 - z)^0 + 1 + sage: (1 - z)^3 + 1 - 3*z + 3*z^2 - z^3 + sage: (1 - z)^-3 + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + ... + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M ^ 2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ... + + sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: M ^ 2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ... + """ + if n == 0: + return self.parent().one() + + return generic_power(self, n) + + def approximate_series(self, prec, name=None): + """ + Return the Taylor series with absolute precision ``prec`` approximated + from this series. + + INPUT: + + - ``prec`` -- an integer + + - ``name`` -- name of the variable; if it is ``None``, the name of + the variable of the series is used + + OUTPUT: a Taylor series with absolute precision ``prec`` + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: z = L.gen() + sage: f = (z - 2*z^3)^5/(1 - 2*z) + sage: f + z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + 32*z^10 - 16*z^11 + ... + sage: g = f.approximate_series(10) + sage: g + z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + O(z^10) + sage: g.parent() + Power Series Ring in z over Integer Ring + sage: h = (f^-1).approximate_series(3) + sage: h + z^-5 - 2*z^-4 + 10*z^-3 - 20*z^-2 + 60*z^-1 - 120 + 280*z - 560*z^2 + O(z^3) + sage: h.parent() + Taylor Series Ring in z over Integer Ring + """ + S = self.parent() + + if name is None: + name = S.variable_name() + + if self.valuation() < 0: + from sage.rings.all import TaylorSeriesRing + R = TaylorSeriesRing(S.base_ring(), name=name) + n = self.valuation() + return R([self[i] for i in range(n, prec)], n).add_bigoh(prec) + else: + from sage.rings.all import PowerSeriesRing + R = PowerSeriesRing(S.base_ring(), name=name) + return R([self[i] for i in range(prec)]).add_bigoh(prec) + + def polynomial(self, degree=None, name=None): + r""" + Return the polynomial or Taylor polynomial if the series is actually so. + + INPUT: + + - ``degree`` -- ``None`` or an integer + + - ``name`` -- name of the variable; if it is ``None``, the name of the variable + of the series is used + + OUTPUT: + + A Taylor polynomial if the valuation of the series is negative or + a polynomial otherwise. + + If ``degree`` is not ``None``, the terms of the series of degree + greater than ``degree`` are truncated first. If ``degree`` is ``None`` + and the series is not a polynomial or a Taylor polynomial, a + ``ValueError`` is raised. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = L([1,0,0,2,0,0,0,3], 5); f + z^5 + 2*z^8 + 3*z^12 + sage: f.polynomial() + 3*z^12 + 2*z^8 + z^5 + + TESTS:: + + sage: g = L([1,0,0,2,0,0,0,3], -5); g + z^-5 + 2*z^-2 + 3*z^2 + sage: g.polynomial() + z^-5 + 2*z^-2 + 3*z^2 + sage: z = L.gen() + sage: f = (1 + z)/(z^3 - z^5) + sage: f + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + ... + sage: f.polynomial(5) + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + z^4 + z^5 + sage: f.polynomial(0) + z^-3 + z^-2 + z^-1 + 1 + sage: f.polynomial(-5) + 0 + sage: M = L(lambda n: n^2, 0) + sage: M.polynomial(3) + 9*z^3 + 4*z^2 + z + sage: M = L(lambda n: n^2, 0) + sage: M.polynomial(5) + 25*z^5 + 16*z^4 + 9*z^3 + 4*z^2 + z + + sage: f = 1/(1 + z) + sage: f.polynomial() + Traceback (most recent call last): + ... + ValueError: not a polynomial + """ + if degree is None: + if isinstance(self._coeff_stream, CoefficientStream_zero): + from sage.rings.all import PolynomialRing + return PolynomialRing(S.base_ring(), name=name).zero() + elif isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: + m = self._coeff_stream._degree + else: + raise ValueError("not a polynomial") + else: + m = degree + 1 + + S = self.parent() + + if name is None: + name = S.variable_name() + + from sage.rings.all import PolynomialRing + R = PolynomialRing(S.base_ring(), name=name) + return R([self[i] for i in range(m)]) + + def _repr_(self): + """ + Return the string representation of this Taylor series. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: -1/(1 + 2*z) + -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + ... + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return '0' + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return 'Uninitialized Lazy Taylor Series' + + atomic_repr = self.base_ring()._repr_option('element_is_atomic') + X = self.parent().variable_name() + v = self._coeff_stream._approximate_valuation + + if not isinstance(self._coeff_stream, CoefficientStream_exact): + m = v + 7 # long enough + elif not self._coeff_stream._constant: + # Just a polynonial, so let that print itself + R = self.parent()._poly_ring + if len(self.parent().variable_names()) == 1: + z = R.gen() + return repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, self._coeff_stream._degree))) + else: + return repr(R.sum(self._coeff_stream[i] for i in range(v, self._coeff_stream._degree))) + else: + m = self._coeff_stream._degree + 3 + + # Use the polynomial printing + R = self.parent()._poly_ring + if len(self.parent().variable_names()) == 1: + z = R.gen() + ret = repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, m))) + else: + ret = repr(R.sum(self._coeff_stream[i] for i in range(v, m))) + # TODO: Better handling when ret == 0 but we have not checked up to the constant term + return ret + ' + ...' + class LazyDirichletSeries(LazySequencesModuleElement): r""" diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index e52747fe01a..bb7a03d127f 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -80,8 +80,9 @@ from .integer_ring import ZZ from .infinity import infinity from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_generic +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from .lazy_laurent_series import LazyLaurentSeries, LazyDirichletSeries +from .lazy_laurent_series import LazyLaurentSeries, LazyDirichletSeries, LazyTaylorSeries from sage.data_structures.coefficient_stream import ( CoefficientStream_zero, @@ -119,6 +120,7 @@ def __init__(self, base_ring, names, sparse=False, category=None): sage: TestSuite(L).run(skip='_test_elements') """ self._sparse = sparse + self._coeff_ring = base_ring self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names, sparse=sparse) Parent.__init__(self, base=base_ring, names=names, category=MagmasAndAdditiveMagmas().or_subcategory(category)) @@ -164,8 +166,8 @@ def gen(self, n=0): """ if n != 0: raise IndexError("there is only one generator") - R = self._laurent_poly_ring - coeff_stream = CoefficientStream_exact([R.gen(n)[1]], self._sparse, constant=ZZ.zero(), valuation=1, degree=2) + R = self.base_ring() + coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), valuation=1) return self.element_class(self, coeff_stream) def ngens(self): @@ -296,7 +298,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if valuation is None: valuation = 0 return self.element_class(self, CoefficientStream_uninitialized(self._sparse, valuation)) - + R = self._laurent_poly_ring BR = self.base_ring() try: @@ -390,6 +392,337 @@ def zero(self): """ return self.element_class(self, CoefficientStream_zero(self._sparse)) +###################################################################### + +class LazyTaylorSeriesRing(UniqueRepresentation, Parent): + """ + Lazy Taylor series ring. + + INPUT: + + - ``base_ring`` -- base ring of this Taylor series ring + - ``names`` -- name(s) of the generator of this Taylor series ring + - ``sparse`` -- (default: ``False``) whether this series is sparse or not + + EXAMPLES:: + + sage: LazyTaylorSeriesRing(ZZ, 't') + Lazy Taylor Series Ring in t over Integer Ring + + sage: L. = LazyTaylorSeriesRing(QQ); L + Multivariate Lazy Taylor Series Ring in x, y over Rational Field + """ + Element = LazyTaylorSeries + + def __init__(self, base_ring, names, sparse=False, category=None): + """ + Initialize ``self``. + + TESTS:: + + sage: L = LazyTaylorSeriesRing(ZZ, 't') + sage: TestSuite(L).run(skip='_test_elements') + """ + self._sparse = sparse + self._poly_ring = PolynomialRing(base_ring, names) + if len(names) == 1: + self._coeff_ring = base_ring + else: + self._coeff_ring = PolynomialRing(base_ring, names) + Parent.__init__(self, base=base_ring, names=names, + category=MagmasAndAdditiveMagmas().or_subcategory(category)) + + def _repr_(self): + """ + String representation of this Taylor series ring. + + EXAMPLES:: + + sage: LazyTaylorSeriesRing(GF(2), 'z') + Lazy Taylor Series Ring in z over Finite Field of size 2 + """ + if len(self.variable_names()) == 1: + return "Lazy Taylor Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) + generators_rep = ", ".join(self.variable_names()) + return "Multivariate Lazy Taylor Series Ring in {} over {}".format(generators_rep, self.base_ring()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: latex(L) + \Bold{F}_{2} [\![z]\!] + """ + from sage.misc.latex import latex + generators_rep = ", ".join(self.variable_names()) + return latex(self.base_ring()) + r"[\![{}]\!]".format(generators_rep) + + @cached_method + def gen(self, n=0): + """ + Return the ``n``-th generator of ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.gen() + z + sage: L.gen(3) + Traceback (most recent call last): + ... + IndexError: there is only one generator + """ + m = len(self.variable_names()) + if n > m: + if m == 1: + raise IndexError("there is only one generator") + raise IndexError("there are only %s generators" % m) + + R = self._poly_ring + if len(self.variable_names()) == 1: + coeff_stream = CoefficientStream_exact([1], self._sparse, constant=ZZ.zero(), valuation=1) + else: + coeff_stream = CoefficientStream_exact([R.gen(n)], self._sparse, constant=ZZ.zero(), valuation=1) + return self.element_class(self, coeff_stream) + + def ngens(self): + r""" + Return the number of generators of ``self``. + + This is always 1. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L.ngens() + 1 + """ + return len(self.variable_names()) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L.gens() + (z,) + sage: (1+z)^2 + 1 + 2*z + z^2 + sage: 1/(1 - z) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + """ + return tuple([self.gen(n) for n in range(self.ngens())]) + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True + + R = self._poly_ring + if R.has_coerce_map_from(S): + def make_series_from(poly): + p_dict = poly.homogeneous_components() + v = min(p_dict.keys()) + d = max(p_dict.keys()) + p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + coeff_stream = CoefficientStream_exact(p_list, self._sparse, valuation=v) + return self.element_class(self, coeff_stream) + return SetMorphism(Hom(S, self, Sets()), make_series_from) + + return False + + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None): + """ + Construct a Taylor series from ``x``. + + INPUT: + + - ``x`` -- data used to the define a Taylor series + - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series + - ``constant`` -- (optional) the eventual constant of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + 1 + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + + sage: L(lambda i: i, 5, 1, 10) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + ... + sage: L(lambda i: i, 5, (1, 10)) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + ... + + sage: X = L(constant=5, degree=2); X + 5*z^2 + 5*z^3 + 5*z^4 + ... + sage: X.valuation() + 2 + + sage: def g(i): + ....: if i < 0: + ....: return 1 + ....: else: + ....: return 1 + sum(k for k in range(i+1)) + sage: e = L(g, -5); e + z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + ... + sage: f = e^-1; f + z^5 - z^6 - z^11 + ... + sage: f.coefficient(10) + 0 + sage: f[20] + 9 + sage: f[30] + -219 + + sage: L(valuation=2, constant=1) + z^2 + z^3 + z^4 + ... + sage: L(constant=1) + Traceback (most recent call last): + ... + ValueError: you must specify the degree for the polynomial 0 + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: + + sage: f = L([1,2,3,4], -5) + sage: f + z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 + sage: g = L([1,3,5,7,9], 5, -1) + sage: g + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + ... + + .. TODO:: + + Add a method to change the sparse/dense implementation. + """ + if valuation is None: + valuation = 0 + assert valuation >= 0, "the valuation of a Taylor series must be positive" + + R = self._poly_ring + if x is None: + coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) + return self.element_class(self, coeff_stream) + + try: + # Try to build stuff using the polynomial ring constructor + x = R(x) + except (TypeError, ValueError): + pass + if isinstance(constant, (tuple, list)): + constant, degree = constant + if constant is not None: + constant = R(constant) + if x in R: + if not x and not constant: + coeff_stream = CoefficientStream_zero(self._sparse) + else: + if x and valuation: + valuation = valuation - v + if degree is None and not x: + degree = valuation + if x == R.zero(): + coeff_stream = CoefficientStream_exact([x], self._sparse, valuation=degree-1, constant=constant) + return self.element_class(self, coeff_stream) + if len(self.variable_names()) == 1: + v = x.valuation() + d = x.degree() + p_list = [x[i] for i in range(v, d + 1)] + else: + p_dict = x.homogeneous_components() + v = min(p_dict.keys()) + d = max(p_dict.keys()) + p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + coeff_stream = CoefficientStream_exact(p_list, self._sparse, + valuation=valuation, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + if isinstance(x, LazyTaylorSeries): + if x._coeff_stream._is_sparse is self._sparse: + return self.element_class(self, x._coeff_stream) + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + if callable(x): + if degree is not None: + if constant is None: + constant = ZZ.zero() + z = R.gen() + p = [x(i) for i in range(valuation, degree)] + coeff_stream = CoefficientStream_exact(p, self._sparse, + valuation=valuation, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) + return self.element_class(self, coeff_stream) + raise ValueError(f"unable to convert {x} into a lazy Taylor series") + + def _an_element_(self): + """ + Return a Taylor series in ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.an_element() + z^-10 + z^-9 + z^-8 + ... + """ + c = self.base_ring()(1) + R = self._poly_ring + coeff_stream = CoefficientStream_exact([R.one()], self._sparse, valuation=1, constant=c) + return self.element_class(self, coeff_stream) + + @cached_method + def one(self): + r""" + Return the constant series `1`. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.one() + 1 + """ + R = self._poly_ring + coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) + return self.element_class(self, coeff_stream) + + @cached_method + def zero(self): + r""" + Return the zero series. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, CoefficientStream_zero(self._sparse)) ###################################################################### @@ -423,6 +756,7 @@ def __init__(self, base_ring, names, sparse=False, category=None): raise ValueError("positive characteristic not allowed for Dirichlet series") self._sparse = sparse + self._coeff_ring = base_ring Parent.__init__(self, base=base_ring, names=names, category=MagmasAndAdditiveMagmas().or_subcategory(category)) From 5b62ddb9789db751f1ee3cb33a97208654f437ac Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 2 Aug 2021 17:01:08 +0200 Subject: [PATCH 050/355] fix doctests --- src/sage/rings/lazy_laurent_series.py | 20 ++++----- src/sage/rings/lazy_laurent_series_ring.py | 49 ++++++++++------------ 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 9d5b853e445..fa5c7e8eb15 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2106,25 +2106,23 @@ def _repr_(self): if not isinstance(self._coeff_stream, CoefficientStream_exact): m = v + 7 # long enough - elif not self._coeff_stream._constant: - # Just a polynonial, so let that print itself - R = self.parent()._poly_ring - if len(self.parent().variable_names()) == 1: - z = R.gen() - return repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, self._coeff_stream._degree))) - else: - return repr(R.sum(self._coeff_stream[i] for i in range(v, self._coeff_stream._degree))) else: m = self._coeff_stream._degree + 3 - # Use the polynomial printing R = self.parent()._poly_ring if len(self.parent().variable_names()) == 1: z = R.gen() - ret = repr(R.sum(self._coeff_stream[i] * z**i for i in range(v, m))) + ret = " + ".join([repr(R(self._coeff_stream[i] * z**i)) for i in range(v, m) + if self._coeff_stream[i]]) else: - ret = repr(R.sum(self._coeff_stream[i] for i in range(v, m))) + ret = " + ".join([repr(R(self._coeff_stream[i])) for i in range(v, m) + if self._coeff_stream[i]]) + + if not ret: + return "0" # TODO: Better handling when ret == 0 but we have not checked up to the constant term + if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: + return ret return ret + ' + ...' diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index bb7a03d127f..e7c9ff7d423 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -578,28 +578,19 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: X.valuation() 2 - sage: def g(i): - ....: if i < 0: - ....: return 1 - ....: else: - ....: return 1 + sum(k for k in range(i+1)) - sage: e = L(g, -5); e - z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + ... + sage: e = L(lambda n: n+1); e + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... sage: f = e^-1; f - z^5 - z^6 - z^11 + ... + 1 + -2*z + z^2 + ... sage: f.coefficient(10) 0 sage: f[20] - 9 - sage: f[30] - -219 + 0 sage: L(valuation=2, constant=1) z^2 + z^3 + z^4 + ... sage: L(constant=1) - Traceback (most recent call last): - ... - ValueError: you must specify the degree for the polynomial 0 + 1 + z + z^2 + ... Alternatively, ``x`` can be a list of elements of the base ring. Then these elements are read as coefficients of the terms of @@ -607,12 +598,11 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No may be just an element of the base ring instead of a tuple or can be simply omitted if it is zero:: - sage: f = L([1,2,3,4], -5) - sage: f - z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 - sage: g = L([1,3,5,7,9], 5, -1) - sage: g - z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + ... + sage: f = L([1,2,3,4], 1); f + z + 2*z^2 + 3*z^3 + 4*z^4 + + sage: g = L([1,3,5,7,9], 5, -1); g + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 + -z^10 + -z^11 + -z^12 + ... .. TODO:: @@ -621,9 +611,10 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if valuation is None: valuation = 0 assert valuation >= 0, "the valuation of a Taylor series must be positive" - + R = self._poly_ring if x is None: + assert degree is None coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) return self.element_class(self, coeff_stream) @@ -640,13 +631,13 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if not x and not constant: coeff_stream = CoefficientStream_zero(self._sparse) else: - if x and valuation: - valuation = valuation - v - if degree is None and not x: - degree = valuation - if x == R.zero(): - coeff_stream = CoefficientStream_exact([x], self._sparse, valuation=degree-1, constant=constant) + if not x: + coeff_stream = CoefficientStream_exact([], self._sparse, + valuation=valuation, + degree=degree, + constant=constant) return self.element_class(self, coeff_stream) + if len(self.variable_names()) == 1: v = x.valuation() d = x.degree() @@ -656,11 +647,13 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No v = min(p_dict.keys()) d = max(p_dict.keys()) p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + coeff_stream = CoefficientStream_exact(p_list, self._sparse, valuation=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) + if isinstance(x, LazyTaylorSeries): if x._coeff_stream._is_sparse is self._sparse: return self.element_class(self, x._coeff_stream) @@ -689,7 +682,7 @@ def _an_element_(self): sage: L = LazyTaylorSeriesRing(ZZ, 'z') sage: L.an_element() - z^-10 + z^-9 + z^-8 + ... + z + z^2 + z^3 + z^4 + ... """ c = self.base_ring()(1) R = self._poly_ring From c4852baeea29a2bbdb4b17ae3cbbc9557f6e9ce3 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 4 Aug 2021 13:08:09 +0200 Subject: [PATCH 051/355] factor mul, div, pow, invert into Cauchy class --- src/sage/rings/lazy_laurent_series.py | 957 ++++++-------------------- 1 file changed, 217 insertions(+), 740 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 4bf4ec09206..f6a64cb9bc1 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -87,7 +87,7 @@ from .infinity import infinity -from sage.structure.element import ModuleElement, parent +from sage.structure.element import ModuleElement, RingElement, parent from .integer_ring import ZZ from sage.structure.richcmp import op_EQ, op_NE from sage.arith.power import generic_power @@ -1001,7 +1001,187 @@ def _neg_(self): return P.element_class(P, CoefficientStream_neg(coeff_stream)) -class LazyLaurentSeries(LazySequencesModuleElement): +class LazyCauchyProductSeries(RingElement): + """ + A class for series where multiplication is the Cauchy product. + + We are assuming that :meth:`polynomial` + """ + def __init__(self, parent): + RingElement.__init__(self, parent) + + def _mul_(self, other): + """ + Return the product of this series with ``other``. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: (1 - z)*(1 - z) + 1 - 2*z + z^2 + sage: (1 - z)*(1 - z)*(1 - z) + 1 - 3*z + 3*z^2 - z^3 + sage: M = L(lambda n: n) + sage: M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = M * (1 - M) + sage: N + z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ... + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... + sage: M * N + z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + ... + + sage: L.one() * M is M + True + sage: M * L.one() is M + True + + Similarly for Taylor series:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: (1 - x)*(1 - y) + 1 + -x - y + x*y + sage: (1 - x)*(1 - y)*(1 - z) + 1 + -x - y - z + x*y + x*z + y*z + -x*y*z + + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if isinstance(left, CoefficientStream_zero) or isinstance(right, CoefficientStream_zero): + return P.zero() + + # the product is exact if and only if both of the factors are + # exact, and one has eventually 0 coefficients: + # (p + a x^d/(1-x))(q + b x^e/(1-x)) + # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 + # for the moment we only consider the case where bothe have eventually 0 coefficients + if (isinstance(left, CoefficientStream_exact) and not left._constant + and isinstance(right, CoefficientStream_exact) and not right._constant): + il = left._initial_coefficients + ir = right._initial_coefficients + initial_coefficients = [sum(il[k]*ir[n-k] + for k in range(max(n-len(ir)+1, 0), + min(len(il)-1, n) + 1)) + for n in range(len(il) + len(ir))] + v = left.valuation() + right.valuation() + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v) + return P.element_class(P, coeff_stream) + if isinstance(left, CoefficientStream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.valuation() == 0: + return other # self == 1 + if isinstance(right, CoefficientStream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.valuation() == 0: + return self + return P.element_class(P, CoefficientStream_cauchy_product(left, right)) + + def __invert__(self): + """ + Return the multiplicative inverse of the element. + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be inverted:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: ~(1 - z) + 1 + z + z^2 + O(z^3) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: P = ~M; P + z^-1 - 2 + z + O(z^6) + + Lazy Laurent series that have a sparse implementation can be inverted:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: P = ~M; P + z^-1 - 2 + z + O(z^6) + + sage: ~(~(1 - z)) + 1 - z + + Lazy Laurent series that are known to be exact can be inverted:: + + sage: ~z + z^-1 + + """ + P = self.parent() + coeff_stream = self._coeff_stream + # the inverse is exact if and only if coeff_stream corresponds to one of + # cx^d/(1-x) ... (c, ...) + # cx^d ... (c, 0, ...) + # cx^d (1-x) ... (c, -c, 0, ...) + if isinstance(coeff_stream, CoefficientStream_exact): + initial_coefficients = coeff_stream._initial_coefficients + if not initial_coefficients: + i = 1 / coeff_stream._constant + v = -coeff_stream.valuation() + c = P._coeff_ring.zero() + coeff_stream = CoefficientStream_exact((i, -i), P._sparse, + valuation=v, constant=c) + return P.element_class(P, coeff_stream) + if len(initial_coefficients) == 1: + i = 1 / initial_coefficients[0] + v = -coeff_stream.valuation() + c = P._coeff_ring.zero() + coeff_stream = CoefficientStream_exact((i,), P._sparse, + valuation=v, constant=c) + return P.element_class(P, coeff_stream) + if len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]): + v = -coeff_stream.valuation() + c = 1 / initial_coefficients[0] + coeff_stream = CoefficientStream_exact((), P._sparse, + valuation=v, constant=c) + return P.element_class(P, coeff_stream) + + # (f^-1)^-1 = f + if isinstance(coeff_stream, CoefficientStream_cauchy_inverse): + return P.element_class(P, coeff_stream._series) + return P.element_class(P, CoefficientStream_cauchy_inverse(coeff_stream)) + + def _div_(self, other): + r""" + Return ``self`` divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + """ + P = self.parent() + left = self._coeff_stream + if isinstance(left, CoefficientStream_zero): + return P.zero() + right = other._coeff_stream + return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) + + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer, the power to which to raise the series + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + """ + if n == 0: + return self.parent().one() + + return generic_power(self, n) + + +class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" A Laurent series where the coefficients are computed lazily. @@ -1162,7 +1342,7 @@ def __call__(self, g): sage: f(g) 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + O(y^7) sage: g^2 + 1 + g^-1 - 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + O(y^7) + 3 - y + 2*y^2 + y^3 + y^4 + y^5 + O(y^6) sage: f = L(lambda n: n, 0); f z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) @@ -1254,7 +1434,7 @@ def __call__(self, g): Traceback (most recent call last): ... ZeroDivisionError: the valuation of the series must be nonnegative - + `g \neq 0` and `val(g) \leq 0` and `f` has infinitely many non-zero coefficients`:: @@ -1266,7 +1446,7 @@ def __call__(self, g): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series - + We cannot compose if `g` has a negative valuation:: sage: f = L(lambda n: n, 1) @@ -1350,88 +1530,6 @@ def __call__(self, g): return P.element_class(P, CoefficientStream_composition(self._coeff_stream, g._coeff_stream)) - def _mul_(self, other): - """ - Return the product of this series with ``other``. - - INPUT: - - - ``other`` -- other series - - EXAMPLES: - - Lazy Laurent series that are known to be exact can be multiplied:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: (1 - z)*(1 - z) - 1 - 2*z + z^2 - sage: (1 - z)*(1 - z)*(1 - z) - 1 - 3*z + 3*z^2 - z^3 - - Lazy Laurent series that have a dense implementation can be multiplied:: - - sage: M = L(lambda n: n) - sage: M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = M * (1 - M) - sage: N - z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + O(z^7) - - sage: z * M - z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + 6*z^7 + O(z^8) - sage: M * z^-2 - z^-1 + 2 + 3*z + 4*z^2 + 5*z^3 + 6*z^4 + O(z^5) - - sage: L.one() * M is M - True - sage: M * L.one() is M - True - - We check the sparse implementation:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: M * N - z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + O(z^7) - sage: z * M - z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + 6*z^7 + O(z^8) - sage: M * z^-2 - z^-1 + 2 + 3*z + 4*z^2 + 5*z^3 + 6*z^4 + O(z^5) - - sage: L.one() * M is M - True - sage: M * L.one() is M - True - """ - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream - if isinstance(left, CoefficientStream_zero) or isinstance(right, CoefficientStream_zero): - return P.zero() - - R = P._laurent_poly_ring - z = R.gen() - if isinstance(left, CoefficientStream_exact): - if not left._constant: - if left._approximate_valuation == 0 and left._initial_coefficients == (1,): # self == 1 - return other - pl = left.polynomial_part(z) - if isinstance(right, CoefficientStream_exact): - if not right._constant: - pr = right.polynomial_part(z) - p = pl * pr - c = left._constant - initial_coefficients = [p[i] for i in range(p.valuation(), p.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, valuation=p.valuation(), constant=c)) - elif isinstance(right, CoefficientStream_exact): - if not right._constant: - if right._approximate_valuation == 0 and right._initial_coefficients == (1,): # other == 1 - return self - return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream)) - def _div_(self, other): r""" Return ``self`` divided by ``other``. @@ -1505,53 +1603,6 @@ def _div_(self, other): return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - def __invert__(self): - """ - Return the multiplicative inverse of the element. - - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be inverted:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: ~(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: P = ~M; P - z^-1 - 2 + z + O(z^6) - - Lazy Laurent series that have a sparse implementation can be inverted:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: P = ~M; P - z^-1 - 2 + z + O(z^6) - - sage: ~(~(1 - z)) - 1 - z - - Lazy Laurent series that are known to be exact can be inverted:: - - sage: ~z - z^-1 - - """ - P = self.parent() - R = P._laurent_poly_ring - z = R.gen() - if isinstance(self._coeff_stream, CoefficientStream_exact): - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - if poly == R.gen(): - ret = 1 / poly - initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, valuation=ret.valuation(), constant=self._coeff_stream._constant)) - # (f^-1)^-1 = f - if isinstance(self._coeff_stream, CoefficientStream_cauchy_inverse): - return P.element_class(P, self._coeff_stream._series) - return P.element_class(P, CoefficientStream_cauchy_inverse(self._coeff_stream)) - def __pow__(self, n): """ Return the ``n``-th power of the series. @@ -1567,7 +1618,7 @@ def __pow__(self, n): sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: (1 - z)^-1 - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) sage: (1 - z)^0 1 sage: (1 - z)^3 @@ -1930,17 +1981,17 @@ def _unicode_art_(self): # TODO: Better handling when ret == 0 but we have not checked up to the constant term return ret + ' + ...' -class LazyTaylorSeries(LazySequencesModuleElement): +class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" A Taylor series where the coefficients are computed lazily. EXAMPLES:: sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L(lambda i: i, valuation=-3, constant=(-1,3)) - -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + ... - sage: L(lambda i: i, valuation=-3, constant=-1, degree=3) - -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + ... + sage: L(lambda i: i, valuation=3, constant=(-1, 6)) + 3*z^3 + 4*z^4 + 5*z^5 + -z^6 + -z^7 + -z^8 + ... + sage: L(lambda i: i, valuation=3, constant=-1, degree=6) + 3*z^3 + 4*z^4 + 5*z^5 + -z^6 + -z^7 + -z^8 + ... :: @@ -1967,624 +2018,51 @@ def change_ring(self, ring): EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=False) + sage: L. = LazyTaylorSeriesRing(ZZ) sage: s = 2 + z sage: t = s.change_ring(QQ) sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M.change_ring(QQ) - sage: N.parent() + 1/2 + -1/4*z + 1/8*z^2 + -1/16*z^3 + 1/32*z^4 + -1/64*z^5 + 1/128*z^6 + ... + sage: t.parent() Lazy Taylor Series Ring in z over Rational Field - sage: M.parent() - Lazy Taylor Series Ring in z over Integer Ring - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M.parent() - Lazy Taylor Series Ring in z over Integer Ring - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Taylor Series Ring in z over Rational Field - sage: M ^-1 - z^-1 - 2 + z + ... """ from .lazy_laurent_series_ring import LazyTaylorSeriesRing Q = LazyTaylorSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) - def __call__(self, g): - r""" - Return the composition of ``self`` with ``g``. + def _repr_(self): + """ + Return the string representation of this Taylor series. - Given two Taylor Series `f` and `g` over the same base ring, the - composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + TESTS:: - - `g = 0` and `val(f) >= 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: -1/(1 + 2*z) + -1 + 2*z + -4*z^2 + 8*z^3 + -16*z^4 + 32*z^5 + -64*z^6 + ... + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return '0' + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return 'Uninitialized Lazy Taylor Series' - INPUT: + atomic_repr = self.base_ring()._repr_option('element_is_atomic') + X = self.parent().variable_name() + v = self._coeff_stream._approximate_valuation - - ``g`` -- other series - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(QQ) - sage: f = z^2 + 1 + z - sage: f(0) - 1 - sage: f(L(0)) - 1 - sage: f(f) - 3 + 3*z + 4*z^2 + 2*z^3 + z^4 - sage: g = z^-3/(1-2*z); g - z^-3 + 2*z^-2 + 4*z^-1 + 8 + 16*z + 32*z^2 + 64*z^3 + ... - sage: f(g) - z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + ... - sage: g^2 + 1 + g - z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + ... - - sage: f = z^-2 + z + 4*z^3 - sage: f(f) - 4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + ... - sage: f^-2 + f + 4*f^3 - 4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + ... - sage: f(g) - 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + ... - sage: g^-2 + g + 4*g^3 - 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + ... - - sage: f = z^-3 + z^-2 + 1 / (1 + z^2); f - z^-3 + z^-2 + 1 - z^2 + ... - sage: g = z^3 / (1 + z - z^3); g - z^3 - z^4 + z^5 - z^7 + 2*z^8 - 2*z^9 + ... - sage: f(g) - z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + ... - sage: g^-3 + g^-2 + 1 / (1 + g^2) - z^-9 + 3*z^-8 + 3*z^-7 - z^-6 - 4*z^-5 - 2*z^-4 + z^-3 + ... - - sage: f = L(lambda n: n); f - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: f(z^2) - z^2 + 2*z^4 + 3*z^6 + ... - - sage: f = L(lambda n: n, -2); f - -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + ... - sage: f3 = f(z^3); f3 - -2*z^-6 - z^-3 + ... - sage: [f3[i] for i in range(-6,13)] - [-2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4] - - We compose a Taylor polynomial with a generic element:: - - sage: R. = QQ[] - sage: f = z^2 + 1 + z^-1 - sage: g = x^2 + x + 3 - sage: f(g) - (x^6 + 3*x^5 + 12*x^4 + 19*x^3 + 37*x^2 + 28*x + 31)/(x^2 + x + 3) - sage: f(g) == g^2 + 1 + g^-1 - True - - We compose with another lazy Taylor series:: - - sage: LS. = LazyTaylorSeriesRing(QQ) - sage: f = z^2 + 1 + z^-1 - sage: fy = f(y); fy - y^-1 + 1 + y^2 - sage: fy.parent() is LS - True - sage: g = y - y - sage: f(g) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - - sage: g = 1 - y - sage: f(g) - 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + ... - sage: g^2 + 1 + g^-1 - 3 - y + 2*y^2 + y^3 + y^4 + y^5 + y^6 + ... - - sage: f = L(lambda n: n, 0); f - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: f(0) - 0 - sage: f(y) - y + 2*y^2 + 3*y^3 + 4*y^4 + 5*y^5 + 6*y^6 + ... - sage: fp = f(y - y) - sage: fp == 0 - True - sage: fp.parent() is LS - True - - sage: f = z^2 + 3 + z - sage: f(y - y) - 3 - - With both of them sparse:: - - sage: L. = LazyTaylorSeriesRing(QQ, sparse=True) - sage: LS. = LazyTaylorSeriesRing(QQ, sparse=True) - sage: f = L(lambda n: 1); f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: f(y^2) - 1 + y^2 + y^4 + y^6 + ... - - sage: fp = f - 1 + z^-2; fp - z^-2 + z + z^2 + z^3 + z^4 + ... - sage: fpy = fp(y^2); fpy - y^-4 + y^2 + ... - sage: [fpy[i] for i in range(-4,11)] - [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] - - sage: g = LS(valuation=2, constant=1); g - y^2 + y^3 + y^4 + ... - sage: fg = f(g); fg - 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + ... - sage: 1 + g + g^2 + g^3 + g^4 + g^5 + g^6 - 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + ... - - sage: h = LS(lambda n: 1 if n % 2 else 0, 2); h - y^3 + y^5 + y^7 + ... - sage: fgh = fg(h); fgh - 1 + y^6 + ... - sage: [fgh[i] for i in range(0, 15)] - [1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13] - sage: t = 1 + h^2 + h^3 + 2*h^4 + 3*h^5 + 5*h^6 - sage: [t[i] for i in range(0, 15)] - [1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13] - - We look at mixing the sparse and the dense:: - - sage: L. = LazyTaylorSeriesRing(QQ) - sage: f = L(lambda n: 1); f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: g = LS(lambda n: 1, 1); g - y + y^2 + y^3 + y^4 + y^5 + y^6 + y^7 + ... - sage: f(g) - 1 + y + 2*y^2 + 4*y^3 + 8*y^4 + 16*y^5 + 32*y^6 + ... - - sage: f = z^-2 + 1 + z - sage: g = 1/(y*(1-y)); g - y^-1 + 1 + y + y^2 + y^3 + y^4 + y^5 + ... - sage: f(g) - y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + ... - sage: g^-2 + 1 + g - y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + ... - - sage: f = z^-3 + z^-2 + 1 - sage: g = 1/(y^2*(1-y)); g - y^-2 + y^-1 + 1 + y + y^2 + y^3 + y^4 + ... - sage: f(g) - 1 + y^4 - 2*y^5 + 2*y^6 + ... - sage: g^-3 + g^-2 + 1 - 1 + y^4 - 2*y^5 + 2*y^6 + ... - sage: z(y) - y - """ - # f = self and compute f(g) - P = g.parent() - - # g = 0 case - if ((not isinstance(g, LazyTaylorSeries) and not g) - or (isinstance(g, LazyTaylorSeries) - and isinstance(g._coeff_stream, CoefficientStream_zero))): - if self._coeff_stream._approximate_valuation >= 0: - return P(self[0]) - # Perhaps we just don't yet know if the valuation is non-negative - if any(self._coeff_stream[i] for i in range(self._coeff_stream._approximate_valuation, 0)): - raise ZeroDivisionError("the valuation of the series must be nonnegative") - self._coeff_stream._approximate_valuation = 0 - return P(self[0]) - - # f has finite length - if isinstance(self._coeff_stream, CoefficientStream_zero): # constant 0 - return self - if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: - # constant polynomial - R = self.parent()._poly_ring - z = R.gen() - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - if poly.is_constant(): - return self - if not isinstance(g, LazyTaylorSeries): - return poly(g) - # g also has finite length, compose the polynomials - if isinstance(g._coeff_stream, CoefficientStream_exact) and not g._coeff_stream._constant: - try: - R = P._poly_ring - g_poly = R(sum([g._coeff_stream[i] * z**i for i in range(g._coeff_stream._approximate_valuation, g._coeff_stream._degree)])) - ret = poly(g_poly) - if ret.parent() is R: - p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, self._coeff_stream._is_sparse, valuation=ret.valuation())) - except TypeError: # the result is not a Taylor polynomial - pass - - # Return the sum since g is not known to be finite or we do not get a Taylor polynomial - # TODO: Optimize when f has positive valuation - ret = P.zero() - gp = P.one() - # We build this iteratively so each power can benefit from the caching - # Equivalent to P.sum(poly[i] * g**i for i in range(poly.valuation(), poly.degree()+1)) - # We could just do "return poly(g)" if we don't care about speed - deg = poly.degree() - for i in range(deg): - ret += poly[i] * gp - gp *= g - ret += poly[deg] * gp - gi = ~g - gp = P.one() - for i in range(-1, poly.valuation()-1, -1): - gp *= gi - ret += poly[i] * gp - return ret - - # g != 0 and val(g) > 0 - if not isinstance(g, LazyTaylorSeries): - try: - g = self.parent()(g) - except (TypeError, ValueError): - raise NotImplementedError("can only compose with a lazy Taylor series") - # Perhaps we just don't yet know if the valuation is positive - if g._coeff_stream._approximate_valuation <= 0: - if any(g._coeff_stream[i] for i in range(self._coeff_stream._approximate_valuation)): - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_valuation = 1 - - return P.element_class(P, CoefficientStream_composition(self._coeff_stream, g._coeff_stream)) - - def _mul_(self, other): - """ - Return the product of this series with ``other``. - - INPUT: - - - ``other`` -- other series - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: (1 - z)*(1 - z) - 1 - 2*z + z^2 - sage: (1 - z)*(1 - z)*(1 - z) - 1 - 3*z + 3*z^2 - z^3 - sage: M = L(lambda n: n) - sage: M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M * (1 - M) - sage: N - z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ... - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: M * N - z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + ... - - sage: L.one() * M is M - True - sage: M * L.one() is M - True - """ - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream - if isinstance(left, CoefficientStream_zero) or isinstance(right, CoefficientStream_zero): - return P.zero() - - R = P._poly_ring - z = R.gen() - if isinstance(left, CoefficientStream_exact): - if not left._constant: - if left._initial_coefficients == (P._coeff_ring.one(),) and not left.valuation(): - return other # self == 1 - if isinstance(right, CoefficientStream_exact): - if not right._constant: - # left and right polynomials - il = left._initial_coefficients - ir = right._initial_coefficients - initial_coefficients = [sum(il[k]*ir[n-k] - for k in range(max(n-len(ir)+1, 0), - min(len(il)-1, n) + 1)) - for n in range(len(il) + len(ir))] - v = left.valuation() + right.valuation() - coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v) - return P.element_class(P, coeff_stream) - elif isinstance(right, CoefficientStream_exact): - if not right._constant: - if right._initial_coefficients == (P._coeff_ring.one(),) and not right.valuation(): - return self # other == 1 - return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream)) - - def _div_(self, other): - """ - Return ``self`` divided by ``other``. - - INPUT: - - - ``other`` -- nonzero series - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: z/(1 - z) - z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - """ - if isinstance(other._coeff_stream, CoefficientStream_zero): - raise ZeroDivisionError("cannot divide by 0") - - P = self.parent() - left = self._coeff_stream - if isinstance(left, CoefficientStream_zero): - return P.zero() - right = other._coeff_stream - if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): - if not left._constant and not right._constant: - R = P._poly_ring - z = R.gen() - pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)])) - pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)])) - ret = pl / pr - try: - ret = P._poly_ring(ret) - p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=left._constant)) - except (TypeError, ValueError): - # We cannot divide the polynomials, so the result must be a series - pass - - return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - - def __invert__(self): - """ - Return the multiplicative inverse of the element. - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=False) - sage: ~(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: P = ~M; P - z^-1 - 2 + z + ... - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: P = ~M; P - z^-1 - 2 + z + ... - - sage: ~(~(1 - z)) - 1 - z - """ - P = self.parent() - R = P._poly_ring - z = R.gen() - if isinstance(self._coeff_stream, CoefficientStream_exact): - poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)])) - if poly == R.gen(): - ret = 1 / poly - p_list = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(p_list, P._sparse, valuation=ret.valuation(), constant=self._coeff_stream._constant)) - # (f^-1)^-1 = f - if isinstance(self._coeff_stream, CoefficientStream_cauchy_inverse): - return P.element_class(P, self._coeff_stream._series) - return P.element_class(P, CoefficientStream_cauchy_inverse(self._coeff_stream)) - - - def __pow__(self, n): - """ - Return the ``n``-th power of the series. - - INPUT: - - - ``n`` -- integer; the power to which to raise the series - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: (1 - z)^-1 - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - sage: (1 - z)^0 - 1 - sage: (1 - z)^3 - 1 - 3*z + 3*z^2 - z^3 - sage: (1 - z)^-3 - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + ... - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M ^ 2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ... - - sage: L. = LazyTaylorSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: M ^ 2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ... - """ - if n == 0: - return self.parent().one() - - return generic_power(self, n) - - def approximate_series(self, prec, name=None): - """ - Return the Taylor series with absolute precision ``prec`` approximated - from this series. - - INPUT: - - - ``prec`` -- an integer - - - ``name`` -- name of the variable; if it is ``None``, the name of - the variable of the series is used - - OUTPUT: a Taylor series with absolute precision ``prec`` - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: z = L.gen() - sage: f = (z - 2*z^3)^5/(1 - 2*z) - sage: f - z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + 32*z^10 - 16*z^11 + ... - sage: g = f.approximate_series(10) - sage: g - z^5 + 2*z^6 - 6*z^7 - 12*z^8 + 16*z^9 + O(z^10) - sage: g.parent() - Power Series Ring in z over Integer Ring - sage: h = (f^-1).approximate_series(3) - sage: h - z^-5 - 2*z^-4 + 10*z^-3 - 20*z^-2 + 60*z^-1 - 120 + 280*z - 560*z^2 + O(z^3) - sage: h.parent() - Taylor Series Ring in z over Integer Ring - """ - S = self.parent() - - if name is None: - name = S.variable_name() - - if self.valuation() < 0: - from sage.rings.all import TaylorSeriesRing - R = TaylorSeriesRing(S.base_ring(), name=name) - n = self.valuation() - return R([self[i] for i in range(n, prec)], n).add_bigoh(prec) - else: - from sage.rings.all import PowerSeriesRing - R = PowerSeriesRing(S.base_ring(), name=name) - return R([self[i] for i in range(prec)]).add_bigoh(prec) - - def polynomial(self, degree=None, name=None): - r""" - Return the polynomial or Taylor polynomial if the series is actually so. - - INPUT: - - - ``degree`` -- ``None`` or an integer - - - ``name`` -- name of the variable; if it is ``None``, the name of the variable - of the series is used - - OUTPUT: - - A Taylor polynomial if the valuation of the series is negative or - a polynomial otherwise. - - If ``degree`` is not ``None``, the terms of the series of degree - greater than ``degree`` are truncated first. If ``degree`` is ``None`` - and the series is not a polynomial or a Taylor polynomial, a - ``ValueError`` is raised. - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = L([1,0,0,2,0,0,0,3], 5); f - z^5 + 2*z^8 + 3*z^12 - sage: f.polynomial() - 3*z^12 + 2*z^8 + z^5 - - TESTS:: - - sage: g = L([1,0,0,2,0,0,0,3], -5); g - z^-5 + 2*z^-2 + 3*z^2 - sage: g.polynomial() - z^-5 + 2*z^-2 + 3*z^2 - sage: z = L.gen() - sage: f = (1 + z)/(z^3 - z^5) - sage: f - z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + ... - sage: f.polynomial(5) - z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + z^4 + z^5 - sage: f.polynomial(0) - z^-3 + z^-2 + z^-1 + 1 - sage: f.polynomial(-5) - 0 - sage: M = L(lambda n: n^2, 0) - sage: M.polynomial(3) - 9*z^3 + 4*z^2 + z - sage: M = L(lambda n: n^2, 0) - sage: M.polynomial(5) - 25*z^5 + 16*z^4 + 9*z^3 + 4*z^2 + z - - sage: f = 1/(1 + z) - sage: f.polynomial() - Traceback (most recent call last): - ... - ValueError: not a polynomial - """ - if degree is None: - if isinstance(self._coeff_stream, CoefficientStream_zero): - from sage.rings.all import PolynomialRing - return PolynomialRing(S.base_ring(), name=name).zero() - elif isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: - m = self._coeff_stream._degree - else: - raise ValueError("not a polynomial") - else: - m = degree + 1 - - S = self.parent() - - if name is None: - name = S.variable_name() - - from sage.rings.all import PolynomialRing - R = PolynomialRing(S.base_ring(), name=name) - return R([self[i] for i in range(m)]) - - def _repr_(self): - """ - Return the string representation of this Taylor series. - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: -1/(1 + 2*z) - -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + ... - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return '0' - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Taylor Series' - - atomic_repr = self.base_ring()._repr_option('element_is_atomic') - X = self.parent().variable_name() - v = self._coeff_stream._approximate_valuation - - if not isinstance(self._coeff_stream, CoefficientStream_exact): - m = v + 7 # long enough - else: - m = self._coeff_stream._degree + 3 + if not isinstance(self._coeff_stream, CoefficientStream_exact): + m = v + 7 # long enough + else: + m = self._coeff_stream._degree + 3 R = self.parent()._poly_ring if len(self.parent().variable_names()) == 1: z = R.gen() - ret = " + ".join([repr(R(self._coeff_stream[i] * z**i)) for i in range(v, m) - if self._coeff_stream[i]]) + ret = " + ".join([repr(self[i] * z**i) for i in range(v, m) + if self[i]]) else: - ret = " + ".join([repr(R(self._coeff_stream[i])) for i in range(v, m) - if self._coeff_stream[i]]) - + ret = " + ".join([repr(self[i]) for i in range(v, m) + if self[i]]) if not ret: return "0" # TODO: Better handling when ret == 0 but we have not checked up to the constant term @@ -2652,7 +2130,6 @@ def _mul_(self, other): coeff = CoefficientStream_dirichlet_convolution(left, right) return P.element_class(P, coeff) - def __invert__(self): """ Return the multiplicative inverse of the element. From a12571d0e124bda3fc0eb7c52f3aa62d69938c28 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 4 Aug 2021 13:19:04 +0200 Subject: [PATCH 052/355] remove dead code --- src/sage/rings/lazy_laurent_series.py | 5 ----- src/sage/rings/lazy_laurent_series_ring.py | 1 - 2 files changed, 6 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index f6a64cb9bc1..597d37f4bcb 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1975,11 +1975,6 @@ def _unicode_art_(self): return UnicodeArt('Uninitialized Lazy Laurent Series') return self._format_series(unicode_art, True) - # Use the polynomial printing - R = self.parent()._laurent_poly_ring - ret = repr(R([self._coeff_stream[i] for i in range(v, m)]).shift(v)) - # TODO: Better handling when ret == 0 but we have not checked up to the constant term - return ret + ' + ...' class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index 1dca22e6be3..d12bf5e2ae3 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -89,7 +89,6 @@ from sage.data_structures.coefficient_stream import ( CoefficientStream_zero, - CoefficientStream_exact, CoefficientStream_coefficient_function, CoefficientStream_exact, CoefficientStream_uninitialized From 362a99ed646b8f20b5956671fa701750c5207851 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 4 Aug 2021 17:56:29 +0200 Subject: [PATCH 053/355] improve repr, add monomial --- src/sage/rings/lazy_laurent_series.py | 383 ++++++++++++--------- src/sage/rings/lazy_laurent_series_ring.py | 94 ++++- 2 files changed, 297 insertions(+), 180 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 597d37f4bcb..1847f924fd8 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -148,6 +148,54 @@ def __init__(self, parent, coeff_stream): ModuleElement.__init__(self, parent) self._coeff_stream = coeff_stream + def finite_part(self, degree=None): + r""" + Return ``self`` truncated to ``degree`` as an element of an appropriate ring. + + INPUT: + + - ``degree`` -- ``None`` or an integer + + OUTPUT: + + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are removed first. If + ``degree`` is ``None`` and the series is not known to have + only finitely many nonzero coefficients, a ``ValueError`` is + raised. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = L([1,0,0,2,0,0,0,3], valuation=-3); f.finite_part() + z^-3 + 2 + 3*z^4 + sage: f.polynomial() + z^-3 + 2 + 3*z^4 + + sage: L = LazyDirichletSeriesRing(ZZ, "s") + sage: f = L([1,0,0,2,0,0,0,3], valuation=2); f.finite_part() + 3/9^s + 2/5^s + 1/2^s + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1/(1+x+y^2); f.finite_part(3) + -x^3 + 2*x*y^2 + x^2 - y^2 - x + 1 + """ + P = self.parent() + L = P._laurent_poly_ring + coeff_stream = self._coeff_stream + if degree is None: + if isinstance(coeff_stream, CoefficientStream_zero): + return L.zero() + elif isinstance(coeff_stream, CoefficientStream_exact) and not coeff_stream._constant: + m = coeff_stream._degree + else: + raise ValueError("not a polynomial") + else: + m = degree + 1 + + v = self.valuation() + return L.sum(self[i]*P.monomial(1, i) for i in range(v, m)) + def __getitem__(self, n): """ Return the coefficient of the term with exponent ``n`` of the series. @@ -618,6 +666,143 @@ def define(self, s): self._coeff_stream._target = s._coeff_stream + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z^-3 + z - 5 + z^-3 - 5 + z + sage: -1/(1 + 2*z) + -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + O(z^7) + sage: -z^-7/(1 + 2*z) + -z^-7 + 2*z^-6 - 4*z^-5 + 8*z^-4 - 16*z^-3 + 32*z^-2 - 64*z^-1 + O(1) + sage: L([1,5,0,3], valuation=-1, degree=5, constant=2) + z^-1 + 5 + 3*z^2 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) + sage: L(constant=5, valuation=2) + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: L(constant=5, degree=-2) + 5*z^-2 + 5*z^-1 + 5 + O(z) + sage: L(lambda x: x if x < 0 else 0, valuation=-2) + -2*z^-2 - z^-1 + O(z^5) + sage: L(lambda x: x if x < 0 else 0, valuation=2) + O(z^9) + sage: L(lambda x: x if x > 0 else 0, valuation=-2) + z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) + sage: L(lambda x: x if x > 0 else 0, valuation=-10) + O(z^-3) + + sage: L(None) + Uninitialized Lazy Laurent Series + sage: L(0) + 0 + + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4 + (-y + 1)*z^-4 + x^4*z^-3 + z^-2 + (x - y)*z^-1 + + (x^2 - 2*x*y + y^2) + (x^3 - 3*x^2*y + 3*x*y^2 - y^3)*z + + (x^4 - 4*x^3*y + 6*x^2*y^2 - 4*x*y^3 + y^4)*z^2 + O(z^3) + """ + if isinstance(self._coeff_stream, CoefficientStream_zero): + return '0' + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return 'Uninitialized Lazy Laurent Series' + return self._format_series(repr) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: latex(z^-3 + z - 5) + \frac{1}{z^{3}} - 5 + z + sage: latex(-1/(1 + 2*z)) + -1 + 2z - 4z^{2} + 8z^{3} - 16z^{4} + 32z^{5} - 64z^{6} + O(z^{7}) + sage: latex(-z^-7/(1 + 2*z)) + \frac{-1}{z^{7}} + \frac{2}{z^{6}} + \frac{-4}{z^{5}} + \frac{8}{z^{4}} + + \frac{-16}{z^{3}} + \frac{32}{z^{2}} + \frac{-64}{z} + O(1) + sage: latex(L([1,5,0,3], valuation=-1, degree=5, constant=2)) + \frac{1}{z} + 5 + 3z^{2} + 2z^{5} + 2z^{6} + 2z^{7} + O(z^{8}) + sage: latex(L(constant=5, valuation=2)) + 5z^{2} + 5z^{3} + 5z^{4} + O(z^{5}) + sage: latex(L(constant=5, degree=-2)) + \frac{5}{z^{2}} + \frac{5}{z} + 5 + O(z) + sage: latex(L(lambda x: x if x < 0 else 0, valuation=-2)) + \frac{-2}{z^{2}} + \frac{-1}{z} + O(z^{5}) + sage: latex(L(lambda x: x if x < 0 else 0, valuation=2)) + O(z^{9}) + sage: latex(L(lambda x: x if x > 0 else 0, valuation=-2)) + z + 2z^{2} + 3z^{3} + 4z^{4} + O(z^{5}) + sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) + O(\frac{1}{z^{3}}) + + sage: latex(L(None)) + \text{\texttt{Undef}} + sage: latex(L(0)) + 0 + + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: latex(z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4) + \frac{-y + 1}{z^{4}} + \frac{x^{4}}{z^{3}} + \frac{1}{z^{2}} + + \frac{x - y}{z} + x^{2} - 2 x y + y^{2} + + \left(x^{3} - 3 x^{2} y + 3 x y^{2} - y^{3}\right)z + + \left(x^{4} - 4 x^{3} y + 6 x^{2} y^{2} - 4 x y^{3} + y^{4}\right)z^{2} + + O(z^{3}) + """ + from sage.misc.latex import latex + if isinstance(self._coeff_stream, CoefficientStream_zero): + return latex('0') + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return latex("Undef") + return self._format_series(latex) + + def _ascii_art_(self): + r""" + Return an ascii art representation of ``self``. + + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).e() + sage: L. = LazyLaurentSeriesRing(e) + sage: L.options.display_length = 3 + sage: ascii_art(1 / (1 - e[1]*z)) + e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: L.options._reset() + """ + from sage.typeset.ascii_art import ascii_art, AsciiArt + if isinstance(self._coeff_stream, CoefficientStream_zero): + return AsciiArt('0') + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return AsciiArt('Uninitialized Lazy Laurent Series') + return self._format_series(ascii_art, True) + + def _unicode_art_(self): + r""" + Return a unicode art representation of ``self``. + + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).e() + sage: L. = LazyLaurentSeriesRing(e) + sage: L.options.display_length = 3 + sage: unicode_art(1 / (1 - e[1]*z)) + e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: L.options._reset() + """ + from sage.typeset.unicode_art import unicode_art, UnicodeArt + if isinstance(self._coeff_stream, CoefficientStream_zero): + return UnicodeArt('0') + if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: + return UnicodeArt('Uninitialized Lazy Laurent Series') + return self._format_series(unicode_art, True) + + class LazySequencesModuleElement(LazySequenceElement): r""" A lazy series where addition and scalar multiplication @@ -891,7 +1076,7 @@ def _lmul_(self, scalar): Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: g = L.gen(1) + sage: g = L.gen(2) sage: 2*g 2/2^z sage: -1*g @@ -1009,7 +1194,7 @@ class LazyCauchyProductSeries(RingElement): """ def __init__(self, parent): RingElement.__init__(self, parent) - + def _mul_(self, other): """ Return the product of this series with ``other``. @@ -1162,7 +1347,7 @@ def _div_(self, other): return P.zero() right = other._coeff_stream return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - + def __pow__(self, n): """ Return the ``n``-th power of the series. @@ -1839,142 +2024,6 @@ def _format_series(self, formatter, format_strings=False): return strformat("O({})".format(formatter(z**m))) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) - def _repr_(self): - r""" - Return a string representation of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: z^-3 + z - 5 - z^-3 - 5 + z - sage: -1/(1 + 2*z) - -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + O(z^7) - sage: -z^-7/(1 + 2*z) - -z^-7 + 2*z^-6 - 4*z^-5 + 8*z^-4 - 16*z^-3 + 32*z^-2 - 64*z^-1 + O(1) - sage: L([1,5,0,3], valuation=-1, degree=5, constant=2) - z^-1 + 5 + 3*z^2 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) - sage: L(constant=5, valuation=2) - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: L(constant=5, degree=-2) - 5*z^-2 + 5*z^-1 + 5 + O(z) - sage: L(lambda x: x if x < 0 else 0, valuation=-2) - -2*z^-2 - z^-1 + O(z^5) - sage: L(lambda x: x if x < 0 else 0, valuation=2) - O(z^9) - sage: L(lambda x: x if x > 0 else 0, valuation=-2) - z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) - sage: L(lambda x: x if x > 0 else 0, valuation=-10) - O(z^-3) - - sage: L(None) - Uninitialized Lazy Laurent Series - sage: L(0) - 0 - - sage: R. = QQ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4 - (-y + 1)*z^-4 + x^4*z^-3 + z^-2 + (x - y)*z^-1 - + (x^2 - 2*x*y + y^2) + (x^3 - 3*x^2*y + 3*x*y^2 - y^3)*z - + (x^4 - 4*x^3*y + 6*x^2*y^2 - 4*x*y^3 + y^4)*z^2 + O(z^3) - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return '0' - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Laurent Series' - return self._format_series(repr) - - def _latex_(self): - r""" - Return a latex representation of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: latex(z^-3 + z - 5) - \frac{1}{z^{3}} - 5 + z - sage: latex(-1/(1 + 2*z)) - -1 + 2z - 4z^{2} + 8z^{3} - 16z^{4} + 32z^{5} - 64z^{6} + O(z^{7}) - sage: latex(-z^-7/(1 + 2*z)) - \frac{-1}{z^{7}} + \frac{2}{z^{6}} + \frac{-4}{z^{5}} + \frac{8}{z^{4}} - + \frac{-16}{z^{3}} + \frac{32}{z^{2}} + \frac{-64}{z} + O(1) - sage: latex(L([1,5,0,3], valuation=-1, degree=5, constant=2)) - \frac{1}{z} + 5 + 3z^{2} + 2z^{5} + 2z^{6} + 2z^{7} + O(z^{8}) - sage: latex(L(constant=5, valuation=2)) - 5z^{2} + 5z^{3} + 5z^{4} + O(z^{5}) - sage: latex(L(constant=5, degree=-2)) - \frac{5}{z^{2}} + \frac{5}{z} + 5 + O(z) - sage: latex(L(lambda x: x if x < 0 else 0, valuation=-2)) - \frac{-2}{z^{2}} + \frac{-1}{z} + O(z^{5}) - sage: latex(L(lambda x: x if x < 0 else 0, valuation=2)) - O(z^{9}) - sage: latex(L(lambda x: x if x > 0 else 0, valuation=-2)) - z + 2z^{2} + 3z^{3} + 4z^{4} + O(z^{5}) - sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) - O(\frac{1}{z^{3}}) - - sage: latex(L(None)) - \text{\texttt{Undef}} - sage: latex(L(0)) - 0 - - sage: R. = QQ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: latex(z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4) - \frac{-y + 1}{z^{4}} + \frac{x^{4}}{z^{3}} + \frac{1}{z^{2}} - + \frac{x - y}{z} + x^{2} - 2 x y + y^{2} - + \left(x^{3} - 3 x^{2} y + 3 x y^{2} - y^{3}\right)z - + \left(x^{4} - 4 x^{3} y + 6 x^{2} y^{2} - 4 x y^{3} + y^{4}\right)z^{2} - + O(z^{3}) - """ - from sage.misc.latex import latex - if isinstance(self._coeff_stream, CoefficientStream_zero): - return latex('0') - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return latex("Undef") - return self._format_series(latex) - - def _ascii_art_(self): - r""" - Return an ascii art representation of ``self``. - - EXAMPLES:: - - sage: e = SymmetricFunctions(QQ).e() - sage: L. = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: ascii_art(1 / (1 - e[1]*z)) - e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() - """ - from sage.typeset.ascii_art import ascii_art, AsciiArt - if isinstance(self._coeff_stream, CoefficientStream_zero): - return AsciiArt('0') - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return AsciiArt('Uninitialized Lazy Laurent Series') - return self._format_series(ascii_art, True) - - def _unicode_art_(self): - r""" - Return a unicode art representation of ``self``. - - EXAMPLES:: - - sage: e = SymmetricFunctions(QQ).e() - sage: L. = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: unicode_art(1 / (1 - e[1]*z)) - e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() - """ - from sage.typeset.unicode_art import unicode_art, UnicodeArt - if isinstance(self._coeff_stream, CoefficientStream_zero): - return UnicodeArt('0') - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return UnicodeArt('Uninitialized Lazy Laurent Series') - return self._format_series(unicode_art, True) - class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" @@ -2026,44 +2075,40 @@ def change_ring(self, ring): Q = LazyTaylorSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) - def _repr_(self): + def _format_series(self, formatter, format_strings=False): """ - Return the string representation of this Taylor series. + Return nonzero ``self`` formatted by ``formatter``. TESTS:: - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: -1/(1 + 2*z) - -1 + 2*z + -4*z^2 + 8*z^3 + -16*z^4 + 32*z^5 + -64*z^6 + ... - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return '0' - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Taylor Series' - - atomic_repr = self.base_ring()._repr_option('element_is_atomic') - X = self.parent().variable_name() - v = self._coeff_stream._approximate_valuation + sage: L. = LazyTaylorSeriesRing(QQ) + sage: f = 1 / (2 - x^2 - y) + sage: f._format_series(ascii_art, True) - if not isinstance(self._coeff_stream, CoefficientStream_exact): - m = v + 7 # long enough + """ + if format_strings: + strformat = formatter else: - m = self._coeff_stream._degree + 3 + strformat = lambda x: x - R = self.parent()._poly_ring - if len(self.parent().variable_names()) == 1: - z = R.gen() - ret = " + ".join([repr(self[i] * z**i) for i in range(v, m) - if self[i]]) + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_valuation + if isinstance(cs, CoefficientStream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length else: - ret = " + ".join([repr(self[i]) for i in range(v, m) - if self[i]]) - if not ret: - return "0" - # TODO: Better handling when ret == 0 but we have not checked up to the constant term - if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: - return ret - return ret + ' + ...' + m = v + P.options.display_length + + # atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + + poly = [formatter(P.monomial(self[i], i)) for i in range(v, m) if self[i]] + poly = " + ".join(poly) + if isinstance(cs, CoefficientStream_exact) and not cs._constant: + return poly + return poly + strformat(" + O({})".format(formatter(P.monomial(1, m)))) class LazyDirichletSeries(LazySequencesModuleElement): diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index d12bf5e2ae3..e7957cc70a5 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -84,6 +84,7 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.global_options import GlobalOptions +from sage.symbolic.ring import SR from .lazy_laurent_series import LazyLaurentSeries, LazyDirichletSeries, LazyTaylorSeries @@ -168,6 +169,22 @@ def is_sparse(self): """ return self._sparse + @cached_method + def monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.monomial(1, 3) + z^3 + sage: L.monomial(2, -4) + 2*z^-4 + """ + L = self._laurent_poly_ring + return L(c) * L.gen() ** n + @cached_method def gen(self, n=0): r""" @@ -556,11 +573,11 @@ def __init__(self, base_ring, names, sparse=False, category=None): sage: TestSuite(L).run(skip='_test_elements') """ self._sparse = sparse - self._poly_ring = PolynomialRing(base_ring, names) if len(names) == 1: self._coeff_ring = base_ring else: self._coeff_ring = PolynomialRing(base_ring, names) + self._laurent_poly_ring = PolynomialRing(base_ring, names) Parent.__init__(self, base=base_ring, names=names, category=MagmasAndAdditiveMagmas().or_subcategory(category)) @@ -592,6 +609,23 @@ def _latex_(self): generators_rep = ", ".join(self.variable_names()) return latex(self.base_ring()) + r"[\![{}]\!]".format(generators_rep) + @cached_method + def monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.monomial(2, 3) + 2*z^3 + """ + m = len(self.variable_names()) + L = self._laurent_poly_ring + if m == 1: + return L(c) * L.gen() ** n + return L(c) + @cached_method def gen(self, n=0): """ @@ -613,7 +647,7 @@ def gen(self, n=0): raise IndexError("there is only one generator") raise IndexError("there are only %s generators" % m) - R = self._poly_ring + R = self._laurent_poly_ring if len(self.variable_names()) == 1: coeff_stream = CoefficientStream_exact([1], self._sparse, constant=ZZ.zero(), valuation=1) else: @@ -666,7 +700,7 @@ def _coerce_map_from_(self, S): if self.base_ring().has_coerce_map_from(S): return True - R = self._poly_ring + R = self._laurent_poly_ring if R.has_coerce_map_from(S): def make_series_from(poly): p_dict = poly.homogeneous_components() @@ -744,7 +778,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No valuation = 0 assert valuation >= 0, "the valuation of a Taylor series must be positive" - R = self._poly_ring + R = self._laurent_poly_ring if x is None: assert degree is None coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) @@ -817,7 +851,7 @@ def _an_element_(self): z + z^2 + z^3 + z^4 + ... """ c = self.base_ring()(1) - R = self._poly_ring + R = self._laurent_poly_ring coeff_stream = CoefficientStream_exact([R.one()], self._sparse, valuation=1, constant=c) return self.element_class(self, coeff_stream) @@ -832,7 +866,7 @@ def one(self): sage: L.one() 1 """ - R = self._poly_ring + R = self._laurent_poly_ring coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) return self.element_class(self, coeff_stream) @@ -849,6 +883,18 @@ def zero(self): """ return self.element_class(self, CoefficientStream_zero(self._sparse)) + # add options to class + class options(GlobalOptions): + NAME = 'LazyTaylorSeriesRing' + module = 'sage.rings.lazy_laurent_series_ring' + display_length = dict(default=7, + description='the number of coefficients to display from the valuation', + checker=lambda x: x in ZZ and x > 0) + constant_length = dict(default=3, + description='the number of coefficients to display for nonzero constant series', + checker=lambda x: x in ZZ and x > 0) + + ###################################################################### class LazyDirichletSeriesRing(UniqueRepresentation, Parent): @@ -882,6 +928,7 @@ def __init__(self, base_ring, names, sparse=False, category=None): self._sparse = sparse self._coeff_ring = base_ring + self._laurent_poly_ring = SR Parent.__init__(self, base=base_ring, names=names, category=MagmasAndAdditiveMagmas().or_subcategory(category)) @@ -897,7 +944,21 @@ def _repr_(self): return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) @cached_method - def gen(self, n=0): + def monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.monomial(5, 3) + 5/3^z + """ + L = self._laurent_poly_ring + return L(c) * L(n) ** -L(self.variable_name()) + + @cached_method + def gen(self, n=1): """ Return the `n`-th generator of this Dirichlet series ring. @@ -906,12 +967,12 @@ def gen(self, n=0): sage: L = LazyDirichletSeriesRing(ZZ, 'z') sage: L.gen() 1 - sage: L.gen(3) + sage: L.gen(4) 1/(4^z) """ - assert n >= 0 - coeff_stream = CoefficientStream_exact([1], self._sparse, valuation=n+1, constant=ZZ.zero()) + assert n >= 1 + coeff_stream = CoefficientStream_exact([1], self._sparse, valuation=n, constant=ZZ.zero()) return self.element_class(self, coeff_stream) def ngens(self): @@ -938,7 +999,7 @@ def gens(self): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: L.gens() Lazy family ((i))_{i in Positive integers} - sage: L.gens()[1] + sage: L.gens()[2] 1/(2^z) """ @@ -1105,3 +1166,14 @@ def zero(self): 0 """ return self.element_class(self, CoefficientStream_zero(self._sparse)) + + # add options to class + class options(GlobalOptions): + NAME = 'LazyDirichletSeriesRing' + module = 'sage.rings.lazy_laurent_series_ring' + display_length = dict(default=7, + description='the number of coefficients to display from the valuation', + checker=lambda x: x in ZZ and x > 0) + constant_length = dict(default=3, + description='the number of coefficients to display for nonzero constant series', + checker=lambda x: x in ZZ and x > 0) From 2d5285b32491f7b5a6de5a2e154407a1def0e9a6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Aug 2021 12:20:13 +0200 Subject: [PATCH 054/355] improve repr, fix doctests --- src/sage/rings/lazy_laurent_series.py | 218 ++++++++++++++------- src/sage/rings/lazy_laurent_series_ring.py | 28 +-- 2 files changed, 160 insertions(+), 86 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 1847f924fd8..3f7a603c28a 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1080,19 +1080,19 @@ def _lmul_(self, scalar): sage: 2*g 2/2^z sage: -1*g - -1/2^z + -1/(2^z) sage: 0*g 0 sage: M = L(lambda n: n); M - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) sage: M * 3 - 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) sage: M = L(lambda n: n); M - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) sage: M * 3 - 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + ... + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) sage: 1 * M is M True @@ -1233,9 +1233,9 @@ def _mul_(self, other): sage: L. = LazyTaylorSeriesRing(ZZ) sage: (1 - x)*(1 - y) - 1 + -x - y + x*y + 1 + (-x-y) + x*y sage: (1 - x)*(1 - y)*(1 - z) - 1 + -x - y - z + x*y + x*z + y*z + -x*y*z + 1 + (-x-y-z) + (x*y+x*z+y*z) + (-x*y*z) """ P = self.parent() @@ -1243,7 +1243,10 @@ def _mul_(self, other): right = other._coeff_stream if isinstance(left, CoefficientStream_zero) or isinstance(right, CoefficientStream_zero): return P.zero() - + if isinstance(left, CoefficientStream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.valuation() == 0: + return other # self == 1 + if isinstance(right, CoefficientStream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.valuation() == 0: + return self # the product is exact if and only if both of the factors are # exact, and one has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) @@ -1260,10 +1263,7 @@ def _mul_(self, other): v = left.valuation() + right.valuation() coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v) return P.element_class(P, coeff_stream) - if isinstance(left, CoefficientStream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.valuation() == 0: - return other # self == 1 - if isinstance(right, CoefficientStream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.valuation() == 0: - return self + return P.element_class(P, CoefficientStream_cauchy_product(left, right)) def __invert__(self): @@ -2031,24 +2031,18 @@ class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L(lambda i: i, valuation=3, constant=(-1, 6)) - 3*z^3 + 4*z^4 + 5*z^5 + -z^6 + -z^7 + -z^8 + ... - sage: L(lambda i: i, valuation=3, constant=-1, degree=6) - 3*z^3 + 4*z^4 + 5*z^5 + -z^6 + -z^7 + -z^8 + ... - - :: - - sage: f = 1 / (1 - z - z^2); f - 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + ... - sage: f.coefficient(100) - 573147844013817084101 + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1 / (1 - x^2 + y^3); f + 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 + sage: P. = PowerSeriesRing(ZZ, default_prec=101) + sage: g = 1 / (1 - x^2 + y^3); f[100] - g[100] + 0 Lazy Taylor series is picklable:: sage: g = loads(dumps(f)) sage: g - 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + ... + 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 sage: g == f True """ @@ -2066,7 +2060,7 @@ def change_ring(self, ring): sage: s = 2 + z sage: t = s.change_ring(QQ) sage: t^-1 - 1/2 + -1/4*z + 1/8*z^2 + -1/16*z^3 + 1/32*z^4 + -1/64*z^5 + 1/128*z^6 + ... + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) sage: t.parent() Lazy Taylor Series Ring in z over Rational Field @@ -2082,15 +2076,14 @@ def _format_series(self, formatter, format_strings=False): TESTS:: sage: L. = LazyTaylorSeriesRing(QQ) - sage: f = 1 / (2 - x^2 - y) - sage: f._format_series(ascii_art, True) + sage: f = 1 / (2 - x^2 + y) + sage: f._format_series(repr) + '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' + sage: f = (2 - x^2 + y) + sage: f._format_series(repr) + '2 + y + (-x^2)' """ - if format_strings: - strformat = formatter - else: - strformat = lambda x: x - P = self.parent() cs = self._coeff_stream v = cs._approximate_valuation @@ -2102,13 +2095,48 @@ def _format_series(self, formatter, format_strings=False): else: m = v + P.options.display_length - # atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, CoefficientStream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P.monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - poly = [formatter(P.monomial(self[i], i)) for i in range(v, m) if self[i]] - poly = " + ".join(poly) - if isinstance(cs, CoefficientStream_exact) and not cs._constant: - return poly - return poly + strformat(" + O({})".format(formatter(P.monomial(1, m)))) + return poly class LazyDirichletSeries(LazySequencesModuleElement): @@ -2149,16 +2177,16 @@ def _mul_(self, other): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L(constant=1); g - 1 + 1/(2^z) + 1/(3^z) + ... + 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) sage: g*g - 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: [number_of_divisors(n) for n in range(1, 8)] [1, 2, 2, 3, 2, 4, 2] sage: mu = L(moebius); mu - 1 + -1/2^z + -1/3^z + -1/5^z + 1/(6^z) + -1/7^z + ... + 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) sage: g*mu - 1 + ... + 1 + O(1/(8^z)) sage: L.one() * mu is mu True sage: mu * L.one() is mu @@ -2167,6 +2195,15 @@ def _mul_(self, other): P = self.parent() left = self._coeff_stream right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) + and left._initial_coefficients == (P._coeff_ring.one(),) + and left.valuation() == 1): + return other # self == 1 + if (isinstance(right, CoefficientStream_exact) + and right._initial_coefficients == (P._coeff_ring.one(),) + and right.valuation() == 1): + return self + coeff = CoefficientStream_dirichlet_convolution(left, right) return P.element_class(P, coeff) @@ -2178,10 +2215,10 @@ def __invert__(self): sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) sage: ~L(constant=1) - L(moebius) - 0 + O(1/(8^z)) sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) sage: ~L(constant=1) - L(moebius) - 0 + O(1/(8^z)) """ P = self.parent() @@ -2220,38 +2257,75 @@ def __pow__(self, n): return generic_power(self, n) - def _repr_(self): + def _format_series(self, formatter, format_strings=False): """ - Return the string representation of this Dirichlet series. + Return nonzero ``self`` formatted by ``formatter``. TESTS:: - sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ - if isinstance(self._coeff_stream, CoefficientStream_zero): - return '0' - if isinstance(self._coeff_stream, CoefficientStream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Dirichlet Series' + sage: L = LazyDirichletSeriesRing(QQ, "s") + sage: f = L(constant=1) + sage: f._format_series(repr) + '1 + 1/(2^s) + 1/(3^s) + O(1/(4^s))' + + sage: L([1,-1,1])._format_series(repr) + '1 - 1/(2^s) + 1/(3^s)' - atomic_repr = self.base_ring()._repr_option('element_is_atomic') - X = self.parent().variable_name() - v = self._coeff_stream._approximate_valuation + sage: L([1,-1,1])._format_series(ascii_art) + -s -s + 1 + -2 + 3 + + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_valuation + if isinstance(cs, CoefficientStream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length - if not isinstance(self._coeff_stream, CoefficientStream_exact): - m = v + 7 # long enough + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, CoefficientStream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P.monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] else: - m = self._coeff_stream._degree + 3 - - # Use the symbolic ring printing - from sage.calculus.var import var - from sage.symbolic.ring import SR - variable = var(self.parent().variable_name()) - ret = " + ".join([repr(SR(self._coeff_stream[i])*i**(-variable)) - for i in range(v, m) if self._coeff_stream[i]]) - if not ret: - return "0" - # TODO: Better handling when ret == 0 but we have not checked up to the constant term + bigO = [] - if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: - return ret - return ret + ' + ...' + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index e7957cc70a5..baf7cf0667a 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -735,28 +735,28 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: L = LazyTaylorSeriesRing(ZZ, 'z') sage: L(lambda i: i, 5, 1, 10) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + ... + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: L(lambda i: i, 5, (1, 10)) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + ... + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: X = L(constant=5, degree=2); X - 5*z^2 + 5*z^3 + 5*z^4 + ... + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) sage: X.valuation() 2 sage: e = L(lambda n: n+1); e - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + ... + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) sage: f = e^-1; f - 1 + -2*z + z^2 + ... + 1 - 2*z + z^2 + O(z^7) sage: f.coefficient(10) 0 sage: f[20] 0 sage: L(valuation=2, constant=1) - z^2 + z^3 + z^4 + ... + z^2 + z^3 + z^4 + O(z^5) sage: L(constant=1) - 1 + z + z^2 + ... + 1 + z + z^2 + O(z^3) Alternatively, ``x`` can be a list of elements of the base ring. Then these elements are read as coefficients of the terms of @@ -768,7 +768,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No z + 2*z^2 + 3*z^3 + 4*z^4 sage: g = L([1,3,5,7,9], 5, -1); g - z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 + -z^10 + -z^11 + -z^12 + ... + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) .. TODO:: @@ -1042,20 +1042,20 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: L(3) 3 sage: L(lambda i: i, constant=1, degree=6) - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + ... + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + O(1/(9^z)) sage: X = L(constant=5, degree=3); X - 5/3^z + 5/4^z + 5/5^z + ... + 5/3^z + 5/4^z + 5/5^z + O(1/(6^z)) sage: X.valuation() 3 sage: e = L(moebius); e - 1 + -1/2^z + -1/3^z + -1/5^z + 1/(6^z) + -1/7^z + ... + 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) sage: L([0], constant=1) - 1/(2^z) + 1/(3^z) + 1/(4^z) + ... + 1/(2^z) + 1/(3^z) + 1/(4^z) + O(1/(5^z)) sage: L(constant=1) - 1 + 1/(2^z) + 1/(3^z) + ... + 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) Alternatively, ``x`` can be a list of elements of the base ring. Then these elements are read as coefficients of the terms of @@ -1066,7 +1066,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: f = L([1,2,3,4], 4); f 1/(4^z) + 2/5^z + 3/6^z + 4/7^z sage: g = L([1,3,5,7,9], 6, -1); g - 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z + -1/11^z + -1/12^z + -1/13^z + ... + 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) - 1/(13^z) + O(1/(14^z)) TESTS:: From 117022ddad90dd37cfb7b2cc7399d358b3acc8e9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Aug 2021 13:07:03 +0200 Subject: [PATCH 055/355] check for nonzero constant in multivariate Taylor series --- src/sage/rings/lazy_laurent_series_ring.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index baf7cf0667a..9f1869bdc1d 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -733,7 +733,6 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No 1 sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L(lambda i: i, 5, 1, 10) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: L(lambda i: i, 5, (1, 10)) @@ -773,17 +772,26 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No .. TODO:: Add a method to change the sparse/dense implementation. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: L(constant=1) + Traceback (most recent call last): + ... + ValueError: constant must be zero for multivariate Taylor series + """ if valuation is None: valuation = 0 - assert valuation >= 0, "the valuation of a Taylor series must be positive" + if valuation < 0: + raise ValueError("the valuation of a Taylor series must be positive") R = self._laurent_poly_ring if x is None: assert degree is None coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) return self.element_class(self, coeff_stream) - try: # Try to build stuff using the polynomial ring constructor x = R(x) @@ -793,6 +801,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant, degree = constant if constant is not None: constant = R(constant) + if len(self.variable_names()) > 1 and constant: + raise ValueError(f"constant must be zero for multivariate Taylor series") if x in R: if not x and not constant: coeff_stream = CoefficientStream_zero(self._sparse) From b11e9e09dae1c26a3eaa3d99187e9e3e24b57d9e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Aug 2021 17:36:35 +0200 Subject: [PATCH 056/355] optionally check coeffcients in Taylor series --- src/sage/rings/lazy_laurent_series_ring.py | 52 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index 9f1869bdc1d..ae1e5d9c4a0 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -321,6 +321,14 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: g z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) + TESTS:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L(lambda n: 1/(n+1), degree=3) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + .. TODO:: Add a method to change the sparse/dense implementation. @@ -369,7 +377,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if constant is None: constant = ZZ.zero() z = R.gen() - p = [x(i) for i in range(valuation, degree)] + p = [BR(x(i)) for i in range(valuation, degree)] coeff_stream = CoefficientStream_exact(p, self._sparse, valuation=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) return self.element_class(self, CoefficientStream_coefficient_function(x, self.base_ring(), self._sparse, valuation)) @@ -713,7 +721,7 @@ def make_series_from(poly): return False - def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None): + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): """ Construct a Taylor series from ``x``. @@ -723,6 +731,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - ``constant`` -- (optional) the eventual constant of the series - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved EXAMPLES:: @@ -775,12 +784,30 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No TESTS:: - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(ZZ) sage: L(constant=1) Traceback (most recent call last): ... ValueError: constant must be zero for multivariate Taylor series + sage: L(lambda n: 0) + O(x,y)^7 + + sage: L(lambda n: n)[3]; + Traceback (most recent call last): + ... + ValueError: coefficient 1 at degree 1 is not a homogeneous polynomial + + sage: L([1, 2, 3]); + Traceback (most recent call last): + ... + ValueError: unable to convert [1, 2, 3] into a lazy Taylor series + + sage: L(lambda n: n, degree=3); + Traceback (most recent call last): + ... + ValueError: coefficients must be homogeneous polynomials of the correct degree + """ if valuation is None: valuation = 0 @@ -788,6 +815,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No raise ValueError("the valuation of a Taylor series must be positive") R = self._laurent_poly_ring + BR = self.base_ring() if x is None: assert degree is None coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) @@ -840,13 +868,27 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if constant is None: constant = ZZ.zero() z = R.gen() - p = [x(i) for i in range(valuation, degree)] + if len(self.variable_names()) == 1: + p = [BR(x(i)) for i in range(valuation, degree)] + else: + p = [R(x(i)) for i in range(valuation, degree)] + if not all(e.is_homogeneous() and e.degree() == i + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be homogeneous polynomials of the correct degree") coeff_stream = CoefficientStream_exact(p, self._sparse, valuation=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) - coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) + if check and len(self.variable_names()) > 1: + def y(n): + e = R(x(n)) + if not e or e.is_homogeneous() and e.degree() == n: + return e + raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) + coeff_stream = CoefficientStream_coefficient_function(y, self._coeff_ring, self._sparse, valuation) + else: + coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy Taylor series") From 174b6015627c192fb184931103c2fea0dd224ac8 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Aug 2021 17:36:54 +0200 Subject: [PATCH 057/355] initial implementation of composition for Taylor series --- src/sage/rings/lazy_laurent_series.py | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 3f7a603c28a..962eefce2bb 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -107,6 +107,7 @@ CoefficientStream_zero, CoefficientStream_exact, CoefficientStream_uninitialized, + CoefficientStream_coefficient_function, CoefficientStream_dirichlet_convolution, CoefficientStream_dirichlet_inv ) @@ -2046,6 +2047,86 @@ class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): sage: g == f True """ + def __call__(self, *g): + r"""Return the composition of ``self`` with ``g``. + + The arity of ``self`` must be equal to the number of + arguments provided. + + Given two Taylor Series `f` and `g` over the same base ring, the + composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + + - `g = 0` and `val(f) >= 0`, + - `g` is non-zero and `f` has only finitely many non-zero coefficients, + - `g` is non-zero and `val(g) > 0`. + + INPUT: + + - ``g`` -- other series, all of the same parent. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyTaylorSeriesRing(ZZ) + sage: g1 = 1/(1-x); g2 = x+y^2 + sage: p = a^2 + b + 1 + sage: p(g1, g2) - g1^2 - g2 - 1 + O(x,y,z)^7 + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyTaylorSeriesRing(QQ) + + The number of mappings from a set with `m` elements to a set + with `n` elements:: + + sage: Ea = M(lambda n: 1/factorial(n)) + sage: Ex = L(lambda n: 1/factorial(n)*x^n) + sage: Ea(Ex*y)[5] + 1/24*x^4*y + 2/3*x^3*y^2 + 3/4*x^2*y^3 + 1/6*x*y^4 + 1/120*y^5 + + So, there are `3! 2! 2/3 = 8` mappings from a three element + set to a two element set. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1/(1-x-y) + sage: f(f) + Traceback (most recent call last): + ... + ValueError: arity of must be equal to the number of arguments provided + + """ + if len(g) != len(self.parent().variable_names()): + raise ValueError("arity of must be equal to the number of arguments provided") + + # f has finite length + if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: + # constant polynomial + poly = self.finite_part() + if poly.is_constant(): + return self + return poly(g) + + g0 = g[0] + P = g0.parent() + R = P._coeff_ring + if len(g) == 1: + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + r = R(0) + for i in range(n+1): + r += self[i]*(g0 ** i)[n] + return r + else: + def coefficient(n): + r = R(0) + for i in range(n+1): + r += self[i](g)[n] + return r + coeff_stream = CoefficientStream_coefficient_function(coefficient, P._coeff_ring, P._sparse, 0) + return P.element_class(P, coeff_stream) + def change_ring(self, ring): """ Return this series with coefficients converted to elements of ``ring``. From a1897caf6ae27503a3342eeafd98be60e63c5a69 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Aug 2021 19:41:30 +0200 Subject: [PATCH 058/355] tiny optimizations and take care of noncommutativity --- .../data_structures/coefficient_stream.py | 126 ++++++++++++++---- src/sage/rings/lazy_laurent_series.py | 65 +++++++-- 2 files changed, 152 insertions(+), 39 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index 5d66fb5e793..acd739aaf9a 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -72,8 +72,8 @@ Coefficient streams can be multiplied by a scalar:: - sage: from sage.data_structures.coefficient_stream import CoefficientStream_scalar - sage: h = CoefficientStream_scalar(f, 2) + sage: from sage.data_structures.coefficient_stream import CoefficientStream_lmul + sage: h = CoefficientStream_lmul(f, 2) sage: [h[i] for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -640,12 +640,12 @@ class CoefficientStream_unary(CoefficientStream_inexact): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_cauchy_inverse, CoefficientStream_scalar) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_cauchy_inverse, CoefficientStream_lmul) sage: f = CoefficientStream_coefficient_function(lambda n: 2*n, ZZ, False, 1) sage: g = CoefficientStream_cauchy_inverse(f) sage: [g[i] for i in range(10)] [-1, 1/2, 0, 0, 0, 0, 0, 0, 0, 0] - sage: g = CoefficientStream_scalar(f, 2) + sage: g = CoefficientStream_lmul(f, 2) sage: [g[i] for i in range(10)] [0, 4, 8, 12, 16, 20, 24, 28, 32, 36] """ @@ -691,11 +691,11 @@ def __eq__(self, other): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_scalar) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_coefficient_function, CoefficientStream_lmul) sage: f = CoefficientStream_coefficient_function(lambda n: 2*n, ZZ, False, 1) sage: g = CoefficientStream_coefficient_function(lambda n: n, ZZ, False, 1) - sage: h = CoefficientStream_scalar(f, 2) - sage: n = CoefficientStream_scalar(g, 2) + sage: h = CoefficientStream_lmul(f, 2) + sage: n = CoefficientStream_lmul(g, 2) sage: h == n False sage: n == n @@ -1551,10 +1551,78 @@ def iterate_coefficients(self): ##################################################################### # Unary operations +class CoefficientStream_lmul(CoefficientStream_unary): + """ + Operator for multiplying a coefficient stream with a scalar from the left. + + INPUT: + + - ``series`` -- a :class:`CoefficientStream` + - ``scalar`` -- a scalar + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_lmul, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 1) + sage: g = CoefficientStream_lmul(f, 2) + sage: [g[i] for i in range(10)] + [0, 2, 2, 2, 2, 2, 2, 2, 2, 2] + """ + def __init__(self, series, scalar): + """ + Initialize ``self``. + + TESTS:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_lmul, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: -1, ZZ, True, 0) + sage: g = CoefficientStream_lmul(f, 3) + """ + self._scalar = scalar + super().__init__(series, series._is_sparse, series._approximate_valuation) + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient -class CoefficientStream_scalar(CoefficientStream_unary): + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_lmul, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 1) + sage: g = CoefficientStream_lmul(f, 3) + sage: g.get_coefficient(5) + 15 + sage: [g.get_coefficient(i) for i in range(10)] + [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] + """ + return self._scalar * self._series[n] + + def iterate_coefficients(self): + """ + A generator for the coefficients of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_lmul, CoefficientStream_coefficient_function) + sage: f = CoefficientStream_coefficient_function(lambda n: n^2, ZZ, False, 1) + sage: g = CoefficientStream_lmul(f, 4) + sage: n = g.iterate_coefficients() + sage: [next(n) for i in range(10)] + [4, 16, 36, 64, 100, 144, 196, 256, 324, 400] + """ + n = self._offset + while True: + yield self.get_coefficient(n) + n += 1 + + +class CoefficientStream_rmul(CoefficientStream_unary): """ - Operator for multiplying a coefficient stream with a scalar. + Operator for multiplying a coefficient stream with a scalar from the left. INPUT: @@ -1563,9 +1631,9 @@ class CoefficientStream_scalar(CoefficientStream_unary): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_scalar, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_rmul, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 1) - sage: g = CoefficientStream_scalar(f, 2) + sage: g = CoefficientStream_rmul(f, 2) sage: [g[i] for i in range(10)] [0, 2, 2, 2, 2, 2, 2, 2, 2, 2] """ @@ -1575,9 +1643,9 @@ def __init__(self, series, scalar): TESTS:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_scalar, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_rmul, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: -1, ZZ, True, 0) - sage: g = CoefficientStream_scalar(f, 3) + sage: g = CoefficientStream_rmul(f, 3) """ self._scalar = scalar super().__init__(series, series._is_sparse, series._approximate_valuation) @@ -1592,9 +1660,9 @@ def get_coefficient(self, n): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_scalar, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_rmul, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: n, ZZ, True, 1) - sage: g = CoefficientStream_scalar(f, 3) + sage: g = CoefficientStream_rmul(f, 3) sage: g.get_coefficient(5) 15 sage: [g.get_coefficient(i) for i in range(10)] @@ -1608,16 +1676,16 @@ def iterate_coefficients(self): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_scalar, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_rmul, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: n^2, ZZ, False, 1) - sage: g = CoefficientStream_scalar(f, 4) + sage: g = CoefficientStream_rmul(f, 4) sage: n = g.iterate_coefficients() sage: [next(n) for i in range(10)] [4, 16, 36, 64, 100, 144, 196, 256, 324, 400] """ n = self._offset while True: - yield self._series[n] * self._scalar + yield self.get_coefficient(n) n += 1 @@ -1685,7 +1753,7 @@ def iterate_coefficients(self): """ n = self._offset while True: - yield -self._series[n] + yield self.get_coefficient(n) n += 1 @@ -1744,7 +1812,9 @@ def get_coefficient(self, n): return self._ainv c = self._zero for k in range(v, n): - c += self[k] * self._series[n - v - k] + l = self[k] + if l: + c += l * self._series[n - v - k] return -c * self._ainv def iterate_coefficients(self): @@ -1769,9 +1839,13 @@ def iterate_coefficients(self): c = self._zero m = min(len(self._cache), n) for k in range(m): - c += self._cache[k] * self._series[n - v - k] + l = self._cache[k] + if l: + c += l * self._series[n - v - k] for k in range(v+m, v+n): - c += self[k] * self._series[n - k] + l = self[k] + if l: + c += l * self._series[n - k] yield -c * self._ainv @@ -1833,7 +1907,10 @@ def get_coefficient(self, n): sage: [g.get_coefficient(i) for i in range(-1, 3)] [1, 0, 1, 1] """ - return self._function(self._ring(self._series[n])) if self._series[n] else self._series[n] + c = self._series[n] + if c: + return self._function(self._ring(c)) + return c def iterate_coefficients(self): """ @@ -1857,6 +1934,5 @@ def iterate_coefficients(self): """ n = self._offset while True: - yield self._function(self._ring(self._series[n])) if self._series[n] else self._series[n] + yield self.get_coefficient(n) n += 1 - diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 962eefce2bb..4d815b375b9 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -98,7 +98,8 @@ CoefficientStream_sub, CoefficientStream_div, CoefficientStream_composition, - CoefficientStream_scalar, + CoefficientStream_lmul, + CoefficientStream_rmul, CoefficientStream_neg, CoefficientStream_cauchy_inverse, CoefficientStream_apply_coeff, @@ -1010,7 +1011,7 @@ def _sub_(self, other): def _lmul_(self, scalar): r""" Scalar multiplication for module elements with the module - element on the left and the scalar on the right. + element on the right and the scalar on the left. INPUT: @@ -1078,27 +1079,19 @@ def _lmul_(self, scalar): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L.gen(2) - sage: 2*g + sage: 2 * g 2/2^z - sage: -1*g + sage: -1 * g -1/(2^z) sage: 0*g 0 sage: M = L(lambda n: n); M 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - sage: M * 3 - 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) - - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: M = L(lambda n: n); M - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - sage: M * 3 + sage: 3 * M 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) sage: 1 * M is M True - sage: M * 1 is M - True """ P = self.parent() @@ -1114,7 +1107,51 @@ def _lmul_(self, scalar): return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v, constant=c, degree=self._coeff_stream._degree)) - return P.element_class(P, CoefficientStream_scalar(self._coeff_stream, scalar)) + return P.element_class(P, CoefficientStream_lmul(self._coeff_stream, scalar)) + + def _rmul_(self, scalar): + r""" + Scalar multiplication for module elements with the module + element on the left and the scalar on the right. + + INPUT: + + - ``scalar`` -- an element of the base ring + + EXAMPLES: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: M = L(lambda n: 1 + n, valuation=0) + sage: 2 * M == M * 2 + True + + We take care of noncommutativity of the base ring:: + + sage: M = MatrixSpace(ZZ, 2) + sage: L. = LazyTaylorSeriesRing(M) + sage: m = M([[1, 1],[0, 1]]) + sage: n = M([[1, 0],[1, 1]]) + sage: a = L(lambda k: n^k) + sage: (m*a - a*m)[3] + [-3 0] + [ 0 3] + + """ + P = self.parent() + if not scalar: + return P.zero() + if scalar == 1: + return self + + if isinstance(self._coeff_stream, CoefficientStream_exact): + c = self._coeff_stream._constant * scalar + v = self._coeff_stream.valuation() + initial_coefficients = [v * scalar for v in self._coeff_stream._initial_coefficients] + return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + valuation=v, constant=c, + degree=self._coeff_stream._degree)) + return P.element_class(P, CoefficientStream_rmul(self._coeff_stream, scalar)) + def _neg_(self): """ From 094d64a17f45068f3cefc68bd0d1e2a44783bfc9 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 5 Aug 2021 14:15:42 -0400 Subject: [PATCH 059/355] New methods in ring.py: ngens, polynomial_ring, from_polynomial. New methods in element.py: to_polynomial, weights_list, is_homogeneous, weight, homogeneous_components. --- src/sage/modular/quasimodform/element.py | 114 +++++++++++++++++++++++ src/sage/modular/quasimodform/ring.py | 92 ++++++++++++++++++ 2 files changed, 206 insertions(+) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 2d68bfb254e..87f961fb7ba 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -321,3 +321,117 @@ def is_modular_form(self): return self._polynomial[0].is_modular_form() else: return False + + def to_polynomial(self, names='E2, E4, E6'): + r""" + Return a polynomial `P(E_2, E_4, E_6)` corresponding to the given form + where `E_2`, `E_4` and `E_6` are the generators of the quasimodular + form ring given by :meth:`~sage.modular.quasiform.ring.QuasiModularForms.gens`. + + INPUT: + + - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names + (strings), or a comma separated string. Correspond to the names of the + variables; + + OUTPUT: A multivariate polynomial in the variables ``names`` + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0 + QM.1).to_polynomial() + E4 + E2 + sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).to_polynomial() + E2*E6 + 2*E4^2 + E2 + 1/2 + """ + P = self.parent().polynomial_ring(names) + g0, g1 = self.parent().modular_forms_subring().polynomial_ring(names='x').gens() + E2, E4, E6 = P.gens() + return sum(f.to_polynomial().subs({g0:E4, g1:E6}) * E2 ** exp for exp, f in enumerate(self._coefficients)) + + def weights_list(self): + r""" + Return the list of the weights of all the graded components of the given + graded quasimodular form. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).weights_list() + [2] + sage: (QM.0 + QM.1 + QM.2).weights_list() + [2, 4, 6] + sage: (QM.0 * QM.1 + QM.2).weights_list() + [6] + sage: QM(1/2).weights_list() + [0] + """ + return sorted(list(self.to_polynomial().homogeneous_components())) + + def is_homogeneous(self): + r""" + Return True if the graded quasimodular form is a homogeneous element, + that is it lives in a unique graded components of the graded ring of + self. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).is_homogeneous() + True + sage: (QM.0 + QM.1).is_homogeneous() + False + sage: (QM.0 * QM.1 + QM.2).is_homogeneous() + True + sage: QM(1).is_homogeneous() + True + sage: (1 + QM.0).is_homogeneous() + False + """ + return len(self.weights_list()) == 1 + + def weight(self): + r""" + Return the weight of the given quasiform. Note that the given form must + be homogeneous. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).weight() + 2 + sage: (QM.0 * QM.1 + QM.2).weight() + 6 + sage: QM(1/2).weight() + 0 + sage: (QM.0 + QM.1).weight() + Traceback (most recent call last): + ... + ValueError: the given graded quasiform is not an homogeneous element + """ + if self.is_homogeneous(): + return self.to_polynomial().degree() + else: + raise ValueError("the given graded quasiform is not an homogeneous element") + + def homogeneous_components(self): + r""" + Return a dictionnary where the values are the homogeneous components of + the given graded form and the keys are the weights of those components. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).homogeneous_components() + {2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)} + sage: (QM.0 + QM.1 + QM.2).homogeneous_components() + {2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6), + 4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6), + 6: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)} + sage: (1 + QM.0).homogeneous_components() + {0: 1, 2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)} + """ + QM = self.parent() + poly_self = self.to_polynomial() + pol_hom_comp = poly_self.homogeneous_components() + return { k : QM.from_polynomial(pol) for k, pol in pol_hom_comp.items()} diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index d191ff347a2..ec7de41fd47 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -72,6 +72,9 @@ from sage.rings.all import Integer, QQ, ZZ from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.term_order import TermOrder from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -382,6 +385,18 @@ def gens(self): generators = gens # alias + def ngens(self): + r""" + Return the number of generators of the given graded quasimodular forms + ring. + + EXAMPLES:: + + sage: QuasiModularForms(1).ngens() + 3 + """ + return len(self.gens()) + def gen(self, n): r""" Return the `n`-th generator of the quasimodular forms ring. @@ -458,6 +473,83 @@ def polygen(self): """ return self.__polynomial_subring.gen() + def polynomial_ring(self, names='E2, E4, E6'): + r""" + Return a multivariate polynomial ring isomorphic to the given graded + quasimodular forms ring. In the case of the full modular group, this + ring is `R[E_2, E_4, E_6]` where `E_2`, `E_4` and `E_6` have degrees 2, + 4 and 6 respectively. + + INPUT: + + - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names + (strings), or a comma separated string. Correspond to the names of the + variables; + + OUTPUT: A multivariate polynomial ring in the variables ``names`` + + EXAMPLES: + + sage: QM = QuasiModularForms(1) + sage: P. = QM.polynomial_ring(); P + Multivariate Polynomial Ring in E2, E4, E6 over Rational Field + sage: E2.degree() + 2 + sage: E4.degree() + 4 + sage: E6.degree() + 6 + sage: P. = QQ[] + sage: QM.from_polynomial(x+y+z+w) + Traceback (most recent call last): + ... + ValueError: the number of variables (4) of the given polynomial cannot exceed the number of generators (3) of the quasimodular forms ring + """ + return PolynomialRing(self.base_ring(), 3, names, order=TermOrder('wdeglex', [ZZ(2), ZZ(4), ZZ(6)])) + + def from_polynomial(self, polynomial): + r""" + Convert the given polynomial `P(X, Y, Z)` to the graded quasiform + `P(E_2, E_4, E_6)` where `E_2`, `E_4` and `E_6` are the generators given + by :meth:`~sage.modular.quasimodform.ring.QuasiModularForms.gens`. + + INPUT: + + - ``plynomial`` -- A multivariate polynomial + + OUTPUT: the graded quasimodular forms `P(E_2, E_4, E_6)` + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: P. = QQ[] + sage: QM.from_polynomial(x) + 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) + sage: QM.from_polynomial(x) == QM.0 + True + sage: QM.from_polynomial(y) == QM.1 + True + sage: QM.from_polynomial(z) == QM.2 + True + sage: QM.from_polynomial(x^2 + y + x*z + 1) + 4 - 336*q - 2016*q^2 + 322368*q^3 + 3691392*q^4 + 21797280*q^5 + O(q^6) + + TESTS:: + + sage: QuasiModularForms(1).from_polynomial('x') + Traceback (most recent call last): + ... + TypeError: the input must be a polynomial + """ + if not isinstance(polynomial, (MPolynomial, Polynomial)): + raise TypeError('the input must be a polynomial') + poly_parent = polynomial.parent() + nb_var = poly_parent.ngens() + if nb_var > self.ngens(): + raise ValueError("the number of variables (%s) of the given polynomial cannot exceed the number of generators (%s) of the quasimodular forms ring" % (nb_var, self.ngens())) + gens_dict = {poly_parent.gen(i):self.gen(i) for i in range(0, nb_var)} + return self(polynomial.subs(gens_dict)) + def differentiation_operator(self, f): r""" Compute the formal derivative `q\frac{d}{dq}` of the q-expansion of a From c8fb9d15075bb515656e59d9e9db3dc4f88197e8 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 5 Aug 2021 16:06:02 -0400 Subject: [PATCH 060/355] fix some docstring. small fix. --- src/sage/modular/quasimodform/element.py | 7 +++++-- src/sage/modular/quasimodform/ring.py | 23 +++++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 87f961fb7ba..22cd2aa657a 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -35,7 +35,8 @@ class QuasiModularFormsElement(ModuleElement): f_0 + f_1 E_2 + f_2 E_2^2 + \cdots + f_m E_2^m - where each `f_i` a graded modular form element (see :meth:``) + where each `f_i` a graded modular form element + (see :class:`~sage.modular.modform.element.GradedModularFormElement`) EXAMPLES:: @@ -53,9 +54,11 @@ class QuasiModularFormsElement(ModuleElement): sage: QM.0 == QM.1 False - Quasimodular forms ring element can be created via a polynomial in `E2`:: + Quasimodular forms ring element can be created via a polynomial in `E2` over the ring of modular forms:: sage: E2 = QM.polygen() + sage: E2.parent() + Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field sage: QM(E2) 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) sage: M = QM.modular_forms_subring() diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index ec7de41fd47..ccb59e36658 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -46,8 +46,9 @@ .. NOTE: - Only the ring of quasimodular forms for the full modular group have been + - Only the ring of quasimodular forms for the full modular group have been implemented. + - Currently, the only supported base ring is the Rational Field. AUTHORS: @@ -102,6 +103,17 @@ class QuasiModularForms(Parent, UniqueRepresentation): sage: QM.weigt_2_eisenstein_series() 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) + + The current implementation of quasimodular forms is only for the full modular group and for the ring of rationnal numbers:: + + sage: QuasiModularForms(Gamma0(2)) + Traceback (most recent call last): + ... + NotImplementedError: space of quasimodular forms are only implemented for the full modular group + sage: QuasiModularForms(1, GF(5)) + Traceback (most recent call last): + ... + NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring """ Element = QuasiModularFormsElement def __init__(self, group=1, base_ring=QQ, name='E2'): @@ -154,12 +166,11 @@ def __init__(self, group=1, base_ring=QQ, name='E2'): elif not is_CongruenceSubgroup(group): raise ValueError("Group (=%s) should be a congruence subgroup" % group) elif group is not Gamma0(1): - raise NotImplementedError("space of quasimodular forms are implemented for the full modular group") + raise NotImplementedError("space of quasimodular forms are only implemented for the full modular group") - #Check if the base ring is a field - #For some reasons, there is a problem when computing a basis of ModularForms - if not base_ring.is_field(): - raise ValueError("The base ring must be a field") + #Check if the base ring is the rationnal field + if not base_ring != QQ: + raise NotImplementedError("base ring other than Q are not yet supported for quasimodular forms ring") self.__group = group self.__base_ring = base_ring From 6057a6f75afde0bf53ac18f180030e297ad31979 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 6 Aug 2021 09:25:48 -0400 Subject: [PATCH 061/355] fix failing doctests, pyflakes, block, tiple colon --- src/sage/modular/modform/ring.py | 2 +- src/sage/modular/quasimodform/element.py | 6 ++---- src/sage/modular/quasimodform/ring.py | 16 +++++----------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index ed76740b4e2..413c06fea18 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -351,7 +351,7 @@ def polynomial_ring(self, names, gens=None): def _monomials_of_weight(self, weight, gens, poly_parent): r""" - Returns the dictionnary of all homogeneous monomials of weight ``weight`` given by + Return the dictionnary of all homogeneous monomials of weight ``weight`` given by products of generators. The keys of the dictionnary are the monomials living in `poly_parent` and the values are the modular forms associated to these polynomials. diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 22cd2aa657a..5b8242e036d 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -17,9 +17,7 @@ # **************************************************************************** from sage.modular.modform.eis_series import eisenstein_series_qexp -from sage.modular.modform.element import GradedModularFormElement, ModularFormElement - -from sage.rings.all import Integer, QQ, ZZ +from sage.modular.modform.element import GradedModularFormElement from sage.structure.element import ModuleElement from sage.structure.richcmp import richcmp, op_NE, op_EQ @@ -107,7 +105,7 @@ def q_expansion(self, prec=6): An alias of this method is ``qexp``. - EXAMPLES::: + EXAMPLES:: sage: QM = QuasiModularForms() sage: E2 = QM.0 diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index ccb59e36658..6c9eaf26c95 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -137,9 +137,6 @@ def __init__(self, group=1, base_ring=QQ, name='E2'): Modular Group SL(2,Z) sage: M.base_ring() Rational Field - sage: M = QuasiModularForms(1, Integers(5)) - sage: M.base_ring() - Ring of integers modulo 5 sage: QuasiModularForms(2) Traceback (most recent call last): ... @@ -148,9 +145,6 @@ def __init__(self, group=1, base_ring=QQ, name='E2'): Traceback (most recent call last): ... ValueError: Group (=Ring of integers modulo 5) should be a congruence subgroup - sage: M2 = QuasiModularForms(1, GF(7)) - sage: M == M2 - False :: @@ -169,7 +163,7 @@ def __init__(self, group=1, base_ring=QQ, name='E2'): raise NotImplementedError("space of quasimodular forms are only implemented for the full modular group") #Check if the base ring is the rationnal field - if not base_ring != QQ: + if base_ring != QQ: raise NotImplementedError("base ring other than Q are not yet supported for quasimodular forms ring") self.__group = group @@ -208,8 +202,10 @@ def base_ring(self): sage: QuasiModularForms(1).base_ring() Rational Field - sage: QuasiModularForms(1, base_ring=Integers(5)).base_ring() - Ring of integers modulo 5 + sage: QuasiModularForms(1, GF(5)) + Traceback (most recent call last): + ... + NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring """ return self.__base_ring @@ -264,8 +260,6 @@ def _repr_(self): sage: QuasiModularForms(1)._repr_() 'Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field' - sage: QuasiModularForms(1, base_ring=Integers(13))._repr_() - 'Ring of Quasimodular Forms for Modular Group SL(2,Z) over Ring of integers modulo 13' """ return "Ring of Quasimodular Forms for %s over %s" % (self.group(), self.base_ring()) From e37e209749d0063a46751c8a13cf7fe4a09af0a8 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 7 Aug 2021 19:39:14 +0200 Subject: [PATCH 062/355] fix bug with noncommutative basering, more exact series in mul --- .../data_structures/coefficient_stream.py | 4 +- src/sage/rings/lazy_laurent_series.py | 100 ++++++++++++++---- src/sage/rings/lazy_laurent_series_ring.py | 2 +- 3 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index acd739aaf9a..cb97395ca74 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -1114,11 +1114,11 @@ def iterate_coefficients(self): n += 1 -class CoefficientStream_cauchy_product(CoefficientStream_binary_commutative): +class CoefficientStream_cauchy_product(CoefficientStream_binary): """ Operator for multiplication of two coefficient streams. - We are assuming commutativity of the coefficient ring here. + We are not assuming commutativity of the coefficient ring here. INPUT: diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 4d815b375b9..5294939ae72 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1125,7 +1125,7 @@ def _rmul_(self, scalar): sage: 2 * M == M * 2 True - We take care of noncommutativity of the base ring:: + We take care of noncommutative base rings:: sage: M = MatrixSpace(ZZ, 2) sage: L. = LazyTaylorSeriesRing(M) @@ -1147,9 +1147,12 @@ def _rmul_(self, scalar): c = self._coeff_stream._constant * scalar v = self._coeff_stream.valuation() initial_coefficients = [v * scalar for v in self._coeff_stream._initial_coefficients] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - valuation=v, constant=c, - degree=self._coeff_stream._degree)) + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, + valuation=v, constant=c, + degree=self._coeff_stream._degree) + return P.element_class(P, coeff_stream) + if P.base_ring().is_commutative(): + return P.element_class(P, CoefficientStream_lmul(self._coeff_stream, scalar)) return P.element_class(P, CoefficientStream_rmul(self._coeff_stream, scalar)) @@ -1246,14 +1249,11 @@ def _mul_(self, other): sage: L. = LazyLaurentSeriesRing(ZZ) sage: (1 - z)*(1 - z) 1 - 2*z + z^2 - sage: (1 - z)*(1 - z)*(1 - z) - 1 - 3*z + 3*z^2 - z^3 - sage: M = L(lambda n: n) - sage: M + sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... - sage: N = M * (1 - M) - sage: N + sage: N = M * (1 - M); N z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ... + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... @@ -1275,6 +1275,41 @@ def _mul_(self, other): sage: (1 - x)*(1 - y)*(1 - z) 1 + (-x-y-z) + (x*y+x*z+y*z) + (-x*y*z) + We take care of noncommutative base rings:: + + sage: M = MatrixSpace(ZZ, 2) + sage: L. = LazyTaylorSeriesRing(M) + sage: m = M([[1, 1],[0, 1]]) + sage: n = M([[1, 0],[1, 1]]) + sage: a = 1/(1-m*t) + sage: b = 1 + n*t + sage: (b*a-a*b)[20] + [-19 0] + [ 0 19] + + Multiplication of series with eventually constant + coefficients may yield another such series:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: var("a b c d e u v w") + (a, b, c, d, e, u, v, w) + sage: s = a/z^2 + b*z + c*z^2 + d*z^3 + e*z^4 + sage: t = L([u, v], constant=w, valuation=-1) + sage: s1 = s.approximate_series(44) + sage: t1 = t.approximate_series(44) + sage: s1 * t1 - (s * t).approximate_series(42) + O(z^42) + + Noncommutative:: + + sage: M = MatrixSpace(ZZ, 2) + sage: L. = LazyTaylorSeriesRing(M) + sage: a = L([m], degree=1) + sage: b = n*~(1-t) + sage: (a*b)[0] + [2 1] + [1 1] + """ P = self.parent() left = self._coeff_stream @@ -1289,17 +1324,38 @@ def _mul_(self, other): # exact, and one has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 - # for the moment we only consider the case where bothe have eventually 0 coefficients - if (isinstance(left, CoefficientStream_exact) and not left._constant - and isinstance(right, CoefficientStream_exact) and not right._constant): + if (isinstance(left, CoefficientStream_exact) + and isinstance(right, CoefficientStream_exact) + and not (left._constant and right._constant)): il = left._initial_coefficients ir = right._initial_coefficients initial_coefficients = [sum(il[k]*ir[n-k] for k in range(max(n-len(ir)+1, 0), min(len(il)-1, n) + 1)) - for n in range(len(il) + len(ir))] - v = left.valuation() + right.valuation() - coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=v) + for n in range(len(il) + len(ir) - 1)] + lv = left.valuation() + rv = right.valuation() + # (a x^d q)/(1-x) has constant a q(1), and the initial + # values are the cumulative sums of the coeffcients of q + if right._constant: + d = right._degree + c = left._constant # this is zero + # left._constant must be 0 and thus len(il) >= 1 + for k in range(len(il)-1): + c += il[k] * right._constant + initial_coefficients[d - rv + k] += c + c += il[-1] * right._constant + elif left._constant: + d = left._degree + c = right._constant # this is zero + # left._constant must be 0 and thus len(il) >= 1 + for k in range(len(ir)): + c += left._constant * ir[k] + initial_coefficients[d - lv + k] += c + c += left._constant * ir[-1] + else: + c = left._constant # this is zero + coeff_stream = CoefficientStream_exact(initial_coefficients, P._sparse, valuation=lv + rv, constant=c) return P.element_class(P, coeff_stream) return P.element_class(P, CoefficientStream_cauchy_product(left, right)) @@ -1346,22 +1402,22 @@ def __invert__(self): if isinstance(coeff_stream, CoefficientStream_exact): initial_coefficients = coeff_stream._initial_coefficients if not initial_coefficients: - i = 1 / coeff_stream._constant - v = -coeff_stream.valuation() + i = ~ coeff_stream._constant + v = - coeff_stream.valuation() c = P._coeff_ring.zero() coeff_stream = CoefficientStream_exact((i, -i), P._sparse, valuation=v, constant=c) return P.element_class(P, coeff_stream) if len(initial_coefficients) == 1: - i = 1 / initial_coefficients[0] - v = -coeff_stream.valuation() + i = ~ initial_coefficients[0] + v = - coeff_stream.valuation() c = P._coeff_ring.zero() coeff_stream = CoefficientStream_exact((i,), P._sparse, valuation=v, constant=c) return P.element_class(P, coeff_stream) if len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]): - v = -coeff_stream.valuation() - c = 1 / initial_coefficients[0] + v = - coeff_stream.valuation() + c = ~ initial_coefficients[0] coeff_stream = CoefficientStream_exact((), P._sparse, valuation=v, constant=c) return P.element_class(P, coeff_stream) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index ae1e5d9c4a0..98c45866484 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -828,9 +828,9 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if isinstance(constant, (tuple, list)): constant, degree = constant if constant is not None: - constant = R(constant) if len(self.variable_names()) > 1 and constant: raise ValueError(f"constant must be zero for multivariate Taylor series") + constant = BR(constant) if x in R: if not x and not constant: coeff_stream = CoefficientStream_zero(self._sparse) From 1e3f64daa118186f358db9702e4960128ff28bcb Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Sun, 8 Aug 2021 01:13:49 +0530 Subject: [PATCH 063/355] Shortened the code for the old series, completed all the trigonometric functions. --- src/sage/rings/lazy_laurent_series.py | 166 ++++++++++++++------------ 1 file changed, 89 insertions(+), 77 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index bbd9972cdb2..5a6a971abb1 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1069,7 +1069,7 @@ class LazySpecialFunctions(): sage: L. = LazyLaurentSeriesRing(RR) sage: arccos(z) - 3.14159265358979 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) """ def sin(self): @@ -1096,14 +1096,7 @@ def sin(self): from sage.functions.other import factorial P = self.parent() - def coeff(n): - if n % 2 == 0: - return ZZ.zero() - elif n % 4 == 1: - return 1/factorial(n) - return -1/factorial(n) - sin = P(coeff, 0) - return sin(self) + return P(lambda n: (n % 2)/factorial(n) if n % 4 == 1 else -(n % 2)/factorial(n), 0)(self) def cos(self): r""" @@ -1129,14 +1122,7 @@ def cos(self): from sage.functions.other import factorial P = self.parent() - def coeff(n): - if n % 2: - return ZZ.zero() - elif n % 4 == 0: - return 1/factorial(n) - return -1/factorial(n) - cos = P(coeff, 0) - return cos(self) + return P(lambda n: 1/factorial(n) if n % 4 == 0 else (n % 2 - 1)/factorial(n), 0)(self) def arcsin(self): r""" @@ -1166,12 +1152,7 @@ def arcsin(self): from sage.functions.other import factorial P = self.parent() - def coeff(n): - if n % 2: - return factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) - return ZZ.zero() - arcsin = P(coeff, 0) - return arcsin(self) + return P(lambda n: factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) if n % 2 else ZZ.zero(), 0)(self) def arccos(self): r""" @@ -1181,29 +1162,22 @@ def arccos(self): sage: L. = LazyLaurentSeriesRing(RR) sage: arccos(z) - 3.14159265358979 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) sage: arccos(z^2) - 3.14159265358979 + 0.000000000000000*z - 1.00000000000000*z^2 - 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 - 0.166666666666667*z^6 + O(1.00000000000000*z^7) + 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 - 0.166666666666667*z^6 + O(1.00000000000000*z^7) sage: arccos(z + z^2) - 3.14159265358979 - 1.00000000000000*z - 1.00000000000000*z^2 - 0.166666666666667*z^3 - 0.500000000000000*z^4 - 0.575000000000000*z^5 - 0.541666666666667*z^6 + O(1.00000000000000*z^7) + 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 - 0.166666666666667*z^3 - 0.500000000000000*z^4 - 0.575000000000000*z^5 - 0.541666666666667*z^6 + O(1.00000000000000*z^7) sage: arccos(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series """ - from sage.functions.other import factorial from sage.symbolic.constants import pi + from sage.rings.lazy_laurent_series import LazySpecialFunctions P = self.parent() - def coeff(n): - if n == 0: - return pi - if n % 2: - return -1 * factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) - return ZZ.zero() - arccos = P(coeff, 0) - return arccos(self) + return P(pi/2) - LazySpecialFunctions.arcsin(self) def sinh(self): r""" @@ -1230,10 +1204,7 @@ def sinh(self): from sage.functions.other import factorial P = self.parent() - def coeff(n): - return 1/factorial(n) if n % 2 else ZZ.zero() - sinh = P(coeff, 0) - return sinh(self) + return P(lambda n: 1/factorial(n) if n % 2 else ZZ.zero(), 0)(self) def cosh(self): r""" @@ -1260,14 +1231,7 @@ def cosh(self): from sage.functions.other import factorial P = self.parent() - def coeff(n): - if n == 0: - return 1 - if n % 2: - return ZZ.zero() - return 1/factorial(n) - cosh = P(coeff, 0) - return cosh(self) + return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) def tan(self): r""" @@ -1290,20 +1254,9 @@ def tan(self): ValueError: can only compose with a positive valuation series """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - from sage.rings.rational_field import QQ + from sage.rings.lazy_laurent_series import LazySpecialFunctions - P = self.parent() - def coeff(n): - if n % 2: - a = QQ((bernoulli(n + 1)) * ((-4) ** ((n + 1)/2))) - b = QQ(a * QQ((1 - (4 ** ((n + 1)/2))))) - c = QQ(b / (factorial(n + 1))) - return c - return ZZ.zero() - tan = P(coeff, 0) - return tan(self) + return LazySpecialFunctions.sin(self)/LazySpecialFunctions.cos(self) def arctan(self): r""" @@ -1327,14 +1280,7 @@ def arctan(self): """ P = self.parent() - def coeff(n): - if n % 2 == 0: - return ZZ.zero() - elif n % 4 == 1: - return 1/n - return -1/n - arctan = P(coeff, 0) - return arctan(self) + return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) def tanh(self): r""" @@ -1366,16 +1312,82 @@ def tanh(self): from sage.rings.rational_field import QQ P = self.parent() - def coeff(n): - if n % 2: - a = QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) - b = QQ(a * QQ((-1 + (4 ** ((n + 1)/2))))) - c = QQ(b / (factorial(n + 1))) - return c - return ZZ.zero() - tanh = P(coeff, 0) - return tanh(self) + return P(lambda n: (QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) * (-1 + (4 ** ((n + 1)/2))))/factorial(n + 1) if n % 2 else ZZ.zero(), 0)(self) + + def csc(self): + r""" + Return the cosecant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csc(z) + z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) + sage: csc(0) + Infinity + sage: csc(z^2) + z^-2 + 1/6*z^2 + O(z^5) + sage: csc(z + z^2) + z^-1 - 1 + 7/6*z - 5/6*z^2 + 367/360*z^3 - 113/120*z^4 + 16033/15120*z^5 + O(z^6) + sage: csc(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return ~LazySpecialFunctions.sin(self) + + def sec(self): + r""" + Return the secant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sec(z) + 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) + sage: sec(z^2) + 1 + 1/2*z^4 + O(z^7) + sage: sec(z + z^2) + 1 + 1/2*z^2 + z^3 + 17/24*z^4 + 5/6*z^5 + 961/720*z^6 + O(z^7) + sage: sec(0) + 1 + sage: sec(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return ~LazySpecialFunctions.cos(self) + + def cot(self): + r""" + Return the cotangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cot(z) + z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) + sage: cot(z^2) + z^-2 - 1/3*z^2 + O(z^5) + sage: cot(z + z^2) + z^-1 - 1 + 2/3*z - 4/3*z^2 + 44/45*z^3 - 16/15*z^4 + 176/189*z^5 + O(z^6) + sage: cot(0) + Infinity + sage: cot(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + return ~LazySpecialFunctions.tan(self) class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): r""" From 7dd2cdb86f2cfdc42c5aa60403b86a0af606d82b Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Sun, 8 Aug 2021 01:29:27 +0530 Subject: [PATCH 064/355] Formatting --- src/sage/rings/lazy_laurent_series.py | 42 +++++++++++++++------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 5a6a971abb1..1d2f420aedb 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -109,6 +109,7 @@ CoefficientStream_uninitialized ) + class LazySequenceElement(ModuleElement): r""" An element of a lazy series. @@ -129,6 +130,7 @@ class LazySequenceElement(ModuleElement): sage: f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) """ + def __init__(self, parent, coeff_stream): """ Initialize the series. @@ -599,6 +601,7 @@ class LazySequencesModuleElement(LazySequenceElement): sage: R[:10] [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] """ + def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -640,7 +643,7 @@ def _add_(self, other): left = self._coeff_stream right = other._coeff_stream if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): + and isinstance(right, CoefficientStream_exact)): approximate_valuation = min(left.valuation(), right.valuation()) degree = max(left._degree, right._degree) initial_coefficients = [left[i] + right[i] for i in range(approximate_valuation, degree)] @@ -874,6 +877,7 @@ class LazyCauchyProductSeries(RingElement): We are assuming that :meth:`polynomial` """ + def __init__(self, parent): """ Initialize. @@ -934,7 +938,7 @@ def _mul_(self, other): # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 # for the moment we only consider the case where bothe have eventually 0 coefficients if (isinstance(left, CoefficientStream_exact) and not left._constant - and isinstance(right, CoefficientStream_exact) and not right._constant): + and isinstance(right, CoefficientStream_exact) and not right._constant): il = left._initial_coefficients ir = right._initial_coefficients initial_coefficients = [sum(il[k]*ir[n-k] @@ -1039,12 +1043,12 @@ class LazySpecialFunctions(): sage: tan(z) z + 1/3*z^3 + 2/15*z^5 + O(z^7) - + The arcsin of a series can be found. :: sage: arcsin(z) z + 1/6*z^3 + 3/40*z^5 + O(z^7) - + The sinh of a series can be found. :: sage: sinh(z) @@ -1054,17 +1058,17 @@ class LazySpecialFunctions(): sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - + The arctangent of a series can be found. :: sage: arctan(z) z - 1/3*z^3 + 1/5*z^5 + O(z^7) - + The tanh of a series can be found. :: sage: tanh(z) z - 1/3*z^3 + 2/15*z^5 + O(z^7) - + The arccosine of a series can be found. :: sage: L. = LazyLaurentSeriesRing(RR) @@ -1072,6 +1076,7 @@ class LazySpecialFunctions(): 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) """ + def sin(self): r""" Return the sine of ``self``. @@ -1097,7 +1102,7 @@ def sin(self): P = self.parent() return P(lambda n: (n % 2)/factorial(n) if n % 4 == 1 else -(n % 2)/factorial(n), 0)(self) - + def cos(self): r""" Return the cosine of ``self``. @@ -1153,7 +1158,7 @@ def arcsin(self): P = self.parent() return P(lambda n: factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) if n % 2 else ZZ.zero(), 0)(self) - + def arccos(self): r""" Return the arccos of ``self``. @@ -1178,7 +1183,7 @@ def arccos(self): P = self.parent() return P(pi/2) - LazySpecialFunctions.arcsin(self) - + def sinh(self): r""" Return the sinh of ``self``. @@ -1205,7 +1210,7 @@ def sinh(self): P = self.parent() return P(lambda n: 1/factorial(n) if n % 2 else ZZ.zero(), 0)(self) - + def cosh(self): r""" Return the cosh of ``self``. @@ -1232,7 +1237,7 @@ def cosh(self): P = self.parent() return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) - + def tan(self): r""" Return the tangent of ``self``. @@ -1257,7 +1262,7 @@ def tan(self): from sage.rings.lazy_laurent_series import LazySpecialFunctions return LazySpecialFunctions.sin(self)/LazySpecialFunctions.cos(self) - + def arctan(self): r""" Return the arctangent of ``self``. @@ -1281,7 +1286,7 @@ def arctan(self): """ P = self.parent() return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) - + def tanh(self): r""" Return the tanh of ``self``. @@ -1338,7 +1343,7 @@ def csc(self): from sage.rings.lazy_laurent_series import LazySpecialFunctions return ~LazySpecialFunctions.sin(self) - + def sec(self): r""" Return the secant of ``self``. @@ -1363,7 +1368,7 @@ def sec(self): from sage.rings.lazy_laurent_series import LazySpecialFunctions return ~LazySpecialFunctions.cos(self) - + def cot(self): r""" Return the cotangent of ``self``. @@ -1389,6 +1394,7 @@ def cot(self): return ~LazySpecialFunctions.tan(self) + class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): r""" A Laurent series where the coefficients are computed lazily. @@ -1889,7 +1895,7 @@ def __pow__(self, n): cs = self._coeff_stream if (isinstance(cs, CoefficientStream_exact) and not cs._constant and n in ZZ - and (n > 0 or len(cs._initial_coefficients) == 1)): + and (n > 0 or len(cs._initial_coefficients) == 1)): P = self.parent() z = P._laurent_poly_ring.gen() ret = cs.polynomial_part(z) ** ZZ(n) @@ -2048,7 +2054,7 @@ def _format_series(self, formatter, format_strings=False): if format_strings: strformat = formatter else: - strformat = lambda x: x + def strformat(x): return x if isinstance(cs, CoefficientStream_exact): poly = cs.polynomial_part(z) From 11f59f9409dd64a3377d7a9f752501ae2508ba3a Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Mon, 9 Aug 2021 01:20:04 +0530 Subject: [PATCH 065/355] Added all trig, inverse trig, hyperbolic functions, and exponential functions. --- src/sage/rings/lazy_laurent_series.py | 84 ++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 1d2f420aedb..d12f18bc3d8 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1028,9 +1028,14 @@ class LazySpecialFunctions(): EXAMPLES: - The sine of a series can be found. :: + The exponential series can be found. :: sage: L. = LazyLaurentSeriesRing(QQ) + sage: exp(z) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + + The sine of a series can be found. :: + sage: sin(z) z - 1/6*z^3 + 1/120*z^5 + O(z^7) @@ -1077,6 +1082,31 @@ class LazySpecialFunctions(): """ + def exp(self): + r""" + Return the exponential series of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: exp(z) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: exp(z^2) + 1 + z^2 + 1/2*z^4 + 1/6*z^6 + O(z^7) + sage: exp(z + z^2) + 1 + z + 3/2*z^2 + 7/6*z^3 + 25/24*z^4 + 27/40*z^5 + 331/720*z^6 + O(z^7) + sage: exp(0) + 1 + sage: exp(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + """ + from sage.functions.other import factorial + + P = self.parent() + return P(lambda n: 1/factorial(n), 0)(self) + def sin(self): r""" Return the sine of ``self``. @@ -1394,6 +1424,58 @@ def cot(self): return ~LazySpecialFunctions.tan(self) + def arsh(self): + r""" + Return the inverse of the hyperbolic sine of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: LazySpecialFunctions.arsh(z) + z - 1/6*z^3 + 3/40*z^5 + O(z^7) + sage: LazySpecialFunctions.arsh(z^2) + z^2 - 1/6*z^6 + O(z^7) + sage: LazySpecialFunctions.arsh(z + z^2) + z + z^2 - 1/6*z^3 - 1/2*z^4 - 17/40*z^5 + 5/24*z^6 + O(z^7) + sage: LazySpecialFunctions.arsh(L(0)) + 0 + sage: LazySpecialFunctions.arsh(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.other import factorial + + P = self.parent() + return P(lambda n: ZZ.zero() if n % 2 == 0 else (((-1) ** ((n - 1)/2)) * factorial(n - 1))/(4 ** ((n - 1)/2) * (factorial((n - 1)/2) ** 2) * n), 0)(self) + + def artanh(self): + r""" + Return the inverse of the hyperbolic tangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: LazySpecialFunctions.artanh(z) + z + 1/3*z^3 + 1/5*z^5 + O(z^7) + sage: LazySpecialFunctions.artanh(z^2) + z^2 + 1/3*z^6 + O(z^7) + sage: LazySpecialFunctions.artanh(L(0)) + 0 + sage: LazySpecialFunctions.artanh(z + z^2) + z + z^2 + 1/3*z^3 + z^4 + 6/5*z^5 + 4/3*z^6 + O(z^7) + sage: LazySpecialFunctions.artanh(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + P = self.parent() + return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) + class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): r""" From cd9da2a883ba745ab812cab7d6ada5bb71e6da66 Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Mon, 9 Aug 2021 01:59:37 +0530 Subject: [PATCH 066/355] Added hypergeometric function. --- src/sage/rings/lazy_laurent_series.py | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index d12f18bc3d8..9d284aa0b2a 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1476,6 +1476,65 @@ def artanh(self): P = self.parent() return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) + def arccot(self): + r""" + Return the arctangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(RR) + sage: arccot(z) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) + sage: arccot(z^2) + 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) + sage: arccot(z + z^2) + 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) + sage: arctan(0) + 0 + sage: arctan(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + + from sage.symbolic.constants import pi + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + P = self.parent() + return P(pi/2) - LazySpecialFunctions.arctan(self) + + def hypergeometric(self, a, b, c): + r""" + Return the `{}_{p}F_{q}`-hypergeometric function + `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: LazySpecialFunctions.hypergeometric(z, 1, 2, 2) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, 2, 2, 2) + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, 2, 3, 2) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, 2, 3, 4) + 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) + + """ + from sage.functions.other import factorial + + def pochhammer(q, n): + if n: + c = 1 + for i in range(n): + c *= (q + i) + return c + return 1 + P = self.parent() + return P(lambda n: (pochhammer(a, n) * pochhammer(b, n))/(pochhammer(c, n) * factorial(n)), 0)(self) + class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): r""" From d379b141bf1814aa5858ad9dbf680b509b06d480 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 8 Aug 2021 22:37:04 +0200 Subject: [PATCH 067/355] take care of categories, make pow and div generic and fix bugs --- src/sage/rings/lazy_laurent_series.py | 282 ++++++++++----------- src/sage/rings/lazy_laurent_series_ring.py | 109 ++++++-- 2 files changed, 226 insertions(+), 165 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 95a2ff01901..81b96f9ddf1 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1121,8 +1121,8 @@ def _rmul_(self, scalar): sage: n = M([[1, 0],[1, 1]]) sage: a = L(lambda k: n^k) sage: (m*a - a*m)[3] - [-3 0] - [ 0 3] + [ 3 0] + [ 0 -3] """ P = self.parent() @@ -1449,6 +1449,142 @@ def __invert__(self): return P.element_class(P, coeff_stream._series) return P.element_class(P, CoefficientStream_cauchy_inverse(coeff_stream)) + def _div_(self, other): + r""" + Return ``self`` divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be divided:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: z/(1 - z) + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + Lazy Laurent series that have a sparse implementation can be divided:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = L(lambda n: 1); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + Lazy Laurent series that are known to be exact can be divided:: + + M = z^2 + 2*z + 1 + N = z + 1 + O = M / N; O + z + 1 + + An example over the ring of symmetric functions:: + + sage: e = SymmetricFunctions(QQ).e() + sage: R. = LazyLaurentSeriesRing(e) + sage: 1 / (1 - e[1]*z) + e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) + """ + if isinstance(other._coeff_stream, CoefficientStream_zero): + raise ZeroDivisionError("cannot divide by 0") + + P = self.parent() + left = self._coeff_stream + if isinstance(left, CoefficientStream_zero): + return P.zero() + right = other._coeff_stream + if (isinstance(left, CoefficientStream_exact) + and isinstance(right, CoefficientStream_exact)): + if not left._constant and not right._constant: + R = P._laurent_poly_ring + z = R.gen() + pl = self.finite_part() + pr = other.finite_part() + try: + ret = pl / pr + ret = P._laurent_poly_ring(ret) + return P(ret) + except (TypeError, ValueError, NotImplementedError): + # We cannot divide the polynomials, so the result must be a series + pass + + return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) + + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: (1 - z)^-1 + 1 + z + z^2 + O(z^3) + sage: (1 - z)^0 + 1 + sage: (1 - z)^3 + 1 - 3*z + 3*z^2 - z^3 + sage: (1 - z)^-3 + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + We can create a really large power of a monomial, even with + the dense implementation:: + + sage: z^1000000 + z^1000000 + + Lazy Laurent series that have a sparse implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + Lazy Laurent series that are known to be exact can be raised + to the power ``n``:: + + sage: z^2 + z^2 + sage: (1 - z)^2 + 1 - 2*z + z^2 + sage: (1 + z)^2 + 1 + 2*z + z^2 + """ + if n == 0: + return self.parent().one() + + cs = self._coeff_stream + if (isinstance(cs, CoefficientStream_exact) + and not cs._constant and n in ZZ + and (n > 0 or len(cs._initial_coefficients) == 1)): + P = self.parent() + return P(self.finite_part() ** ZZ(n)) + + return generic_power(self, n) + class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" @@ -1827,148 +1963,6 @@ def revert(self): else: return f / z**(1 - self._coeff_stream._approximate_valuation) - def _div_(self, other): - r""" - Return ``self`` divided by ``other``. - - INPUT: - - - ``other`` -- nonzero series - - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be divided:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: z/(1 - z) - z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - - Lazy Laurent series that have a sparse implementation can be divided:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - - Lazy Laurent series that are known to be exact can be divided:: - - M = z^2 + 2*z + 1 - N = z + 1 - O = M / N; O - z + 1 - - An example over the ring of symmetric functions:: - - sage: e = SymmetricFunctions(QQ).e() - sage: R. = LazyLaurentSeriesRing(e) - sage: 1 / (1 - e[1]*z) - e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 - + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) - """ - if isinstance(other._coeff_stream, CoefficientStream_zero): - raise ZeroDivisionError("cannot divide by 0") - - P = self.parent() - left = self._coeff_stream - if isinstance(left, CoefficientStream_zero): - return P.zero() - right = other._coeff_stream - if (isinstance(left, CoefficientStream_exact) - and isinstance(right, CoefficientStream_exact)): - if not left._constant and not right._constant: - R = P._laurent_poly_ring - z = R.gen() - pl = left.polynomial_part(z) - pr = right.polynomial_part(z) - try: - ret = pl / pr - ret = P._laurent_poly_ring(ret) - initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, valuation=ret.valuation(), constant=left._constant)) - except (TypeError, ValueError, NotImplementedError): - # We cannot divide the polynomials, so the result must be a series - pass - - return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - - def __pow__(self, n): - """ - Return the ``n``-th power of the series. - - INPUT: - - - ``n`` -- integer; the power to which to raise the series - - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: (1 - z)^-1 - 1 + z + z^2 + O(z^3) - sage: (1 - z)^0 - 1 - sage: (1 - z)^3 - 1 - 3*z + 3*z^2 - z^3 - sage: (1 - z)^-3 - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - We can create a really large power of a monomial, even with - the dense implementation:: - - sage: z^1000000 - z^1000000 - - Lazy Laurent series that have a sparse implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - Lazy Laurent series that are known to be exact can be raised - to the power ``n``:: - - sage: z^2 - z^2 - sage: (1 - z)^2 - 1 - 2*z + z^2 - sage: (1 + z)^2 - 1 + 2*z + z^2 - """ - if n == 0: - return self.parent().one() - - cs = self._coeff_stream - if (isinstance(cs, CoefficientStream_exact) - and not cs._constant and n in ZZ - and (n > 0 or len(cs._initial_coefficients) == 1)): - P = self.parent() - z = P._laurent_poly_ring.gen() - ret = cs.polynomial_part(z) ** ZZ(n) - val = ret.valuation() - deg = ret.degree() + 1 - initial_coefficients = [ret[i] for i in range(val, deg)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, self._coeff_stream._constant, deg, val)) - - return generic_power(self, n) - def approximate_series(self, prec, name=None): """ Return the Laurent series with absolute precision ``prec`` approximated diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index 99ade6fbd17..10e36b4b112 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -21,15 +21,17 @@ from sage.structure.parent import Parent from sage.categories.algebras import Algebras +from sage.categories.rings import Rings from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields -from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields +from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields, CompleteDiscreteValuationRings from .laurent_series_ring_element import LaurentSeries from .ring import CommutativeRing from sage.misc.cachefunc import cached_method +from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -342,6 +344,20 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: g z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) + Finally, ``x`` can be a Laurent polynomial:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: p = x^-2 + 3*x^3 + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L(p) + x^-2 + 3*x^3 + + sage: L(p, valuation=0) + 1 + 3*x^5 + + sage: L(p, valuation=1) + x + 3*x^6 + TESTS:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') @@ -374,7 +390,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if not x and not constant: coeff_stream = CoefficientStream_zero(self._sparse) else: - if x and valuation: + if x and valuation is not None: x = x.shift(valuation - x.valuation()) if degree is None and not x: if valuation is None: @@ -598,7 +614,7 @@ def __init__(self, base_ring, names, sparse=False, category=None): TESTS:: sage: L = LazyTaylorSeriesRing(ZZ, 't') - sage: TestSuite(L).run(skip='_test_elements') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) """ self._sparse = sparse if len(names) == 1: @@ -606,8 +622,20 @@ def __init__(self, base_ring, names, sparse=False, category=None): else: self._coeff_ring = PolynomialRing(base_ring, names) self._laurent_poly_ring = PolynomialRing(base_ring, names) + category = Algebras(base_ring.category()) + if base_ring in Fields(): + category &= CompleteDiscreteValuationRings() + elif base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + + if base_ring.is_zero(): + category = category.Finite() + else: + category = category.Infinite() Parent.__init__(self, base=base_ring, names=names, - category=MagmasAndAdditiveMagmas().or_subcategory(category)) + category=category) def _repr_(self): """ @@ -729,17 +757,17 @@ def _coerce_map_from_(self, S): return True R = self._laurent_poly_ring - if R.has_coerce_map_from(S): - def make_series_from(poly): - p_dict = poly.homogeneous_components() - v = min(p_dict.keys()) - d = max(p_dict.keys()) - p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] - coeff_stream = CoefficientStream_exact(p_list, self._sparse, valuation=v) - return self.element_class(self, coeff_stream) - return SetMorphism(Hom(S, self, Sets()), make_series_from) + return R.has_coerce_map_from(S) - return False + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): """ @@ -802,6 +830,23 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No Add a method to change the sparse/dense implementation. + Finally, ``x`` can be a polynomial:: + + sage: P. = QQ[] + sage: p = x + 3*x^2 + x^5 + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(p) + x + 3*x^2 + x^5 + + sage: L(p, valuation=0) + 1 + 3*x + x^4 + + sage: P. = QQ[] + sage: p = x + y^2 + x*y + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(p) + x + (x*y+y^2) + TESTS:: sage: L. = LazyTaylorSeriesRing(ZZ) @@ -829,10 +874,11 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No ValueError: coefficients must be homogeneous polynomials of the correct degree """ - if valuation is None: - valuation = 0 - if valuation < 0: - raise ValueError("the valuation of a Taylor series must be positive") + if valuation is not None: + if valuation < 0: + raise ValueError("the valuation of a Taylor series must be positive") + if len(self.variable_names()) > 1: + raise ValueError(f"valuation must not be specified for multivariate Taylor series") R = self._laurent_poly_ring BR = self.base_ring() @@ -866,6 +912,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No v = x.valuation() d = x.degree() p_list = [x[i] for i in range(v, d + 1)] + if valuation is not None: + v = valuation else: p_dict = x.homogeneous_components() v = min(p_dict.keys()) @@ -873,7 +921,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] coeff_stream = CoefficientStream_exact(p_list, self._sparse, - valuation=valuation, + valuation=v, constant=constant, degree=degree) return self.element_class(self, coeff_stream) @@ -884,6 +932,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") if callable(x): + if valuation is None: + valuation = 0 if degree is not None: if constant is None: constant = ZZ.zero() @@ -993,7 +1043,7 @@ def __init__(self, base_ring, names, sparse=False, category=None): TESTS:: sage: L = LazyDirichletSeriesRing(ZZ, 't') - sage: TestSuite(L).run(skip='_test_elements') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) """ if base_ring.characteristic() > 0: raise ValueError("positive characteristic not allowed for Dirichlet series") @@ -1001,8 +1051,15 @@ def __init__(self, base_ring, names, sparse=False, category=None): self._sparse = sparse self._coeff_ring = base_ring self._laurent_poly_ring = SR + + category = Algebras(base_ring.category()) + if base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + category = category.Infinite() Parent.__init__(self, base=base_ring, names=names, - category=MagmasAndAdditiveMagmas().or_subcategory(category)) + category=category) def _repr_(self): """ @@ -1097,6 +1154,16 @@ def _coerce_map_from_(self, S): return False + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None): """ Construct a Dirichlet series from ``x``. From d160b715b4c087b84e36c95885853b654563b8c9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 9 Aug 2021 13:27:18 +0200 Subject: [PATCH 068/355] make div and pow work for Taylor again --- src/sage/rings/lazy_laurent_series.py | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index f4fe7100686..4c59747dc2d 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1532,19 +1532,19 @@ def _div_(self, other): and isinstance(right, CoefficientStream_exact)): if not left._constant and not right._constant: R = P._laurent_poly_ring - pl = left.polynomial_part(R) - pr = right.polynomial_part(R) - # pl = self.finite_part() - # pr = other.finite_part() + # pl = left.polynomial_part(R) + # pr = right.polynomial_part(R) + pl = self.finite_part() + pr = other.finite_part() try: - # ret = pl / pr - # ret = P._laurent_poly_ring(ret) - # return P(ret) ret = pl / pr ret = P._laurent_poly_ring(ret) - initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - valuation=ret.valuation(), constant=left._constant)) + return P(ret) + # ret = pl / pr + # ret = P._laurent_poly_ring(ret) + # initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + # valuation=ret.valuation(), constant=left._constant)) except (TypeError, ValueError, NotImplementedError): # We cannot divide the polynomials, so the result must be a series pass @@ -1611,13 +1611,13 @@ def __pow__(self, n): and not cs._constant and n in ZZ and (n > 0 or len(cs._initial_coefficients) == 1)): P = self.parent() - # return P(self.finite_part() ** ZZ(n)) - ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) - val = ret.valuation() - deg = ret.degree() + 1 - initial_coefficients = [ret[i] for i in range(val, deg)] - return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - constant=cs._constant, degree=deg, valuation=val)) + return P(self.finite_part() ** ZZ(n)) + # ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) + # val = ret.valuation() + # deg = ret.degree() + 1 + # initial_coefficients = [ret[i] for i in range(val, deg)] + # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + # constant=cs._constant, degree=deg, valuation=val)) return generic_power(self, n) From 38c93fb47b74a0117a838f280dad15f58528d7c6 Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Tue, 10 Aug 2021 01:30:59 +0530 Subject: [PATCH 069/355] Added some documentation for reversion, changed the name. --- src/sage/rings/lazy_laurent_series.py | 76 ++++++++++++++++++++------- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 5f0709bb567..51aa3f21749 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2016,7 +2016,7 @@ def cot(self): return ~LazySpecialFunctions.tan(self) - def arsh(self): + def asinh(self): r""" Return the inverse of the hyperbolic sine of ``self``. @@ -2024,15 +2024,15 @@ def arsh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.arsh(z) + sage: LazySpecialFunctions.asinh(z) z - 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: LazySpecialFunctions.arsh(z^2) + sage: LazySpecialFunctions.asinh(z^2) z^2 - 1/6*z^6 + O(z^7) - sage: LazySpecialFunctions.arsh(z + z^2) + sage: LazySpecialFunctions.asinh(z + z^2) z + z^2 - 1/6*z^3 - 1/2*z^4 - 17/40*z^5 + 5/24*z^6 + O(z^7) - sage: LazySpecialFunctions.arsh(L(0)) + sage: LazySpecialFunctions.asinh(L(0)) 0 - sage: LazySpecialFunctions.arsh(1 + z) + sage: LazySpecialFunctions.asinh(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2043,7 +2043,7 @@ def arsh(self): P = self.parent() return P(lambda n: ZZ.zero() if n % 2 == 0 else (((-1) ** ((n - 1)/2)) * factorial(n - 1))/(4 ** ((n - 1)/2) * (factorial((n - 1)/2) ** 2) * n), 0)(self) - def artanh(self): + def atanh(self): r""" Return the inverse of the hyperbolic tangent of ``self``. @@ -2051,15 +2051,15 @@ def artanh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.artanh(z) + sage: LazySpecialFunctions.atanh(z) z + 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: LazySpecialFunctions.artanh(z^2) + sage: LazySpecialFunctions.atanh(z^2) z^2 + 1/3*z^6 + O(z^7) - sage: LazySpecialFunctions.artanh(L(0)) + sage: LazySpecialFunctions.atanh(L(0)) 0 - sage: LazySpecialFunctions.artanh(z + z^2) + sage: LazySpecialFunctions.atanh(z + z^2) z + z^2 + 1/3*z^3 + z^4 + 6/5*z^5 + 4/3*z^6 + O(z^7) - sage: LazySpecialFunctions.artanh(1 + z) + sage: LazySpecialFunctions.atanh(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2081,9 +2081,9 @@ def arccot(self): 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) sage: arccot(z + z^2) 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) - sage: arctan(0) - 0 - sage: arctan(1 + z) + sage: arccot(L(0)) + 1.57079632679490 + sage: arccot(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2473,6 +2473,11 @@ def revert(self): r""" Return the compositional inverse of ``self``. + Given a Laurent Series `f` we want to find a Laurent Series `g` over the same base ring, such + that the composition `(f \circ g)(z) = f(g(z)) = z`. The composition inverse exists if and only if: + - `val(f) = 1' or `f(0) * f(1) != 0`, + + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) @@ -2486,20 +2491,53 @@ def revert(self): z - z^2 + 2*z^3 - 5*z^4 + 14*z^5 - 42*z^6 + 132*z^7 + O(z^8) sage: (2*z).revert() 1/2*z + O(z^8) + sage: s = L(lambda n: 1 if n == 1 else 0) + sage: s.revert() + z + O(z^8) + + We look at some cases where the compositional inverse does not exist.: + + `f = 0`:: + + sage: L(0).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: (z - z).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + `val(f) ! = 1 and f(0) * f(1) = 0`:: + + sage: (z^2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: L(1).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist """ P = self.parent() z = P.gen() - if self._coeff_stream._approximate_valuation == 1: + # g = 0 case + if isinstance(self._coeff_stream, CoefficientStream_zero): + raise ValueError('compositional inverse does not exist') + # val g > 0 and ensure that val(g) == 1 + if self.valuation() >= 0 and self.valuation() != 1: + raise ValueError('compositional inverse does not exist') + if self.valuation() == 1: g = self else: - g = self * z**(1 - self._coeff_stream._approximate_valuation) + g = self * z**(1 - self.valuation()) f = P(None, valuation=1) f.define(z/((g/z)(f))) - if self._coeff_stream._approximate_valuation == 1: + if self.valuation() == 1: return f else: - return f / z**(1 - self._coeff_stream._approximate_valuation) + return f / z**(1 - self.valuation()) def approximate_series(self, prec, name=None): """ From d4643201865bef38481b2cf94c334181184f0e70 Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Tue, 10 Aug 2021 02:25:32 +0530 Subject: [PATCH 070/355] Re-did hypergeometric series and completed inverse hyperbolic functions. --- src/sage/rings/lazy_laurent_series.py | 158 +++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 51aa3f21749..155d39cfb06 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2067,6 +2067,121 @@ def atanh(self): """ P = self.parent() return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) + + def acosh(self): + r""" + Return the inverse of the hyperbolic tangent of ``self``. + + EXAMPLES:: + + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: L. = LazyLaurentSeriesRing(QQ) + sage: LazySpecialFunctions.acosh(z) + 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) + sage: LazySpecialFunctions.acosh(z^2) + 1 + 1/2*z^4 + O(z^7) + sage: LazySpecialFunctions.acosh(z + z^2) + 1 + 1/2*z^2 + z^3 + 13/24*z^4 + 1/6*z^5 + 181/720*z^6 + O(z^7) + sage: LazySpecialFunctions.acosh(L(0)) + 1 + sage: LazySpecialFunctions.acosh(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.other import factorial + + P = self.parent() + return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) + + def asech(self): + r""" + Return the inverse of the hyperbolic secant of ``self``. + + EXAMPLES:: + + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: L. = LazyLaurentSeriesRing(QQ) + sage: LazySpecialFunctions.asech(z) + 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) + sage: LazySpecialFunctions.asech(z^2) + 1 - 1/2*z^4 + O(z^7) + sage: LazySpecialFunctions.asech(z + z^2) + 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) + sage: LazySpecialFunctions.asech(L(0)) + 1 + sage: LazySpecialFunctions.asech(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.other import factorial + from sage.combinat.combinat import euler_number + + P = self.parent() + return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) + + def acosech(self): + r""" + Return the inverse of the hyperbolic cosecant of ``self``. + + EXAMPLES:: + + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: L. = LazyLaurentSeriesRing(QQ) + sage: LazySpecialFunctions.acosech(z) + z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) + sage: LazySpecialFunctions.acosech(z^2) + z^-2 - 1/6*z^2 + O(z^5) + sage: LazySpecialFunctions.acosech(z + z^2) + z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) + sage: LazySpecialFunctions.acosech(L(0)) + Traceback (most recent call last): + ... + ZeroDivisionError: the valuation of the series must be nonnegative + sage: LazySpecialFunctions.acosech(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.other import factorial + from sage.arith.misc import bernoulli + + P = self.parent() + return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) + + def acoth(self): + r""" + Return the inverse of the hyperbolic cotangent of ``self``. + + EXAMPLES:: + + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: L. = LazyLaurentSeriesRing(QQ) + sage: LazySpecialFunctions.acoth(z) + z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) + sage: LazySpecialFunctions.acoth(z^2) + z^-2 + 1/3*z^2 + O(z^5) + sage: LazySpecialFunctions.acoth(z + z^2) + z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) + sage: LazySpecialFunctions.acoth(L(0)) + Traceback (most recent call last): + ... + ZeroDivisionError: the valuation of the series must be nonnegative + sage: LazySpecialFunctions.acoth(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.other import factorial + from sage.arith.misc import bernoulli + + P = self.parent() + return P(lambda n: (2 ** (n + 1) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) def arccot(self): r""" @@ -2096,36 +2211,49 @@ def arccot(self): P = self.parent() return P(pi/2) - LazySpecialFunctions.arctan(self) - def hypergeometric(self, a, b, c): + def hypergeometric(self, a, b): r""" Return the `{}_{p}F_{q}`-hypergeometric function `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. + INPUT:: + + - ``a`` -- the first parameter of the hypergeometric function + - ``b`` -- the second parameter of the hypergeometric function + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.hypergeometric(z, 1, 2, 2) + sage: LazySpecialFunctions.hypergeometric(z, [1, 1], [1]) 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, 2, 2, 2) + sage: LazySpecialFunctions.hypergeometric(z, [1, 2], [1]) 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, 2, 3, 2) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, 2, 3, 4) + sage: LazySpecialFunctions.hypergeometric(z, 1, 1) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [4]) 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, (1, 1), [1, 1]) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) """ from sage.functions.other import factorial - - def pochhammer(q, n): - if n: - c = 1 - for i in range(n): - c *= (q + i) - return c - return 1 + from sage.arith.misc import rising_factorial + if not isinstance(a, (list, tuple)): + a = [a] + if not isinstance(b, (list, tuple)): + b = [b] + def coeff(n, c): + num = 1 + for term in range(len(c)): + num *= rising_factorial(c[term], n) + return num P = self.parent() - return P(lambda n: (pochhammer(a, n) * pochhammer(b, n))/(pochhammer(c, n) * factorial(n)), 0)(self) + return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): From 0c48f4f61f0f7c77575e56a47566de21a0bad431 Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Tue, 10 Aug 2021 02:41:51 +0530 Subject: [PATCH 071/355] Corrected the names. --- src/sage/rings/lazy_laurent_series.py | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 155d39cfb06..8b9278b5866 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2095,23 +2095,23 @@ def acosh(self): P = self.parent() return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - def asech(self): + def sech(self): r""" - Return the inverse of the hyperbolic secant of ``self``. + Return the hyperbolic secant of ``self``. EXAMPLES:: sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.asech(z) + sage: LazySpecialFunctions.sech(z) 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: LazySpecialFunctions.asech(z^2) + sage: LazySpecialFunctions.sech(z^2) 1 - 1/2*z^4 + O(z^7) - sage: LazySpecialFunctions.asech(z + z^2) + sage: LazySpecialFunctions.sech(z + z^2) 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) - sage: LazySpecialFunctions.asech(L(0)) + sage: LazySpecialFunctions.sech(L(0)) 1 - sage: LazySpecialFunctions.asech(1 + z) + sage: LazySpecialFunctions.sech(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2123,25 +2123,25 @@ def asech(self): P = self.parent() return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - def acosech(self): + def cosech(self): r""" - Return the inverse of the hyperbolic cosecant of ``self``. + Return the hyperbolic cosecant of ``self``. EXAMPLES:: sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.acosech(z) + sage: LazySpecialFunctions.cosech(z) z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.acosech(z^2) + sage: LazySpecialFunctions.cosech(z^2) z^-2 - 1/6*z^2 + O(z^5) - sage: LazySpecialFunctions.acosech(z + z^2) + sage: LazySpecialFunctions.cosech(z + z^2) z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.acosech(L(0)) + sage: LazySpecialFunctions.cosech(L(0)) Traceback (most recent call last): ... ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.acosech(1 + z) + sage: LazySpecialFunctions.cosech(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2153,25 +2153,25 @@ def acosech(self): P = self.parent() return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - def acoth(self): + def coth(self): r""" - Return the inverse of the hyperbolic cotangent of ``self``. + Return the hyperbolic cotangent of ``self``. EXAMPLES:: sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.acoth(z) + sage: LazySpecialFunctions.coth(z) z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) - sage: LazySpecialFunctions.acoth(z^2) + sage: LazySpecialFunctions.coth(z^2) z^-2 + 1/3*z^2 + O(z^5) - sage: LazySpecialFunctions.acoth(z + z^2) + sage: LazySpecialFunctions.coth(z + z^2) z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) - sage: LazySpecialFunctions.acoth(L(0)) + sage: LazySpecialFunctions.coth(L(0)) Traceback (most recent call last): ... ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.acoth(1 + z) + sage: LazySpecialFunctions.coth(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series @@ -2181,7 +2181,7 @@ def acoth(self): from sage.arith.misc import bernoulli P = self.parent() - return P(lambda n: (2 ** (n + 1) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) + return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) def arccot(self): r""" From cfa0fba54a78d28a1abd2c6a55d90b88ea1fc344 Mon Sep 17 00:00:00 2001 From: tejasvicsr1 Date: Tue, 10 Aug 2021 23:52:14 +0530 Subject: [PATCH 072/355] Added log, and a^x. --- src/sage/rings/lazy_laurent_series.py | 573 +++++++++++++++----------- 1 file changed, 322 insertions(+), 251 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 8b9278b5866..ee1b9b94aa8 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1673,6 +1673,8 @@ class LazySpecialFunctions(): 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) """ +## Miscellaneous functions + def exp(self): r""" Return the exponential series of ``self``. @@ -1699,6 +1701,113 @@ def exp(self): P = self.parent() return P(lambda n: 1/factorial(n), 0)(self) + def hypergeometric(self, a, b): + r""" + Return the `{}_{p}F_{q}`-hypergeometric function + `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. + + INPUT:: + + - ``a`` -- the first parameter of the hypergeometric function + - ``b`` -- the second parameter of the hypergeometric function + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: LazySpecialFunctions.hypergeometric(z, [1, 1], [1]) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [1, 2], [1]) + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, 1, 1) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [4]) + 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: LazySpecialFunctions.hypergeometric(z, (1, 1), [1, 1]) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + + """ + from sage.functions.other import factorial + from sage.arith.misc import rising_factorial + if not isinstance(a, (list, tuple)): + a = [a] + if not isinstance(b, (list, tuple)): + b = [b] + def coeff(n, c): + num = 1 + for term in range(len(c)): + num *= rising_factorial(c[term], n) + return num + P = self.parent() + return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) + + def log(self): + r""" + Return the series for the natural logarithm of ``1 + self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: log(z) + z - 1/2*z^2 + 1/3*z^3 - 1/4*z^4 + 1/5*z^5 - 1/6*z^6 + 1/7*z^7 + O(z^8) + sage: log(z^2) + z^2 - 1/2*z^4 + 1/3*z^6 - 1/4*z^8 + O(z^9) + sage: log(z + z^2) + z + 1/2*z^2 - 2/3*z^3 + 1/4*z^4 + 1/5*z^5 - 1/3*z^6 + 1/7*z^7 + O(z^8) + sage: log(-z) + -z - 1/2*z^2 - 1/3*z^3 - 1/4*z^4 - 1/5*z^5 - 1/6*z^6 - 1/7*z^7 + O(z^8) + sage: log(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + P = self.parent() + return P(lambda n: ((-1) ** (n + 1))/n, 1)(self) + + def a_pow_z(self, a): + r""" + Return the series expansion for `a^{self}`. + + INPUT: + + - ``a`` - The base of the series + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions + sage: var('a b c') + (a, b, c) + sage: from sage.symbolic.constants import e + sage: LazySpecialFunctions.a_pow_z(z, a) + 1 + log(a)*z + 1/2*log(a)^2*z^2 + 1/6*log(a)^3*z^3 + 1/24*log(a)^4*z^4 + 1/120*log(a)^5*z^5 + 1/720*log(a)^6*z^6 + O(z^7) + sage: LazySpecialFunctions.a_pow_z(z^2, b) + 1 + log(b)*z^2 + 1/2*log(b)^2*z^4 + 1/6*log(b)^3*z^6 + O(z^7) + sage: LazySpecialFunctions.a_pow_z(z + z^2, c) + 1 + log(c)*z + (1/2*log(c)^2 + log(c))*z^2 + (1/6*log(c)^3 + log(c)^2)*z^3 + (1/24*log(c)^4 + 1/2*log(c)^3 + 1/2*log(c)^2)*z^4 + (1/120*log(c)^5 + 1/6*log(c)^4 + 1/2*log(c)^3)*z^5 + (1/720*log(c)^6 + 1/24*log(c)^5 + 1/4*log(c)^4 + 1/6*log(c)^3)*z^6 + O(z^7) + sage: LazySpecialFunctions.a_pow_z(z, e) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: LazySpecialFunctions.a_pow_z(z, 2) + 1 + log(2)*z + 1/2*log(2)^2*z^2 + 1/6*log(2)^3*z^3 + 1/24*log(2)^4*z^4 + 1/120*log(2)^5*z^5 + 1/720*log(2)^6*z^6 + O(z^7) + sage: LazySpecialFunctions.a_pow_z(1 + z, c) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.functions.log import log + from sage.functions.other import factorial + + P = self.parent() + return P(lambda n: log(a) ** (n)/factorial(n) if n else 1, 0)(self) + +## Trigonometric functions + def sin(self): r""" Return the sine of ``self``. @@ -1751,6 +1860,108 @@ def cos(self): P = self.parent() return P(lambda n: 1/factorial(n) if n % 4 == 0 else (n % 2 - 1)/factorial(n), 0)(self) + def tan(self): + r""" + Return the tangent of ``self``. + + EXAMPLES: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: tan(z) + z + 1/3*z^3 + 2/15*z^5 + O(z^7) + sage: tan(z^2) + z^2 + 1/3*z^6 + O(z^7) + sage: tan(z + z^2) + z + z^2 + 1/3*z^3 + z^4 + 17/15*z^5 + z^6 + O(z^7) + sage: tan(0) + 0 + sage: tan(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return LazySpecialFunctions.sin(self)/LazySpecialFunctions.cos(self) + + def cot(self): + r""" + Return the cotangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cot(z) + z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) + sage: cot(z^2) + z^-2 - 1/3*z^2 + O(z^5) + sage: cot(z + z^2) + z^-1 - 1 + 2/3*z - 4/3*z^2 + 44/45*z^3 - 16/15*z^4 + 176/189*z^5 + O(z^6) + sage: cot(0) + Infinity + sage: cot(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return ~LazySpecialFunctions.tan(self) + + def csc(self): + r""" + Return the cosecant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csc(z) + z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) + sage: csc(0) + Infinity + sage: csc(z^2) + z^-2 + 1/6*z^2 + O(z^5) + sage: csc(z + z^2) + z^-1 - 1 + 7/6*z - 5/6*z^2 + 367/360*z^3 - 113/120*z^4 + 16033/15120*z^5 + O(z^6) + sage: csc(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return ~LazySpecialFunctions.sin(self) + + def sec(self): + r""" + Return the secant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sec(z) + 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) + sage: sec(z^2) + 1 + 1/2*z^4 + O(z^7) + sage: sec(z + z^2) + 1 + 1/2*z^2 + z^3 + 17/24*z^4 + 5/6*z^5 + 961/720*z^6 + O(z^7) + sage: sec(0) + 1 + sage: sec(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + return ~LazySpecialFunctions.cos(self) + +## Inverse trigonometric functions + def arcsin(self): r""" Return the arcsin of ``self``. @@ -1806,6 +2017,60 @@ def arccos(self): P = self.parent() return P(pi/2) - LazySpecialFunctions.arcsin(self) + def arctan(self): + r""" + Return the arctangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: arctan(z) + z - 1/3*z^3 + 1/5*z^5 + O(z^7) + sage: arctan(z^2) + z^2 - 1/3*z^6 + O(z^7) + sage: arctan(z + z^2) + z + z^2 - 1/3*z^3 - z^4 - 4/5*z^5 + 2/3*z^6 + O(z^7) + sage: arctan(0) + 0 + sage: arctan(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + P = self.parent() + return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) + + def arccot(self): + r""" + Return the arctangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(RR) + sage: arccot(z) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) + sage: arccot(z^2) + 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) + sage: arccot(z + z^2) + 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) + sage: arccot(L(0)) + 1.57079632679490 + sage: arccot(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + """ + + from sage.symbolic.constants import pi + from sage.rings.lazy_laurent_series import LazySpecialFunctions + + P = self.parent() + return P(pi/2) - LazySpecialFunctions.arctan(self) + +## Hyerbolic functions + def sinh(self): r""" Return the sinh of ``self``. @@ -1860,60 +2125,11 @@ def cosh(self): P = self.parent() return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) - def tan(self): + def tanh(self): r""" - Return the tangent of ``self``. - - EXAMPLES: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: tan(z) - z + 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tan(z^2) - z^2 + 1/3*z^6 + O(z^7) - sage: tan(z + z^2) - z + z^2 + 1/3*z^3 + z^4 + 17/15*z^5 + z^6 + O(z^7) - sage: tan(0) - 0 - sage: tan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions + Return the tanh of ``self``. - return LazySpecialFunctions.sin(self)/LazySpecialFunctions.cos(self) - - def arctan(self): - r""" - Return the arctangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: arctan(z) - z - 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: arctan(z^2) - z^2 - 1/3*z^6 + O(z^7) - sage: arctan(z + z^2) - z + z^2 - 1/3*z^3 - z^4 - 4/5*z^5 + 2/3*z^6 + O(z^7) - sage: arctan(0) - 0 - sage: arctan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - P = self.parent() - return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) - - def tanh(self): - r""" - Return the tanh of ``self``. - - EXAMPLES:: + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) sage: tanh(z) @@ -1941,80 +2157,95 @@ def tanh(self): P = self.parent() return P(lambda n: (QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) * (-1 + (4 ** ((n + 1)/2))))/factorial(n + 1) if n % 2 else ZZ.zero(), 0)(self) - def csc(self): + def coth(self): r""" - Return the cosecant of ``self``. + Return the hyperbolic cotangent of ``self``. EXAMPLES:: + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: csc(z) - z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) - sage: csc(0) - Infinity - sage: csc(z^2) - z^-2 + 1/6*z^2 + O(z^5) - sage: csc(z + z^2) - z^-1 - 1 + 7/6*z - 5/6*z^2 + 367/360*z^3 - 113/120*z^4 + 16033/15120*z^5 + O(z^6) - sage: csc(1 + z) + sage: LazySpecialFunctions.coth(z) + z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) + sage: LazySpecialFunctions.coth(z^2) + z^-2 + 1/3*z^2 + O(z^5) + sage: LazySpecialFunctions.coth(z + z^2) + z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) + sage: LazySpecialFunctions.coth(L(0)) + Traceback (most recent call last): + ... + ZeroDivisionError: the valuation of the series must be nonnegative + sage: LazySpecialFunctions.coth(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions + from sage.functions.other import factorial + from sage.arith.misc import bernoulli - return ~LazySpecialFunctions.sin(self) + P = self.parent() + return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - def sec(self): + def sech(self): r""" - Return the secant of ``self``. + Return the hyperbolic secant of ``self``. EXAMPLES:: + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: sec(z) - 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: sec(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: sec(z + z^2) - 1 + 1/2*z^2 + z^3 + 17/24*z^4 + 5/6*z^5 + 961/720*z^6 + O(z^7) - sage: sec(0) + sage: LazySpecialFunctions.sech(z) + 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) + sage: LazySpecialFunctions.sech(z^2) + 1 - 1/2*z^4 + O(z^7) + sage: LazySpecialFunctions.sech(z + z^2) + 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) + sage: LazySpecialFunctions.sech(L(0)) 1 - sage: sec(1 + z) + sage: LazySpecialFunctions.sech(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - return ~LazySpecialFunctions.cos(self) + from sage.functions.other import factorial + from sage.combinat.combinat import euler_number - def cot(self): + P = self.parent() + return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) + + def cosech(self): r""" - Return the cotangent of ``self``. + Return the hyperbolic cosecant of ``self``. EXAMPLES:: + sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions sage: L. = LazyLaurentSeriesRing(QQ) - sage: cot(z) - z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) - sage: cot(z^2) - z^-2 - 1/3*z^2 + O(z^5) - sage: cot(z + z^2) - z^-1 - 1 + 2/3*z - 4/3*z^2 + 44/45*z^3 - 16/15*z^4 + 176/189*z^5 + O(z^6) - sage: cot(0) - Infinity - sage: cot(1 + z) + sage: LazySpecialFunctions.cosech(z) + z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) + sage: LazySpecialFunctions.cosech(z^2) + z^-2 - 1/6*z^2 + O(z^5) + sage: LazySpecialFunctions.cosech(z + z^2) + z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) + sage: LazySpecialFunctions.cosech(L(0)) + Traceback (most recent call last): + ... + ZeroDivisionError: the valuation of the series must be nonnegative + sage: LazySpecialFunctions.cosech(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions + from sage.functions.other import factorial + from sage.arith.misc import bernoulli - return ~LazySpecialFunctions.tan(self) + P = self.parent() + return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) + +## Inverse hyperbolic functions def asinh(self): r""" @@ -2094,166 +2325,6 @@ def acosh(self): P = self.parent() return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - - def sech(self): - r""" - Return the hyperbolic secant of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.sech(z) - 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: LazySpecialFunctions.sech(z^2) - 1 - 1/2*z^4 + O(z^7) - sage: LazySpecialFunctions.sech(z + z^2) - 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) - sage: LazySpecialFunctions.sech(L(0)) - 1 - sage: LazySpecialFunctions.sech(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.combinat.combinat import euler_number - - P = self.parent() - return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - - def cosech(self): - r""" - Return the hyperbolic cosecant of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.cosech(z) - z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.cosech(z^2) - z^-2 - 1/6*z^2 + O(z^5) - sage: LazySpecialFunctions.cosech(z + z^2) - z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.cosech(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.cosech(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - - P = self.parent() - return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - - def coth(self): - r""" - Return the hyperbolic cotangent of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.coth(z) - z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) - sage: LazySpecialFunctions.coth(z^2) - z^-2 + 1/3*z^2 + O(z^5) - sage: LazySpecialFunctions.coth(z + z^2) - z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) - sage: LazySpecialFunctions.coth(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.coth(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - - P = self.parent() - return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - - def arccot(self): - r""" - Return the arctangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(RR) - sage: arccot(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) - sage: arccot(z^2) - 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) - sage: arccot(z + z^2) - 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccot(L(0)) - 1.57079632679490 - sage: arccot(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - - from sage.symbolic.constants import pi - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - P = self.parent() - return P(pi/2) - LazySpecialFunctions.arctan(self) - - def hypergeometric(self, a, b): - r""" - Return the `{}_{p}F_{q}`-hypergeometric function - `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. - - INPUT:: - - - ``a`` -- the first parameter of the hypergeometric function - - ``b`` -- the second parameter of the hypergeometric function - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.hypergeometric(z, [1, 1], [1]) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [1, 2], [1]) - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, 1, 1) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [4]) - 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, (1, 1), [1, 1]) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - - """ - from sage.functions.other import factorial - from sage.arith.misc import rising_factorial - if not isinstance(a, (list, tuple)): - a = [a] - if not isinstance(b, (list, tuple)): - b = [b] - def coeff(n, c): - num = 1 - for term in range(len(c)): - num *= rising_factorial(c[term], n) - return num - P = self.parent() - return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): From 651b3725402fa4ba485671133be73ec9765c31a9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 11 Aug 2021 10:34:49 +0200 Subject: [PATCH 073/355] Revert "Merge branch 'u/gh-tejasvicsr1/special_functions_for_lazy_series' of git://trac.sagemath.org/sage into t/32324/lazy_taylor_series" This reverts commit 9c83de492be62192ed3e87db94d9c1248578368e, reversing changes made to eb27019f9f77701bcc7930442b52debb6fa63c8c. --- src/sage/rings/lazy_laurent_series.py | 1250 ++++++------------------- 1 file changed, 293 insertions(+), 957 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 31b2215de80..5869acfdec5 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -69,9 +69,11 @@ -1 AUTHORS: + - Kwankyu Lee (2019-02-24): initial version - Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): refactored and expanded functionality + """ # **************************************************************************** @@ -121,13 +123,13 @@ class LazySequenceElement(ModuleElement): Lazy Laurent Series Ring in z over Integer Ring sage: f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: f = 1/(1 - z) sage: f.parent() Lazy Laurent Series Ring in z over Integer Ring sage: f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - """ def __init__(self, parent, coeff_stream): """ @@ -137,6 +139,7 @@ def __init__(self, parent, coeff_stream): sage: L. = LazyLaurentSeriesRing(ZZ) sage: TestSuite(L.an_element()).run() + sage: L = LazyDirichletSeriesRing(QQbar, 'z') sage: g = L(constant=1) sage: TestSuite(g).run() @@ -168,13 +171,14 @@ def finite_part(self, degree=None): z^-3 + 2 + 3*z^4 sage: f.polynomial() z^-3 + 2 + 3*z^4 + sage: L = LazyDirichletSeriesRing(ZZ, "s") sage: f = L([1,0,0,2,0,0,0,3], valuation=2); f.finite_part() 3/9^s + 2/5^s + 1/2^s + sage: L. = LazyTaylorSeriesRing(ZZ) sage: f = 1/(1+x+y^2); f.finite_part(3) -x^3 + 2*x*y^2 + x^2 - y^2 - x + 1 - """ P = self.parent() L = P._laurent_poly_ring @@ -208,9 +212,11 @@ def __getitem__(self, n): [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] sage: f[0:20] [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + sage: M = L(lambda n: n) sage: [M[n] for n in range(20)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n) sage: [M[n] for n in range(20)] @@ -224,6 +230,7 @@ def __getitem__(self, n): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] sage: f[1:11] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: M = L(lambda n: n) sage: [M[n] for n in range(1, 11)] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -250,9 +257,10 @@ def map_coefficients(self, func, ring=None): coefficient of ``self``. INPUT: + - ``func`` -- function that takes in a coefficient and returns a new coefficient - + EXAMPLES: Dense Implementation:: @@ -270,7 +278,7 @@ def map_coefficients(self, func, ring=None): 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) Sparse Implementation:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) @@ -278,14 +286,14 @@ def map_coefficients(self, func, ring=None): 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) An example where the series is known to be exact:: - + sage: f = z + z^2 + z^3 sage: m = f.map_coefficients(lambda c: c + 1) sage: m 2*z + 2*z^2 + 2*z^3 Similarly for Dirichlet series:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: s = L(lambda n: n-1); s 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + ... @@ -316,13 +324,13 @@ def truncate(self, d): Return this series with its terms of degree >= ``d`` truncated. INPUT: - + - ``d`` -- integer; the degree from which the series is truncated EXAMPLES: - + Dense Implementation:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: alpha = 1/(1-z) sage: alpha @@ -336,21 +344,20 @@ def truncate(self, d): z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M.truncate(4) z + 2*z^2 + 3*z^3 - + Sparse Implementation:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M.truncate(4) z + 2*z^2 + 3*z^3 - + Series which are known to be exact can also be truncated:: - + sage: M = z + z^2 + z^3 + z^4 sage: M.truncate(4) z + z^2 + z^3 - """ P = self.parent() coeff_stream = self._coeff_stream @@ -362,27 +369,26 @@ def truncate(self, d): def prec(self): """ Return the precision of the series, which is infinity. - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: f = 1/(1 - z) sage: f.prec() +Infinity - """ return infinity def valuation(self): r""" Return the valuation of ``self``. - + This method determines the valuation of the series by looking for a nonzero coefficient. Hence if the series happens to be zero, then it may run forever. - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: s = 1/(1 - z) - 1/(1 - 2*z) sage: s.valuation() @@ -395,9 +401,9 @@ def valuation(self): 1 sage: (M - M).valuation() +Infinity - + Similarly for Dirichlet series:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: mu = L(moebius); mu.valuation() 1 @@ -408,7 +414,7 @@ def valuation(self): 2 sage: (g*g).valuation() 4 - + """ return self._coeff_stream.valuation() @@ -416,20 +422,21 @@ def _richcmp_(self, other, op): r""" Compare ``self` with ``other`` with respect to the comparison operator ``op``. - + Equality is verified if the corresponding coefficients of both series can be checked for equality without computing coefficients indefinitely. Otherwise an exception is raised to declare that equality is not decidable. + Inequality is not defined for lazy Laurent series. INPUT: - ``other`` -- another Laurent series - ``op`` -- comparison operator - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(QQ) sage: z + z^2 == z^2 + z True @@ -439,7 +446,6 @@ def _richcmp_(self, other, op): False sage: z + z^2 < z^2 + z False - """ if op is op_EQ: if isinstance(self._coeff_stream, CoefficientStream_zero): # self == 0 @@ -465,14 +471,15 @@ def _richcmp_(self, other, op): if op is op_NE: return not (self == other) + return False def __hash__(self): """ Return the hash of ``self`` - + TESTS:: - + sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: f = L([1,2,3,4], -5) sage: hash(f) == hash(f) @@ -480,16 +487,15 @@ def __hash__(self): sage: g = (1 + f)/(1 - f)^2 sage: {g: 1} {z^5 - 2*z^6 + z^7 + 5*z^9 - 11*z^10 + z^11 + O(z^12): 1} - """ return hash(self._coeff_stream) def __bool__(self): """ Test whether ``self`` is not zero. - + TESTS:: - + sage: L. = LazyLaurentSeriesRing(GF(2)) sage: bool(z-z) False @@ -510,6 +516,7 @@ def __bool__(self): 1 sage: bool(M) True + sage: L. = LazyLaurentSeriesRing(GF(2), sparse=True) sage: M = L(lambda n: 2*n if n < 10 else 1, 0); M O(z^7) @@ -521,7 +528,6 @@ def __bool__(self): 1 sage: bool(M) True - """ if isinstance(self._coeff_stream, CoefficientStream_zero): return False @@ -541,30 +547,30 @@ def __bool__(self): def define(self, s): r""" Define an equation by ``self = s``. - + INPUT: - + - ``s`` -- a Laurent polynomial - + EXAMPLES: - + We begin by constructing the Catalan numbers:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: C = L(None) sage: C.define(1 + z*C^2) sage: C 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - + The Catalan numbers but with a valuation 1:: - + sage: B = L(None, 1) sage: B.define(z + B^2) sage: B z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) - + We can define multiple series that are linked:: - + sage: s = L(None) sage: t = L(None) sage: s.define(1 + z*t^3) @@ -573,9 +579,9 @@ def define(self, s): [1, 1, 3, 9, 34, 132, 546, 2327, 10191] sage: t[:9] [1, 1, 2, 7, 24, 95, 386, 1641, 7150] - + A bigger example:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: A = L(None, 5) sage: B = L(None) @@ -589,17 +595,17 @@ def define(self, s): [0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138] sage: C[0:15] [0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142] - + Counting binary trees:: - + sage: L. = LazyLaurentSeriesRing(QQ) sage: s = L(None, valuation=1) sage: s.define(z + (s^2+s(z^2))/2) sage: [s[i] for i in range(9)] [0, 1, 1, 1, 2, 3, 6, 11, 23] - + The `q`-Catalan numbers:: - + sage: R. = ZZ[] sage: L. = LazyLaurentSeriesRing(R) sage: s = L(None) @@ -610,10 +616,10 @@ def define(self, s): + (q^10 + q^9 + 2*q^8 + 3*q^7 + 5*q^6 + 5*q^5 + 7*q^4 + 7*q^3 + 6*q^2 + 4*q + 1)*z^5 + (q^15 + q^14 + 2*q^13 + 3*q^12 + 5*q^11 + 7*q^10 + 9*q^9 + 11*q^8 + 14*q^7 + 16*q^6 + 16*q^5 + 17*q^4 + 14*q^3 + 10*q^2 + 5*q + 1)*z^6 + O(z^7) - + We count unlabeled ordered trees by total number of nodes and number of internal nodes:: - + sage: R. = QQ[] sage: Q. = LazyLaurentSeriesRing(R) sage: leaf = z @@ -623,9 +629,9 @@ def define(self, s): sage: T.define(leaf + internal_node * L(T)) sage: [T[i] for i in range(6)] [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] - + Similarly for Dirichlet series:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L(constant=1, valuation=2) sage: F = L(None); F.define(1 + g*F) @@ -635,17 +641,19 @@ def define(self, s): 0: A002033: Number of perfect partitions of n. 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. ... + sage: F = L(None); F.define(1 + g*F*F) sage: [F[i] for i in range(1, 16)] [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] - + TESTS:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: s = L(None) sage: s.define(1 + z*s^3) sage: s[:10] [1, 1, 3, 12, 55, 273, 1428, 7752, 43263, 246675] + sage: e = L(None) sage: e.define(1 + z*e) sage: e.define(1 + z*e) @@ -656,18 +664,18 @@ def define(self, s): Traceback (most recent call last): ... ValueError: series already defined - """ if not isinstance(self._coeff_stream, CoefficientStream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") self._coeff_stream._target = s._coeff_stream + def _repr_(self): r""" Return a string representation of ``self``. - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: z^-3 + z - 5 z^-3 - 5 + z @@ -689,17 +697,18 @@ def _repr_(self): z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) sage: L(lambda x: x if x > 0 else 0, valuation=-10) O(z^-3) + sage: L(None) Uninitialized Lazy Laurent Series sage: L(0) 0 + sage: R. = QQ[] sage: L. = LazyLaurentSeriesRing(R) sage: z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4 (-y + 1)*z^-4 + x^4*z^-3 + z^-2 + (x - y)*z^-1 + (x^2 - 2*x*y + y^2) + (x^3 - 3*x^2*y + 3*x*y^2 - y^3)*z + (x^4 - 4*x^3*y + 6*x^2*y^2 - 4*x*y^3 + y^4)*z^2 + O(z^3) - """ if isinstance(self._coeff_stream, CoefficientStream_zero): return '0' @@ -710,9 +719,9 @@ def _repr_(self): def _latex_(self): r""" Return a latex representation of ``self``. - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(ZZ) sage: latex(z^-3 + z - 5) \frac{1}{z^{3}} - 5 + z @@ -735,10 +744,12 @@ def _latex_(self): z + 2z^{2} + 3z^{3} + 4z^{4} + O(z^{5}) sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) O(\frac{1}{z^{3}}) + sage: latex(L(None)) \text{\texttt{Undef}} sage: latex(L(0)) 0 + sage: R. = QQ[] sage: L. = LazyLaurentSeriesRing(R) sage: latex(z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4) @@ -747,7 +758,6 @@ def _latex_(self): + \left(x^{3} - 3 x^{2} y + 3 x y^{2} - y^{3}\right)z + \left(x^{4} - 4 x^{3} y + 6 x^{2} y^{2} - 4 x y^{3} + y^{4}\right)z^{2} + O(z^{3}) - """ from sage.misc.latex import latex if isinstance(self._coeff_stream, CoefficientStream_zero): @@ -759,16 +769,15 @@ def _latex_(self): def _ascii_art_(self): r""" Return an ascii art representation of ``self``. - + EXAMPLES:: - + sage: e = SymmetricFunctions(QQ).e() sage: L. = LazyLaurentSeriesRing(e) sage: L.options.display_length = 3 sage: ascii_art(1 / (1 - e[1]*z)) e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) sage: L.options._reset() - """ from sage.typeset.ascii_art import ascii_art, AsciiArt if isinstance(self._coeff_stream, CoefficientStream_zero): @@ -789,7 +798,6 @@ def _unicode_art_(self): sage: unicode_art(1 / (1 - e[1]*z)) e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) sage: L.options._reset() - """ from sage.typeset.unicode_art import unicode_art, UnicodeArt if isinstance(self._coeff_stream, CoefficientStream_zero): @@ -842,7 +850,6 @@ class LazySequencesModuleElement(LazySequenceElement): sage: R = -M sage: R[:10] [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] - """ def _add_(self, other): """ @@ -895,12 +902,15 @@ def _add_(self, other): 1 + 1/(2^z) + 1/(3^z) + ... sage: s + t 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + ... + sage: r = L(constant=-1) sage: r + t 0 + sage: r = L([1,2,3]) sage: r + t 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + ... + sage: r = L([1,2,3], constant=-1) sage: r + t 2 + 3/2^z + 4/3^z @@ -963,6 +973,7 @@ def _sub_(self, other): sage: O = M - N sage: O[0:10] [1, -1, 0, 0, 0, 0, 0, 0, 0, 0] + sage: M = L([1, 0, 1]) sage: N = L([0, 0, 1]) sage: O = M - L.one() - N @@ -976,7 +987,6 @@ def _sub_(self, other): True sage: 0 - M == -M True - """ P = self.parent() left = self._coeff_stream @@ -1046,7 +1056,6 @@ def _lmul_(self, scalar): True sage: N * 0 0 - """ P = self.parent() if not scalar: @@ -1068,15 +1077,15 @@ def _rmul_(self, scalar): r""" Scalar multiplication for module elements with the module element on the right and the scalar on the left. - + INPUT: - + - ``scalar`` -- an element of the base ring - + EXAMPLES: - + Dense series can be multiplied with a scalar:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: M = L(lambda n: 1 + n, valuation=0) sage: O = 2 * M @@ -1086,9 +1095,9 @@ def _rmul_(self, scalar): True sage: 0 * M 0 - + Sparse series can be multiplied with a scalar:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: 1 + n, valuation=0) sage: O = 2 * M @@ -1098,9 +1107,9 @@ def _rmul_(self, scalar): True sage: 0 * M 0 - + Series which are known to be exact can be multiplied with a scalar:: - + sage: N = L([0, 1]) sage: O = -1 * N sage: O[0:10] @@ -1109,9 +1118,9 @@ def _rmul_(self, scalar): True sage: 0 * N 0 - + Similarly for Dirichlet series:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L.gen(2) sage: 2 * g @@ -1124,11 +1133,12 @@ def _rmul_(self, scalar): 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) sage: 3 * M 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) + sage: 1 * M is M True - + We take care of noncommutative base rings:: - + sage: M = MatrixSpace(ZZ, 2) sage: L. = LazyTaylorSeriesRing(M) sage: m = M([[1, 1],[0, 1]]) @@ -1137,7 +1147,7 @@ def _rmul_(self, scalar): sage: (m*a - a*m)[3] [ 3 0] [ 0 -3] - + """ P = self.parent() if not scalar: @@ -1160,11 +1170,11 @@ def _rmul_(self, scalar): def _neg_(self): """ Return the negative of ``self``. - + EXAMPLES: - + Dense series can be negated:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: M = L(lambda n: n, valuation=0) sage: N = L(lambda n: -n, valuation=0) @@ -1179,9 +1189,9 @@ def _neg_(self): [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: O == M True - + Sparse series can be negated:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n, valuation=0) sage: N = L(lambda n: -n, valuation=0) @@ -1196,9 +1206,9 @@ def _neg_(self): [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: O == M True - + Series which are known to be exact can be negated:: - + sage: M = L.one() sage: N = L([0, 1]) sage: O = -N @@ -1212,7 +1222,6 @@ def _neg_(self): [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] sage: O == M True - """ P = self.parent() coeff_stream = self._coeff_stream @@ -1232,33 +1241,29 @@ def _neg_(self): class LazyCauchyProductSeries(RingElement): """ A class for series where multiplication is the Cauchy product. - - We are assuming that :meth:`polynomial` - """ def __init__(self, parent): """ Initialize. - + TESTS:: - + sage: from sage.rings.lazy_laurent_series import LazyCauchyProductSeries sage: L. = LazyLaurentSeriesRing(ZZ) sage: M = LazyCauchyProductSeries(L) - """ RingElement.__init__(self, parent) def _mul_(self, other): """ Return the product of this series with ``other``. - + INPUT: - + - ``other`` -- other series - + TESTS:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: (1 - z)*(1 - z) 1 - 2*z + z^2 @@ -1270,6 +1275,7 @@ def _mul_(self, other): sage: N = M * (1 - M) sage: N z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ... + sage: p = (1 - z)*(1 + z^2)^3 * z^-2 sage: p z^-2 - z^-1 + 3 - 3*z + 3*z^2 - 3*z^3 + z^4 - z^5 @@ -1281,6 +1287,7 @@ def _mul_(self, other): + 7*z^4 - 2*z^5 + 4*z^6 - 5*z^7 + z^8 - 2*z^9 sage: M * p == p * M True + sage: q = (1 - 2*z)*(1 + z^2)^3 * z^-2 sage: q * M -2*z^-4 + 3*z^-3 - 4*z^-2 + 10*z^-1 + 11*z + 2*z^2 - 3*z^3 @@ -1288,6 +1295,7 @@ def _mul_(self, other): - 16*z^10 - 16*z^11 - 16*z^12 + O(z^13) sage: q * M == M * q True + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ... @@ -1295,21 +1303,22 @@ def _mul_(self, other): 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... sage: M * N z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + ... + sage: L.one() * M is M True sage: M * L.one() is M True - + Similarly for Taylor series:: - + sage: L. = LazyTaylorSeriesRing(ZZ) sage: (1 - x)*(1 - y) 1 + (-x-y) + x*y sage: (1 - x)*(1 - y)*(1 - z) 1 + (-x-y-z) + (x*y+x*z+y*z) + (-x*y*z) - + We take care of noncommutative base rings:: - + sage: M = MatrixSpace(ZZ, 2) sage: L. = LazyTaylorSeriesRing(M) sage: m = M([[1, 1],[0, 1]]) @@ -1319,10 +1328,10 @@ def _mul_(self, other): sage: (b*a-a*b)[20] [-19 0] [ 0 19] - + Multiplication of series with eventually constant coefficients may yield another such series:: - + sage: L. = LazyLaurentSeriesRing(SR) sage: var("a b c d e u v w") (a, b, c, d, e, u, v, w) @@ -1332,9 +1341,9 @@ def _mul_(self, other): sage: t1 = t.approximate_series(44) sage: s1 * t1 - (s * t).approximate_series(42) O(z^42) - + Noncommutative:: - + sage: M = MatrixSpace(ZZ, 2) sage: L. = LazyTaylorSeriesRing(M) sage: a = L([m], degree=1) @@ -1342,7 +1351,7 @@ def _mul_(self, other): sage: (a*b)[0] [2 1] [1 1] - + """ P = self.parent() left = self._coeff_stream @@ -1400,11 +1409,11 @@ def _mul_(self, other): def __invert__(self): """ Return the multiplicative inverse of the element. - + EXAMPLES: - + Lazy Laurent series that have a dense implementation can be inverted:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: ~(1 - z) 1 + z + z^2 + O(z^3) @@ -1412,22 +1421,23 @@ def __invert__(self): z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: P = ~M; P z^-1 - 2 + z + O(z^6) - + Lazy Laurent series that have a sparse implementation can be inverted:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: P = ~M; P z^-1 - 2 + z + O(z^6) + sage: ~(~(1 - z)) 1 - z - + Lazy Laurent series that are known to be exact can be inverted:: - + sage: ~z z^-1 - + """ P = self.parent() coeff_stream = self._coeff_stream @@ -1466,15 +1476,15 @@ def __invert__(self): def _div_(self, other): r""" Return ``self`` divided by ``other``. - + INPUT: - + - ``other`` -- nonzero series - + EXAMPLES: - + Lazy Laurent series that have a dense implementation can be divided:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: z/(1 - z) z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) @@ -1484,9 +1494,9 @@ def _div_(self, other): 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: P = M / N; P z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - + Lazy Laurent series that have a sparse implementation can be divided:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) @@ -1494,22 +1504,21 @@ def _div_(self, other): 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: P = M / N; P z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - + Lazy Laurent series that are known to be exact can be divided:: - + M = z^2 + 2*z + 1 N = z + 1 O = M / N; O z + 1 - + An example over the ring of symmetric functions:: - + sage: e = SymmetricFunctions(QQ).e() sage: R. = LazyLaurentSeriesRing(e) sage: 1 / (1 - e[1]*z) e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) - """ if isinstance(other._coeff_stream, CoefficientStream_zero): raise ZeroDivisionError("cannot divide by 0") @@ -1545,16 +1554,16 @@ def _div_(self, other): def __pow__(self, n): """ Return the ``n``-th power of the series. - + INPUT: - + - ``n`` -- integer; the power to which to raise the series - + EXAMPLES: - + Lazy Laurent series that have a dense implementation can be raised to the power ``n``:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: (1 - z)^-1 1 + z + z^2 + O(z^3) @@ -1568,32 +1577,31 @@ def __pow__(self, n): z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M^2 z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - + We can create a really large power of a monomial, even with the dense implementation:: - + sage: z^1000000 z^1000000 - + Lazy Laurent series that have a sparse implementation can be raised to the power ``n``:: - + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: M = L(lambda n: n); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M^2 z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - + Lazy Laurent series that are known to be exact can be raised to the power ``n``:: - + sage: z^2 z^2 sage: (1 - z)^2 1 - 2*z + z^2 sage: (1 + z)^2 1 + 2*z + z^2 - """ if n == 0: return self.parent().one() @@ -1614,735 +1622,92 @@ def __pow__(self, n): return generic_power(self, n) -class LazySpecialFunctions(): +class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" - A class for lazily computing special functions. - - EXAMPLES: - - The exponential series can be found. :: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: exp(z) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - - The sine of a series can be found. :: - - sage: sin(z) - z - 1/6*z^3 + 1/120*z^5 + O(z^7) - - The cosine of a series can be found. :: - - sage: cos(z) - 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - - The tangent of a series can be found. :: - - sage: tan(z) - z + 1/3*z^3 + 2/15*z^5 + O(z^7) - - The arcsin of a series can be found. :: - - sage: arcsin(z) - z + 1/6*z^3 + 3/40*z^5 + O(z^7) - - The sinh of a series can be found. :: - - sage: sinh(z) - z + 1/6*z^3 + 1/120*z^5 + O(z^7) - - The cosh of a series can be found. :: - - sage: cosh(z) - 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - - The arctangent of a series can be found. :: - - sage: arctan(z) - z - 1/3*z^3 + 1/5*z^5 + O(z^7) - - The tanh of a series can be found. :: - - sage: tanh(z) - z - 1/3*z^3 + 2/15*z^5 + O(z^7) - - The arccosine of a series can be found. :: - - sage: L. = LazyLaurentSeriesRing(RR) - sage: arccos(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) - - """ - def exp(self): - r""" - Return the exponential series of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: exp(z) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: exp(z^2) - 1 + z^2 + 1/2*z^4 + 1/6*z^6 + O(z^7) - sage: exp(z + z^2) - 1 + z + 3/2*z^2 + 7/6*z^3 + 25/24*z^4 + 27/40*z^5 + 331/720*z^6 + O(z^7) - sage: exp(0) - 1 - sage: exp(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial + A Laurent series where the coefficients are computed lazily. - P = self.parent() - return P(lambda n: 1/factorial(n), 0)(self) + EXAMPLES:: - def sin(self): - r""" - Return the sine of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: sin(z) - z - 1/6*z^3 + 1/120*z^5 + O(z^7) - sage: sin(z^2) - z^2 - 1/6*z^6 + O(z^7) - sage: sin(z + z^2) - z + z^2 - 1/6*z^3 - 1/2*z^4 - 59/120*z^5 - 1/8*z^6 + O(z^7) - sage: sin(0) - 0 - sage: sin(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L(lambda i: i, valuation=-3, constant=(-1,3)) + -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + O(z^6) + sage: L(lambda i: i, valuation=-3, constant=-1, degree=3) + -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + O(z^6) - P = self.parent() - return P(lambda n: (n % 2)/factorial(n) if n % 4 == 1 else -(n % 2)/factorial(n), 0)(self) + :: - def cos(self): - r""" - Return the cosine of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: cos(z) - 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - sage: cos(z^2) - 1 - 1/2*z^4 + O(z^7) - sage: cos(z + z^2) - 1 - 1/2*z^2 - z^3 - 11/24*z^4 + 1/6*z^5 + 179/720*z^6 + O(z^7) - sage: cos(0) - 1 - sage: cos(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial + sage: f = 1 / (1 - z - z^2); f + 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7) + sage: f.coefficient(100) + 573147844013817084101 - P = self.parent() - return P(lambda n: 1/factorial(n) if n % 4 == 0 else (n % 2 - 1)/factorial(n), 0)(self) + Lazy Laurent series is picklable:: - def arcsin(self): + sage: g = loads(dumps(f)) + sage: g + 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7) + sage: g == f + True + """ + def change_ring(self, ring): r""" - Return the arcsin of ``self``. - - EXAMPLES:: + Return ``self`` with coefficients converted to elements of ``ring``. - sage: L. = LazyLaurentSeriesRing(QQ) - sage: arcsin(z) - z + 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: arcsin(z)[7] - 5/112 - sage: arcsin(z) - z + 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: arcsin(z^2) - z^2 + 1/6*z^6 + O(z^7) - sage: arcsin(z + z^2) - z + z^2 + 1/6*z^3 + 1/2*z^4 + 23/40*z^5 + 13/24*z^6 + O(z^7) - sage: arcsin(0) - 0 - sage: arcsin(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + INPUT: - """ - from sage.functions.other import factorial + - ``ring`` -- a ring - P = self.parent() - return P(lambda n: factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) if n % 2 else ZZ.zero(), 0)(self) + EXAMPLES: - def arccos(self): - r""" - Return the arccos of ``self``. + Dense Implementation:: - EXAMPLES:: + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring - sage: L. = LazyLaurentSeriesRing(RR) - sage: arccos(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) - sage: arccos(z^2) - 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 - 0.166666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccos(z + z^2) - 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 - 0.166666666666667*z^3 - 0.500000000000000*z^4 - 0.575000000000000*z^5 - 0.541666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccos(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + Sparse Implementation:: + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M ^-1 + z^-1 - 2 + z + O(z^6) """ - from sage.symbolic.constants import pi - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - P = self.parent() - return P(pi/2) - LazySpecialFunctions.arcsin(self) + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) + return Q.element_class(Q, self._coeff_stream) - def sinh(self): + def __call__(self, g): r""" - Return the sinh of ``self``. + Return the composition of ``self`` with ``g``. - EXAMPLES:: + Given two Laurent Series `f` and `g` over the same base ring, the + composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - sage: L. = LazyLaurentSeriesRing(QQ) - sage: sinh(z) - z + 1/6*z^3 + 1/120*z^5 + O(z^7) - sage: sinh(z^2) - z^2 + 1/6*z^6 + O(z^7) - sage: sinh(z + z^2) - z + z^2 + 1/6*z^3 + 1/2*z^4 + 61/120*z^5 + 5/24*z^6 + O(z^7) - sage: sinh(0) - 0 - sage: sinh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - - from sage.functions.other import factorial - - P = self.parent() - return P(lambda n: 1/factorial(n) if n % 2 else ZZ.zero(), 0)(self) - - def cosh(self): - r""" - Return the cosh of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: cosh(z) - 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: cosh(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: cosh(z + z^2) - 1 + 1/2*z^2 + z^3 + 13/24*z^4 + 1/6*z^5 + 181/720*z^6 + O(z^7) - sage: cosh(0) - 1 - sage: cosh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - - from sage.functions.other import factorial - - P = self.parent() - return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) - - def tan(self): - r""" - Return the tangent of ``self``. - - EXAMPLES: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: tan(z) - z + 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tan(z^2) - z^2 + 1/3*z^6 + O(z^7) - sage: tan(z + z^2) - z + z^2 + 1/3*z^3 + z^4 + 17/15*z^5 + z^6 + O(z^7) - sage: tan(0) - 0 - sage: tan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - return LazySpecialFunctions.sin(self)/LazySpecialFunctions.cos(self) - - def arctan(self): - r""" - Return the arctangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: arctan(z) - z - 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: arctan(z^2) - z^2 - 1/3*z^6 + O(z^7) - sage: arctan(z + z^2) - z + z^2 - 1/3*z^3 - z^4 - 4/5*z^5 + 2/3*z^6 + O(z^7) - sage: arctan(0) - 0 - sage: arctan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - P = self.parent() - return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) - - def tanh(self): - r""" - Return the tanh of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: tanh(z) - z - 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tanh(z)[7] - -17/315 - sage: tanh(z) - z - 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tanh(z^2) - z^2 - 1/3*z^6 + O(z^7) - sage: tanh(z + z^2) - z + z^2 - 1/3*z^3 - z^4 - 13/15*z^5 + 1/3*z^6 + O(z^7) - sage: tanh(0) - 0 - sage: tanh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - from sage.rings.rational_field import QQ - - P = self.parent() - return P(lambda n: (QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) * (-1 + (4 ** ((n + 1)/2))))/factorial(n + 1) if n % 2 else ZZ.zero(), 0)(self) - - def csc(self): - r""" - Return the cosecant of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: csc(z) - z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) - sage: csc(0) - Infinity - sage: csc(z^2) - z^-2 + 1/6*z^2 + O(z^5) - sage: csc(z + z^2) - z^-1 - 1 + 7/6*z - 5/6*z^2 + 367/360*z^3 - 113/120*z^4 + 16033/15120*z^5 + O(z^6) - sage: csc(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - return ~LazySpecialFunctions.sin(self) - - def sec(self): - r""" - Return the secant of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: sec(z) - 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: sec(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: sec(z + z^2) - 1 + 1/2*z^2 + z^3 + 17/24*z^4 + 5/6*z^5 + 961/720*z^6 + O(z^7) - sage: sec(0) - 1 - sage: sec(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - return ~LazySpecialFunctions.cos(self) - - def cot(self): - r""" - Return the cotangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: cot(z) - z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) - sage: cot(z^2) - z^-2 - 1/3*z^2 + O(z^5) - sage: cot(z + z^2) - z^-1 - 1 + 2/3*z - 4/3*z^2 + 44/45*z^3 - 16/15*z^4 + 176/189*z^5 + O(z^6) - sage: cot(0) - Infinity - sage: cot(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - return ~LazySpecialFunctions.tan(self) - - def asinh(self): - r""" - Return the inverse of the hyperbolic sine of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.asinh(z) - z - 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: LazySpecialFunctions.asinh(z^2) - z^2 - 1/6*z^6 + O(z^7) - sage: LazySpecialFunctions.asinh(z + z^2) - z + z^2 - 1/6*z^3 - 1/2*z^4 - 17/40*z^5 + 5/24*z^6 + O(z^7) - sage: LazySpecialFunctions.asinh(L(0)) - 0 - sage: LazySpecialFunctions.asinh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - - P = self.parent() - return P(lambda n: ZZ.zero() if n % 2 == 0 else (((-1) ** ((n - 1)/2)) * factorial(n - 1))/(4 ** ((n - 1)/2) * (factorial((n - 1)/2) ** 2) * n), 0)(self) - - def atanh(self): - r""" - Return the inverse of the hyperbolic tangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.atanh(z) - z + 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: LazySpecialFunctions.atanh(z^2) - z^2 + 1/3*z^6 + O(z^7) - sage: LazySpecialFunctions.atanh(L(0)) - 0 - sage: LazySpecialFunctions.atanh(z + z^2) - z + z^2 + 1/3*z^3 + z^4 + 6/5*z^5 + 4/3*z^6 + O(z^7) - sage: LazySpecialFunctions.atanh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - P = self.parent() - return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) - - def acosh(self): - r""" - Return the inverse of the hyperbolic tangent of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.acosh(z) - 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: LazySpecialFunctions.acosh(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: LazySpecialFunctions.acosh(z + z^2) - 1 + 1/2*z^2 + z^3 + 13/24*z^4 + 1/6*z^5 + 181/720*z^6 + O(z^7) - sage: LazySpecialFunctions.acosh(L(0)) - 1 - sage: LazySpecialFunctions.acosh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - - P = self.parent() - return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - - def sech(self): - r""" - Return the hyperbolic secant of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.sech(z) - 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: LazySpecialFunctions.sech(z^2) - 1 - 1/2*z^4 + O(z^7) - sage: LazySpecialFunctions.sech(z + z^2) - 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) - sage: LazySpecialFunctions.sech(L(0)) - 1 - sage: LazySpecialFunctions.sech(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.combinat.combinat import euler_number - - P = self.parent() - return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) - - def cosech(self): - r""" - Return the hyperbolic cosecant of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.cosech(z) - z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.cosech(z^2) - z^-2 - 1/6*z^2 + O(z^5) - sage: LazySpecialFunctions.cosech(z + z^2) - z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) - sage: LazySpecialFunctions.cosech(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.cosech(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - - P = self.parent() - return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - - def coth(self): - r""" - Return the hyperbolic cotangent of ``self``. - - EXAMPLES:: - - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: L. = LazyLaurentSeriesRing(QQ) - sage: LazySpecialFunctions.coth(z) - z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) - sage: LazySpecialFunctions.coth(z^2) - z^-2 + 1/3*z^2 + O(z^5) - sage: LazySpecialFunctions.coth(z + z^2) - z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) - sage: LazySpecialFunctions.coth(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: LazySpecialFunctions.coth(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - from sage.functions.other import factorial - from sage.arith.misc import bernoulli - - P = self.parent() - return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) - - def arccot(self): - r""" - Return the arctangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(RR) - sage: arccot(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) - sage: arccot(z^2) - 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) - sage: arccot(z + z^2) - 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccot(L(0)) - 1.57079632679490 - sage: arccot(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ - - from sage.symbolic.constants import pi - from sage.rings.lazy_laurent_series import LazySpecialFunctions - - P = self.parent() - return P(pi/2) - LazySpecialFunctions.arctan(self) - - def hypergeometric(self, a, b): - r""" - Return the `{}_{p}F_{q}`-hypergeometric function - `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. - - INPUT:: - - - ``a`` -- the first parameter of the hypergeometric function - - ``b`` -- the second parameter of the hypergeometric function - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: from sage.rings.lazy_laurent_series import LazySpecialFunctions - sage: LazySpecialFunctions.hypergeometric(z, [1, 1], [1]) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [1, 2], [1]) - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, 1, 1) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [4]) - 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: LazySpecialFunctions.hypergeometric(z, (1, 1), [1, 1]) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - - """ - from sage.functions.other import factorial - from sage.arith.misc import rising_factorial - if not isinstance(a, (list, tuple)): - a = [a] - if not isinstance(b, (list, tuple)): - b = [b] - def coeff(n, c): - num = 1 - for term in range(len(c)): - num *= rising_factorial(c[term], n) - return num - P = self.parent() - return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) - - -class LazyLaurentSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): - r""" - A Laurent series where the coefficients are computed lazily. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L(lambda i: i, valuation=-3, constant=(-1,3)) - -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + O(z^6) - sage: L(lambda i: i, valuation=-3, constant=-1, degree=3) - -3*z^-3 - 2*z^-2 - z^-1 + z + 2*z^2 - z^3 - z^4 - z^5 + O(z^6) - - :: - - sage: f = 1 / (1 - z - z^2); f - 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7) - sage: f.coefficient(100) - 573147844013817084101 - - Lazy Laurent series is picklable:: - - sage: g = loads(dumps(f)) - sage: g - 1 + z + 2*z^2 + 3*z^3 + 5*z^4 + 8*z^5 + 13*z^6 + O(z^7) - sage: g == f - True - - """ - def change_ring(self, ring): - r""" - Return ``self`` with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES: - - Dense Implementation:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: s = 2 + z - sage: t = s.change_ring(QQ) - sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - - Sparse Implementation:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M ^-1 - z^-1 - 2 + z + O(z^6) - - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - - def __call__(self, g): - r""" - Return the composition of ``self`` with ``g``. - - Given two Laurent Series `f` and `g` over the same base ring, the - composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - `g = 0` and `val(f) >= 0`, - `g` is non-zero and `f` has only finitely many non-zero coefficients, - `g` is non-zero and `val(g) > 0`. - + INPUT: - + - ``g`` -- other series - + EXAMPLES:: - + sage: L. = LazyLaurentSeriesRing(QQ) sage: f = z^2 + 1 + z sage: f(0) @@ -2357,6 +1722,7 @@ def __call__(self, g): z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) sage: g^2 + 1 + g z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) + sage: f = z^-2 + z + 4*z^3 sage: f(f) 4*z^-6 + 12*z^-3 + z^-2 + 48*z^-1 + 12 + O(z) @@ -2366,6 +1732,7 @@ def __call__(self, g): 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + O(z^-2) sage: g^-2 + g + 4*g^3 4*z^-9 + 24*z^-8 + 96*z^-7 + 320*z^-6 + 960*z^-5 + 2688*z^-4 + 7169*z^-3 + O(z^-2) + sage: f = z^-3 + z^-2 + 1 / (1 + z^2); f z^-3 + z^-2 + 1 - z^2 + O(z^4) sage: g = z^3 / (1 + z - z^3); g @@ -2385,15 +1752,16 @@ def __call__(self, g): z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: f(z^2) z^2 + 2*z^4 + 3*z^6 + O(z^7) + sage: f = L(lambda n: n, -2); f -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) sage: f3 = f(z^3); f3 -2*z^-6 - z^-3 + O(z) sage: [f3[i] for i in range(-6,13)] [-2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4] - + We compose a Laurent polynomial with a generic element:: - + sage: R. = QQ[] sage: f = z^2 + 1 + z^-1 sage: g = x^2 + x + 3 @@ -2401,9 +1769,9 @@ def __call__(self, g): (x^6 + 3*x^5 + 12*x^4 + 19*x^3 + 37*x^2 + 28*x + 31)/(x^2 + x + 3) sage: f(g) == g^2 + 1 + g^-1 True - + We compose with another lazy Laurent series:: - + sage: LS. = LazyLaurentSeriesRing(QQ) sage: f = z^2 + 1 + z^-1 sage: fy = f(y); fy @@ -2415,11 +1783,13 @@ def __call__(self, g): Traceback (most recent call last): ... ZeroDivisionError: the valuation of the series must be nonnegative + sage: g = 1 - y sage: f(g) 3 - y + 2*y^2 + y^3 + y^4 + y^5 + O(y^6) sage: g^2 + 1 + g^-1 3 - y + 2*y^2 + y^3 + y^4 + y^5 + O(y^6) + sage: f = L(lambda n: n, 0); f z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: f(0) @@ -2431,18 +1801,20 @@ def __call__(self, g): True sage: fp.parent() is LS True + sage: f = z^2 + 3 + z sage: f(y - y) 3 - + With both of them sparse:: - + sage: L. = LazyLaurentSeriesRing(QQ, sparse=True) sage: LS. = LazyLaurentSeriesRing(QQ, sparse=True) sage: f = L(lambda n: 1); f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: f(y^2) 1 + y^2 + y^4 + y^6 + O(y^7) + sage: fp = f - 1 + z^-2; fp z^-2 + z + z^2 + z^3 + z^4 + O(z^5) sage: fpy = fp(y^2); fpy @@ -2451,12 +1823,14 @@ def __call__(self, g): True sage: [fpy[i] for i in range(-4,11)] [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] + sage: g = LS(valuation=2, constant=1); g y^2 + y^3 + y^4 + O(y^5) sage: fg = f(g); fg 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + O(y^7) sage: 1 + g + g^2 + g^3 + g^4 + g^5 + g^6 1 + y^2 + y^3 + 2*y^4 + 3*y^5 + 5*y^6 + O(y^7) + sage: h = LS(lambda n: 1 if n % 2 else 0, 2); h y^3 + y^5 + y^7 + O(y^9) sage: fgh = fg(h); fgh @@ -2466,9 +1840,9 @@ def __call__(self, g): sage: t = 1 + h^2 + h^3 + 2*h^4 + 3*h^5 + 5*h^6 sage: [t[i] for i in range(0, 15)] [1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 3, 3, 6, 6, 13] - + We look at mixing the sparse and the dense:: - + sage: L. = LazyLaurentSeriesRing(QQ) sage: f = L(lambda n: 1); f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) @@ -2476,6 +1850,7 @@ def __call__(self, g): y + y^2 + y^3 + y^4 + y^5 + y^6 + y^7 + O(y^8) sage: f(g) 1 + y + 2*y^2 + 4*y^3 + 8*y^4 + 16*y^5 + 32*y^6 + O(y^7) + sage: f = z^-2 + 1 + z sage: g = 1/(y*(1-y)); g y^-1 + 1 + y + y^2 + y^3 + y^4 + y^5 + O(y^6) @@ -2483,6 +1858,7 @@ def __call__(self, g): y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + O(y^6) sage: g^-2 + 1 + g y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + O(y^6) + sage: f = z^-3 + z^-2 + 1 sage: g = 1/(y^2*(1-y)); g y^-2 + y^-1 + 1 + y + y^2 + y^3 + y^4 + O(y^5) @@ -2492,10 +1868,10 @@ def __call__(self, g): 1 + y^4 - 2*y^5 + 2*y^6 + O(y^7) sage: z(y) y - + We look at cases where the composition does not exist. - `g = 0` and `val(f) < 0`:: + sage: g = L(0) sage: f = z^-1 + z^-2 sage: f.valuation() < 0 @@ -2504,7 +1880,7 @@ def __call__(self, g): Traceback (most recent call last): ... ZeroDivisionError: the valuation of the series must be nonnegative - + `g \neq 0` and `val(g) \leq 0` and `f` has infinitely many non-zero coefficients`:: @@ -2525,7 +1901,6 @@ def __call__(self, g): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series - """ # f = self and compute f(g) P = g.parent() @@ -2610,71 +1985,30 @@ def revert(self): r""" Return the compositional inverse of ``self``. - Given a Laurent Series `f` we want to find a Laurent Series `g` over the same base ring, such - that the composition `(f \circ g)(z) = f(g(z)) = z`. The composition inverse exists if and only if: - - `val(f) = 1' or `f(0) * f(1) != 0`, - - EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(QQ) + sage: L. = LazyLaurentSeriesRing(ZZ) sage: z.revert() z + O(z^8) sage: (1/z).revert() z^-1 + O(z^6) - sage: (z - z^2).revert() - z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) - sage: (z + z^2).revert() - z - z^2 + 2*z^3 - 5*z^4 + 14*z^5 - 42*z^6 + 132*z^7 + O(z^8) - sage: (2*z).revert() - 1/2*z + O(z^8) - sage: s = L(lambda n: 1 if n == 1 else 0) - sage: s.revert() - z + O(z^8) - - We look at some cases where the compositional inverse does not exist.: - - `f = 0`:: - sage: L(0).revert() - Traceback (most recent call last): - ... - ValueError: compositional inverse does not exist - sage: (z - z).revert() - Traceback (most recent call last): - ... - ValueError: compositional inverse does not exist - - `val(f) ! = 1 and f(0) * f(1) = 0`:: - - sage: (z^2).revert() - Traceback (most recent call last): - ... - ValueError: compositional inverse does not exist - sage: L(1).revert() - Traceback (most recent call last): - ... - ValueError: compositional inverse does not exist + sage: (z-z^2).revert() + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) """ P = self.parent() z = P.gen() - # g = 0 case - if isinstance(self._coeff_stream, CoefficientStream_zero): - raise ValueError('compositional inverse does not exist') - # val g > 0 and ensure that val(g) == 1 - if self.valuation() >= 0 and self.valuation() != 1: - raise ValueError('compositional inverse does not exist') - if self.valuation() == 1: + if self._coeff_stream._approximate_valuation == 1: g = self else: - g = self * z**(1 - self.valuation()) + g = self * z**(1 - self._coeff_stream._approximate_valuation) f = P(None, valuation=1) f.define(z/((g/z)(f))) - if self.valuation() == 1: + if self._coeff_stream._approximate_valuation == 1: return f else: - return f / z**(1 - self.valuation()) + return f / z**(1 - self._coeff_stream._approximate_valuation) def approximate_series(self, prec, name=None): """ @@ -2706,7 +2040,6 @@ def approximate_series(self, prec, name=None): z^-5 - 2*z^-4 + 10*z^-3 - 20*z^-2 + 60*z^-1 - 120 + 280*z - 560*z^2 + O(z^3) sage: h.parent() Laurent Series Ring in z over Integer Ring - """ S = self.parent() @@ -2737,6 +2070,7 @@ def polynomial(self, degree=None, name=None): A Laurent polynomial if the valuation of the series is negative or a polynomial otherwise. + If ``degree`` is not ``None``, the terms of the series of degree greater than ``degree`` are truncated first. If ``degree`` is ``None`` and the series is not a polynomial or a Laurent polynomial, a @@ -2772,14 +2106,15 @@ def polynomial(self, degree=None, name=None): sage: M = L(lambda n: n^2, 0) sage: M.polynomial(5) 25*z^5 + 16*z^4 + 9*z^3 + 4*z^2 + z + sage: f = 1/(1 + z) sage: f.polynomial() Traceback (most recent call last): ... ValueError: not a polynomial + sage: L.zero().polynomial() 0 - """ S = self.parent() @@ -2816,7 +2151,6 @@ def _format_series(self, formatter, format_strings=False): sage: f = 1 / (2 - z^2) sage: f._format_series(ascii_art, True) 1/2 + 1/4*z^2 + 1/8*z^4 + 1/16*z^6 + O(z^7) - """ P = self.parent() R = P._laurent_poly_ring @@ -2846,7 +2180,7 @@ def _format_series(self, formatter, format_strings=False): return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) -class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries, LazySpecialFunctions): +class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries): r""" A Taylor series where the coefficients are computed lazily. @@ -2868,52 +2202,54 @@ class LazyTaylorSeries(LazySequencesModuleElement, LazyCauchyProductSeries, Lazy True """ def __call__(self, *g): - r""" - Return the composition of ``self`` with ``g``. - + r"""Return the composition of ``self`` with ``g``. + The arity of ``self`` must be equal to the number of arguments provided. + Given two Taylor Series `f` and `g` over the same base ring, the composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + - `g = 0` and `val(f) >= 0`, - `g` is non-zero and `f` has only finitely many non-zero coefficients, - `g` is non-zero and `val(g) > 0`. - + INPUT: - + - ``g`` -- other series, all of the same parent. - + EXAMPLES:: - + sage: L. = LazyTaylorSeriesRing(QQ) sage: M. = LazyTaylorSeriesRing(ZZ) sage: g1 = 1/(1-x); g2 = x+y^2 sage: p = a^2 + b + 1 sage: p(g1, g2) - g1^2 - g2 - 1 O(x,y,z)^7 + sage: L. = LazyTaylorSeriesRing(QQ) sage: M. = LazyTaylorSeriesRing(QQ) - + The number of mappings from a set with `m` elements to a set with `n` elements:: - + sage: Ea = M(lambda n: 1/factorial(n)) sage: Ex = L(lambda n: 1/factorial(n)*x^n) sage: Ea(Ex*y)[5] 1/24*x^4*y + 2/3*x^3*y^2 + 3/4*x^2*y^3 + 1/6*x*y^4 + 1/120*y^5 - + So, there are `3! 2! 2/3 = 8` mappings from a three element set to a two element set. - + TESTS:: - + sage: L. = LazyTaylorSeriesRing(ZZ) sage: f = 1/(1-x-y) sage: f(f) Traceback (most recent call last): ... ValueError: arity of must be equal to the number of arguments provided - + """ if len(g) != len(self.parent().variable_names()): raise ValueError("arity of must be equal to the number of arguments provided") @@ -2948,13 +2284,13 @@ def coefficient(n): def change_ring(self, ring): """ Return this series with coefficients converted to elements of ``ring``. - + INPUT: - + - ``ring`` -- a ring - + EXAMPLES:: - + sage: L. = LazyTaylorSeriesRing(ZZ) sage: s = 2 + z sage: t = s.change_ring(QQ) @@ -2962,7 +2298,7 @@ def change_ring(self, ring): 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) sage: t.parent() Lazy Taylor Series Ring in z over Rational Field - + """ from .lazy_laurent_series_ring import LazyTaylorSeriesRing Q = LazyTaylorSeriesRing(ring, names=self.parent().variable_names()) @@ -2971,17 +2307,17 @@ def change_ring(self, ring): def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. - + TESTS:: - + sage: L. = LazyTaylorSeriesRing(QQ) sage: f = 1 / (2 - x^2 + y) sage: f._format_series(repr) '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' + sage: f = (2 - x^2 + y) sage: f._format_series(repr) '2 + y + (-x^2)' - """ P = self.parent() cs = self._coeff_stream @@ -3038,42 +2374,42 @@ def parenthesize(m): return poly -class LazyDirichletSeries(LazySequencesModuleElement, LazySpecialFunctions): +class LazyDirichletSeries(LazySequencesModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. - + INPUT: - + - ``parent`` -- The base ring for the series + - ``coeff_stream`` -- The auxiliary class that handles the coefficient stream - + EXAMPLES:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: f = L(constant=1)^2; f 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... sage: f.coefficient(100) == number_of_divisors(100) True - + Lazy Dirichlet series is picklable:: - + sage: g = loads(dumps(f)) sage: g 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... sage: g == f True - """ def _mul_(self, other): """ Return the product of this series with ``other``. - + INPUT: - + - ``other`` -- other series - + TESTS:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L(constant=1); g 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) @@ -3081,6 +2417,7 @@ def _mul_(self, other): 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: [number_of_divisors(n) for n in range(1, 8)] [1, 2, 2, 3, 2, 4, 2] + sage: mu = L(moebius); mu 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) sage: g*mu @@ -3089,7 +2426,6 @@ def _mul_(self, other): True sage: mu * L.one() is mu True - """ P = self.parent() left = self._coeff_stream @@ -3109,16 +2445,16 @@ def _mul_(self, other): def __invert__(self): """ Return the multiplicative inverse of the element. - + TESTS:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) sage: ~L(constant=1) - L(moebius) O(1/(8^z)) sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) sage: ~L(constant=1) - L(moebius) O(1/(8^z)) - + """ P = self.parent() return P.element_class(P, CoefficientStream_dirichlet_inv(self._coeff_stream)) @@ -3126,15 +2462,14 @@ def __invert__(self): def change_ring(self, ring): """ Return this series with coefficients converted to elements of ``ring``. - + INPUT: - + - ``ring`` -- a ring - + TESTS:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) - """ from .lazy_laurent_series_ring import LazyDirichletSeriesRing Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) @@ -3143,15 +2478,14 @@ def change_ring(self, ring): def __pow__(self, n): """ Return the ``n``-th power of the series. - + INPUT: - + - ``n`` -- integer, the power to which to raise the series - + TESTS:: - + sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ if n == 0: return self.parent().one() @@ -3161,15 +2495,17 @@ def __pow__(self, n): def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. - + TESTS:: - + sage: L = LazyDirichletSeriesRing(QQ, "s") sage: f = L(constant=1) sage: f._format_series(repr) '1 + 1/(2^s) + 1/(3^s) + O(1/(4^s))' + sage: L([1,-1,1])._format_series(repr) '1 - 1/(2^s) + 1/(3^s)' + sage: L([1,-1,1])._format_series(ascii_art) -s -s 1 + -2 + 3 From b3327282df6f49d2367c5703a9b72433f5fe06ce Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 11 Aug 2021 20:26:15 +0200 Subject: [PATCH 074/355] fix and document series reversion --- src/sage/rings/lazy_laurent_series.py | 90 +++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 182f57fe3da..a395c91f257 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2034,30 +2034,96 @@ def revert(self): r""" Return the compositional inverse of ``self``. + Given a Laurent Series `f`. the compositional inverse is a + Laurent Series `g` over the same base ring, such that + `(f \circ g)(z) = f(g(z)) = z`. + + The compositional inverse exists if and only if: + + - `val(f) = 1', or + + - `f = a + b z` with `a b \neq 0`, or + + - `f = a/z' with `a \neq 0` + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(ZZ) sage: z.revert() z + O(z^8) sage: (1/z).revert() - z^-1 + O(z^6) + z^-1 sage: (z-z^2).revert() z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: s = L(lambda n: 1 if n == 1 else 0, valuation=1); s + z + O(z^8) + sage: s.revert() + z + O(z^8) + + sage: (2+3*z).revert() + -2/3 + 1/3*z + + sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s + 2 + 3*z + O(z^7) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: cannot determine whether the compositional inverse exists + + We look at some cases where the compositional inverse does not exist.: + + `f = 0`:: + + sage: L(0).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: (z - z).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + `val(f) ! = 1 and f(0) * f(1) = 0`:: + + sage: (z^2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: L(1).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + """ P = self.parent() - z = P.gen() - if self._coeff_stream._approximate_order == 1: - g = self - else: - g = self * z**(1 - self._coeff_stream._approximate_order) - f = P(None, valuation=1) - f.define(z/((g/z)(f))) - if self._coeff_stream._approximate_order == 1: - return f - else: - return f / z**(1 - self._coeff_stream._approximate_order) + if self.valuation() == 1: + z = P.gen() + g = P(None, valuation=1) + g.define(z/((self/z)(g))) + return g + if self.valuation() not in [-1, 0]: + raise ValueError("compositional inverse does not exist") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, CoefficientStream_exact): + if (coeff_stream.order() == 0 + and coeff_stream._degree == 2): + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = CoefficientStream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + if (coeff_stream.order() == -1 + and coeff_stream._degree == 0): + return self + raise ValueError("compositional inverse does not exist") + raise ValueError("cannot determine whether the compositional inverse exists") def approximate_series(self, prec, name=None): """ From dc1acfd7e1f2d5770c7b4179382bf220c3b876fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 11 Aug 2021 18:01:28 -0700 Subject: [PATCH 075/355] .github/workflows/tox-{optional,experimental}.yml: Remove ubuntu-trusty-gcc_spkg, linuxmint-17-gcc_spkg; restore centos-7-i386-gcc_spkg --- .github/workflows/tox-experimental.yml | 3 ++- .github/workflows/tox-optional.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tox-experimental.yml b/.github/workflows/tox-experimental.yml index 862f00476e9..7bf186ace20 100644 --- a/.github/workflows/tox-experimental.yml +++ b/.github/workflows/tox-experimental.yml @@ -40,7 +40,8 @@ jobs: matrix: # This list is different from the one in tox.yml: # Trac #31526 switches gcc 4.x-based distributions to using the gcc_spkg configuration factor - tox_system_factor: [ubuntu-trusty-gcc_spkg, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17-gcc_spkg, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-gcc_spkg] + # Trac #32281 removes gcc 4.x-based distributions whose binutils are unusable + tox_system_factor: [ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-gcc_spkg] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: diff --git a/.github/workflows/tox-optional.yml b/.github/workflows/tox-optional.yml index 279c6d23feb..9ffc60010d3 100644 --- a/.github/workflows/tox-optional.yml +++ b/.github/workflows/tox-optional.yml @@ -40,7 +40,8 @@ jobs: matrix: # This list is different from the one in tox.yml: # Trac #31526 switches gcc 4.x-based distributions to using the gcc_spkg configuration factor - tox_system_factor: [ubuntu-trusty-gcc_spkg, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17-gcc_spkg, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-gcc_spkg] + # Trac #32281 removes gcc 4.x-based distributions whose binutils are unusable + tox_system_factor: [ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-gcc_spkg] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: From d990cc403b4be93a1bc0104cf7ab29b7d91808e1 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 11:22:09 +0200 Subject: [PATCH 076/355] correct parent of left in special functions --- src/sage/rings/lazy_laurent_series.py | 101 ++++++++++++--------- src/sage/rings/lazy_laurent_series_ring.py | 2 + 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 9072c10c21d..7922583741a 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1227,11 +1227,16 @@ def exp(self): sage: exp(x+y)[4].factor() (1/24) * (x + y)^4 + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: exp(z)[5] - exp(x).series(x).coefficient(x, 5) + 0 + """ from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.rings.rational_field import QQ from sage.functions.other import factorial - P = LazyLaurentSeriesRing(QQ, "z", sparse=self.parent()._sparse) + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/factorial(n), valuation=0)(self) def hypergeometric(self, a, b): @@ -1263,18 +1268,15 @@ def hypergeometric(self, a, b): 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) """ + from .lazy_laurent_series_ring import LazyLaurentSeriesRing from sage.functions.other import factorial from sage.arith.misc import rising_factorial - if not isinstance(a, (list, tuple)): - a = [a] - if not isinstance(b, (list, tuple)): - b = [b] + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def coeff(n, c): num = 1 for term in range(len(c)): num *= rising_factorial(c[term], n) return num - P = self.parent() return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) def log(self): @@ -1284,22 +1286,27 @@ def log(self): EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) + sage: log(1/(1-z)) + z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) + sage: L. = LazyTaylorSeriesRing(QQ) + sage: log((1 + x/(1-y)))[4] + y^3*x - 3/2*y^2*x^2 + y*x^3 - 1/4*x^4 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: log(1+z)[5] - log(1+x).series(x).coefficient(x, 5) + 0 + sage: log(z) - z - 1/2*z^2 + 1/3*z^3 - 1/4*z^4 + 1/5*z^5 - 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: log(z^2) - z^2 - 1/2*z^4 + 1/3*z^6 - 1/4*z^8 + O(z^9) - sage: log(z + z^2) - z + 1/2*z^2 - 2/3*z^3 + 1/4*z^4 + 1/5*z^5 - 1/3*z^6 + 1/7*z^7 + O(z^8) - sage: log(-z) - -z - 1/2*z^2 - 1/3*z^3 - 1/4*z^4 - 1/5*z^5 - 1/6*z^6 - 1/7*z^7 + O(z^8) - sage: log(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series """ - P = self.parent() - return P(lambda n: ((-1) ** (n + 1))/n, 1)(self) + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + return P(lambda n: ((-1) ** (n + 1))/n, 1)(self-1) def a_pow_z(self, a): r""" @@ -1333,8 +1340,8 @@ def a_pow_z(self, a): """ from sage.functions.log import log from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: log(a) ** (n)/factorial(n) if n else 1, 0)(self) ## Trigonometric functions @@ -1361,7 +1368,8 @@ def sin(self): """ from sage.functions.other import factorial - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: (n % 2)/factorial(n) if n % 4 == 1 else -(n % 2)/factorial(n), 0)(self) def cos(self): @@ -1386,7 +1394,8 @@ def cos(self): """ from sage.functions.other import factorial - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/factorial(n) if n % 4 == 0 else (n % 2 - 1)/factorial(n), 0)(self) def tan(self): @@ -1509,8 +1518,8 @@ def arcsin(self): """ from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) if n % 2 else ZZ.zero(), 0)(self) def arccos(self): @@ -1533,7 +1542,8 @@ def arccos(self): """ from sage.symbolic.constants import pi - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(pi/2) - self.arcsin() def arctan(self): @@ -1557,7 +1567,8 @@ def arctan(self): ValueError: can only compose with a positive valuation series """ - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) def arccot(self): @@ -1581,9 +1592,9 @@ def arccot(self): ValueError: can only compose with a positive valuation series """ - from sage.symbolic.constants import pi - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(pi/2) - self.arctan() ## Hyerbolic functions @@ -1611,8 +1622,8 @@ def sinh(self): """ from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/factorial(n) if n % 2 else ZZ.zero(), 0)(self) def cosh(self): @@ -1636,10 +1647,9 @@ def cosh(self): ValueError: can only compose with a positive valuation series """ - from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) def tanh(self): @@ -1670,8 +1680,8 @@ def tanh(self): from sage.functions.other import factorial from sage.arith.misc import bernoulli from sage.rings.rational_field import QQ - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: (QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) * (-1 + (4 ** ((n + 1)/2))))/factorial(n + 1) if n % 2 else ZZ.zero(), 0)(self) def coth(self): @@ -1699,8 +1709,8 @@ def coth(self): """ from sage.functions.other import factorial from sage.arith.misc import bernoulli - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) def sech(self): @@ -1726,8 +1736,8 @@ def sech(self): """ from sage.functions.other import factorial from sage.combinat.combinat import euler_number - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) def csch(self): @@ -1755,8 +1765,8 @@ def csch(self): """ from sage.functions.other import factorial from sage.arith.misc import bernoulli - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) ## Inverse hyperbolic functions @@ -1783,8 +1793,8 @@ def asinh(self): """ from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: ZZ.zero() if n % 2 == 0 else (((-1) ** ((n - 1)/2)) * factorial(n - 1))/(4 ** ((n - 1)/2) * (factorial((n - 1)/2) ** 2) * n), 0)(self) def atanh(self): @@ -1808,7 +1818,8 @@ def atanh(self): ValueError: can only compose with a positive valuation series """ - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) def acosh(self): @@ -1833,8 +1844,8 @@ def acosh(self): """ from sage.functions.other import factorial - - P = self.parent() + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index daea58aebf0..1d865c7d1d0 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -521,6 +521,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No order=x.valuation(), constant=constant, degree=degree) return self.element_class(self, coeff_stream) + # we must not convert, say, a Dirichlet series into a Laurent series + # if isinstance(x, LazyLaurentSeries): if isinstance(x, LazyModuleElement): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy From 8a79ab5d524359eb3ea51b61a81ef01862ab9878 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 11:46:41 +0200 Subject: [PATCH 077/355] fix log doctest --- src/sage/rings/lazy_laurent_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 7922583741a..c5188de0148 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1290,7 +1290,7 @@ def log(self): z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) sage: L. = LazyTaylorSeriesRing(QQ) sage: log((1 + x/(1-y)))[4] - y^3*x - 3/2*y^2*x^2 + y*x^3 - 1/4*x^4 + -1/4*x^4 + x^3*y - 3/2*x^2*y^2 + x*y^3 TESTS:: From fe5d9cb234c4e505e0147fcfca8d6066cc037bea Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 15:10:39 +0200 Subject: [PATCH 078/355] fix special functions, at least with Taylor series --- src/sage/rings/lazy_laurent_series.py | 694 ++++++++++++++------------ 1 file changed, 381 insertions(+), 313 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index c5188de0148..ebd2116caea 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1,4 +1,4 @@ -r""" +""" Lazy Laurent Series A lazy Laurent series is a Laurent series whose coefficients are @@ -1203,6 +1203,34 @@ def _neg_(self): return P.element_class(P, coeff_stream._series) return P.element_class(P, CoefficientStream_neg(coeff_stream)) + def is_constant(self): + """ + Return ``True`` if ``self`` is a constant. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: z.is_constant() + False + sage: L(1).is_constant() + True + sage: L(0).is_constant() + True + + sage: L. = LazyTaylorSeriesRing(SR) + sage: x.is_constant() + False + sage: L(pi).is_constant() + True + + """ + coeff_stream = self._coeff_stream + return (isinstance(coeff_stream, CoefficientStream_zero) + or (isinstance(coeff_stream, CoefficientStream_exact) + and not coeff_stream._constant + and len(coeff_stream._initial_coefficients) == 1 + and coeff_stream.order() == 0)) + # === special functions === def exp(self): @@ -1227,76 +1255,53 @@ def exp(self): sage: exp(x+y)[4].factor() (1/24) * (x + y)^4 - TESTS:: - - sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") - sage: exp(z)[5] - exp(x).series(x).coefficient(x, 5) - 0 - - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.functions.other import factorial - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/factorial(n), valuation=0)(self) - - def hypergeometric(self, a, b): - r""" - Return the `{}_{p}F_{q}`-hypergeometric function - `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. - - INPUT:: + sage: L. = LazyTaylorSeriesRing(SR) + sage: exp(x/(1-y)).finite_part(3) + 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 - - ``a`` -- the first parameter of the hypergeometric function - - ``b`` -- the second parameter of the hypergeometric function + sage: L. = LazyLaurentSeriesRing(SR); a = var("a") + sage: exp(L(a)) + e^a - EXAMPLES:: + TESTS:: - sage: L. = LazyLaurentSeriesRing(QQ) - sage: hypergeometric(z, [1, 1], [1]) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: hypergeometric(z, [1, 2], [1]) - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: hypergeometric(z, 1, 1) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [4]) - 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: hypergeometric(z, (1, 1), [1, 1]) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: exp(z)[0:6] == exp(x).series(x, 6).coefficients(sparse=False) + True """ + # if exp(self) happens to be in the base ring we are fine, too + from sage.functions.log import exp + if self.is_constant(): + return self.parent()(exp(self[0])) from .lazy_laurent_series_ring import LazyLaurentSeriesRing from sage.functions.other import factorial - from sage.arith.misc import rising_factorial P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - def coeff(n, c): - num = 1 - for term in range(len(c)): - num *= rising_factorial(c[term], n) - return num - return P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(n)), 0)(self) + f = P(lambda n: 1/factorial(ZZ(n)), valuation=0) + return f(self) def log(self): r""" - Return the series for the natural logarithm of ``1 + self``. + Return the series for the natural logarithm of ``self``. EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) sage: log(1/(1-z)) z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) - sage: log((1 + x/(1-y)))[4] - -1/4*x^4 + x^3*y - 3/2*x^2*y^2 + x*y^3 + sage: L. = LazyTaylorSeriesRing(SR) + sage: log((1 + x/(1-y))).finite_part(3) + 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x + + sage: L. = LazyLaurentSeriesRing(SR); a = var("a") + sage: log(L(a)) + log(a) TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") - sage: log(1+z)[5] - log(1+x).series(x).coefficient(x, 5) - 0 + sage: log(1+z)[0:6] == log(1+x).series(x, 6).coefficients(sparse=False) + True sage: log(z) Traceback (most recent call last): @@ -1304,47 +1309,16 @@ def log(self): ValueError: can only compose with a positive valuation series """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: ((-1) ** (n + 1))/n, 1)(self-1) - - def a_pow_z(self, a): - r""" - Return the series expansion for `a^{self}`. - - INPUT: - - - ``a`` - The base of the series - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(SR) - sage: var('a b c') - (a, b, c) - sage: from sage.symbolic.constants import e - sage: a_pow_z(z, a) - 1 + log(a)*z + 1/2*log(a)^2*z^2 + 1/6*log(a)^3*z^3 + 1/24*log(a)^4*z^4 + 1/120*log(a)^5*z^5 + 1/720*log(a)^6*z^6 + O(z^7) - sage: a_pow_z(z^2, b) - 1 + log(b)*z^2 + 1/2*log(b)^2*z^4 + 1/6*log(b)^3*z^6 + O(z^7) - sage: a_pow_z(z + z^2, c) - 1 + log(c)*z + (1/2*log(c)^2 + log(c))*z^2 + (1/6*log(c)^3 + log(c)^2)*z^3 + (1/24*log(c)^4 + 1/2*log(c)^3 + 1/2*log(c)^2)*z^4 + (1/120*log(c)^5 + 1/6*log(c)^4 + 1/2*log(c)^3)*z^5 + (1/720*log(c)^6 + 1/24*log(c)^5 + 1/4*log(c)^4 + 1/6*log(c)^3)*z^6 + O(z^7) - sage: a_pow_z(z, e) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: a_pow_z(z, 2) - 1 + log(2)*z + 1/2*log(2)^2*z^2 + 1/6*log(2)^3*z^3 + 1/24*log(2)^4*z^4 + 1/120*log(2)^5*z^5 + 1/720*log(2)^6*z^6 + O(z^7) - sage: a_pow_z(1 + z, c) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series - - """ + # if log(self) happens to be in the base ring we are fine, too from sage.functions.log import log - from sage.functions.other import factorial + if self.is_constant(): + return self.parent()(log(self[0])) from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: log(a) ** (n)/factorial(n) if n else 1, 0)(self) + f = P(lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) + return f(self-1) -## Trigonometric functions + # trigonometric functions def sin(self): r""" @@ -1354,23 +1328,30 @@ def sin(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: sin(z) - z - 1/6*z^3 + 1/120*z^5 + O(z^7) - sage: sin(z^2) - z^2 - 1/6*z^6 + O(z^7) - sage: sin(z + z^2) - z + z^2 - 1/6*z^3 - 1/2*z^4 - 59/120*z^5 - 1/8*z^6 + O(z^7) - sage: sin(0) - 0 + z - 1/6*z^3 + 1/120*z^5 - 1/5040*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: sin(x/(1-y)).finite_part(3) + (-1/6)*x^3 + x*y^2 + x*y + x + sage: sin(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: sin(z)[0:6] == sin(x).series(x, 6).coefficients(sparse=False) + True + """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: (n % 2)/factorial(n) if n % 4 == 1 else -(n % 2)/factorial(n), 0)(self) + f = P(lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)), + valuation=1) + return f(self) def cos(self): r""" @@ -1381,22 +1362,24 @@ def cos(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: cos(z) 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - sage: cos(z^2) - 1 - 1/2*z^4 + O(z^7) - sage: cos(z + z^2) - 1 - 1/2*z^2 - z^3 - 11/24*z^4 + 1/6*z^5 + 179/720*z^6 + O(z^7) - sage: cos(0) - 1 - sage: cos(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: cos(x/(1-y)).finite_part(4) + 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: cos(z)[0:6] == cos(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/factorial(n) if n % 4 == 0 else (n % 2 - 1)/factorial(n), 0)(self) + f = P(lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)), + valuation=0) + return f(self) def tan(self): r""" @@ -1406,17 +1389,17 @@ def tan(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: tan(z) - z + 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tan(z^2) - z^2 + 1/3*z^6 + O(z^7) - sage: tan(z + z^2) - z + z^2 + 1/3*z^3 + z^4 + 17/15*z^5 + z^6 + O(z^7) - sage: tan(0) - 0 - sage: tan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: tan(x/(1-y)).finite_part(5) + 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: tan(z)[0:6] == tan(x).series(x, 6).coefficients(sparse=False) + True """ return self.sin()/self.cos() @@ -1430,16 +1413,16 @@ def cot(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: cot(z) z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) - sage: cot(z^2) - z^-2 - 1/3*z^2 + O(z^5) - sage: cot(z + z^2) - z^-1 - 1 + 2/3*z - 4/3*z^2 + 44/45*z^3 - 16/15*z^4 + 176/189*z^5 + O(z^6) - sage: cot(0) - Infinity - sage: cot(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyLaurentSeriesRing(SR) + sage: cot(x/(1-x)).finite_part(4) + x^-1 - 1 - 1/3*x - 1/3*x^2 - 16/45*x^3 - 2/5*x^4 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: cot(z)[0:6] == cot(x).series(x, 6).coefficients(sparse=False) + True """ return ~ self.tan() @@ -1453,16 +1436,16 @@ def csc(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: csc(z) z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) - sage: csc(0) - Infinity - sage: csc(z^2) - z^-2 + 1/6*z^2 + O(z^5) - sage: csc(z + z^2) - z^-1 - 1 + 7/6*z - 5/6*z^2 + 367/360*z^3 - 113/120*z^4 + 16033/15120*z^5 + O(z^6) - sage: csc(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyLaurentSeriesRing(SR) + sage: csc(x/(1-x)).finite_part(4) + x^-1 - 1 + 1/6*x + 1/6*x^2 + 67/360*x^3 + 9/40*x^4 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: (z*csc(z))[0:6] == (x*csc(x)).series(x, 6).coefficients(sparse=False) + True """ return ~ self.sin() @@ -1476,21 +1459,21 @@ def sec(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: sec(z) 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: sec(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: sec(z + z^2) - 1 + 1/2*z^2 + z^3 + 17/24*z^4 + 5/6*z^5 + 961/720*z^6 + O(z^7) - sage: sec(0) - 1 - sage: sec(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: sec(x/(1-y)).finite_part(4) + 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: sec(z)[0:6] == sec(x).series(x, 6).coefficients(sparse=False) + True """ return ~ self.cos() -## Inverse trigonometric functions + # inverse trigonometric functions def arcsin(self): r""" @@ -1500,27 +1483,28 @@ def arcsin(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: arcsin(z) - z + 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: arcsin(z)[7] - 5/112 - sage: arcsin(z) - z + 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: arcsin(z^2) - z^2 + 1/6*z^6 + O(z^7) - sage: arcsin(z + z^2) - z + z^2 + 1/6*z^3 + 1/2*z^4 + 23/40*z^5 + 13/24*z^6 + O(z^7) - sage: arcsin(0) - 0 - sage: arcsin(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: asin(x/(1-y)) + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: asin(z)[0:6] == asin(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) if n % 2 else ZZ.zero(), 0)(self) + def f(n): + n = ZZ(n) + if n % 2: + return factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) + return ZZ.zero() + return P(f, valuation=1)(self) def arccos(self): r""" @@ -1531,20 +1515,20 @@ def arccos(self): sage: L. = LazyLaurentSeriesRing(RR) sage: arccos(z) 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) - sage: arccos(z^2) - 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 - 0.166666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccos(z + z^2) - 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 - 0.166666666666667*z^3 - 0.500000000000000*z^4 - 0.575000000000000*z^5 - 0.541666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccos(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: arccos(x/(1-y)) + 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: acos(z)[0:6] == acos(x).series(x, 6).coefficients(sparse=False) + True """ from sage.symbolic.constants import pi - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(pi/2) - self.arcsin() + return self.parent()(pi/2) - self.arcsin() def arctan(self): r""" @@ -1554,22 +1538,29 @@ def arctan(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: arctan(z) - z - 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: arctan(z^2) - z^2 - 1/3*z^6 + O(z^7) - sage: arctan(z + z^2) - z + z^2 - 1/3*z^3 - z^4 - 4/5*z^5 + 2/3*z^6 + O(z^7) - sage: arctan(0) - 0 - sage: arctan(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: atan(x/(1-y)) + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: atan(z)[0:6] == atan(x).series(x, 6).coefficients(sparse=False) + True """ from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/n if n % 4 == 1 else ZZ.zero() if n % 2 == 0 else -1/n, 0)(self) + def f(n): + n = ZZ(n) + if n % 4 == 1: + return 1/n + if n % 2 == 0: + return ZZ.zero() + return -1/n + return P(f, valuation=1)(self) def arccot(self): r""" @@ -1580,24 +1571,22 @@ def arccot(self): sage: L. = LazyLaurentSeriesRing(RR) sage: arccot(z) 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) - sage: arccot(z^2) - 1.57079632679490 + 0.000000000000000*z - 1.00000000000000*z^2 + 0.000000000000000*z^3 + 0.000000000000000*z^4 + 0.000000000000000*z^5 + 0.333333333333333*z^6 + O(1.00000000000000*z^7) - sage: arccot(z + z^2) - 1.57079632679490 - 1.00000000000000*z - 1.00000000000000*z^2 + 0.333333333333333*z^3 + 1.00000000000000*z^4 + 0.800000000000000*z^5 - 0.666666666666667*z^6 + O(1.00000000000000*z^7) - sage: arccot(L(0)) - 1.57079632679490 - sage: arccot(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: acot(x/(1-y)) + 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: acot(z)[0:6] == acot(x).series(x, 6).coefficients(sparse=False) + True """ from sage.symbolic.constants import pi - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(pi/2) - self.arctan() + return self.parent()(pi/2) - self.arctan() -## Hyerbolic functions + # hyperbolic functions def sinh(self): r""" @@ -1607,24 +1596,25 @@ def sinh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: sinh(z) - z + 1/6*z^3 + 1/120*z^5 + O(z^7) - sage: sinh(z^2) - z^2 + 1/6*z^6 + O(z^7) - sage: sinh(z + z^2) - z + z^2 + 1/6*z^3 + 1/2*z^4 + 61/120*z^5 + 5/24*z^6 + O(z^7) - sage: sinh(0) - 0 - sage: sinh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) - """ + sage: L. = LazyTaylorSeriesRing(SR) + sage: sinh(x/(1-y)) + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: sinh(z)[0:6] == sinh(x).series(x, 6).coefficients(sparse=False) + True + """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/factorial(n) if n % 2 else ZZ.zero(), 0)(self) + f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), + valuation=1) + return f(self) def cosh(self): r""" @@ -1635,22 +1625,24 @@ def cosh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: cosh(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: cosh(z + z^2) - 1 + 1/2*z^2 + z^3 + 13/24*z^4 + 1/6*z^5 + 181/720*z^6 + O(z^7) - sage: cosh(0) - 1 - sage: cosh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: cosh(x/(1-y)) + 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: cosh(z)[0:6] == cosh(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: ZZ.zero() if n % 2 else 1/factorial(n), 0)(self) + f = P(lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), + valuation=0) + return f(self) def tanh(self): r""" @@ -1660,29 +1652,30 @@ def tanh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: tanh(z) - z - 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tanh(z)[7] - -17/315 - sage: tanh(z) - z - 1/3*z^3 + 2/15*z^5 + O(z^7) - sage: tanh(z^2) - z^2 - 1/3*z^6 + O(z^7) - sage: tanh(z + z^2) - z + z^2 - 1/3*z^3 - z^4 - 13/15*z^5 + 1/3*z^6 + O(z^7) - sage: tanh(0) - 0 - sage: tanh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: tanh(x/(1-y)) + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: tanh(z)[0:6] == tanh(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from sage.arith.misc import bernoulli - from sage.rings.rational_field import QQ from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: (QQ((bernoulli(n + 1)) * ((4) ** ((n + 1)/2))) * (-1 + (4 ** ((n + 1)/2))))/factorial(n + 1) if n % 2 else ZZ.zero(), 0)(self) + def f(n): + n = ZZ(n) + if n % 2: + h = 4 ** ((n + 1) // 2) + return bernoulli(n + 1) * h * (h -1) / factorial(n + 1) + return ZZ.zero() + return P(f, valuation=1)(self) def coth(self): r""" @@ -1693,25 +1686,27 @@ def coth(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: coth(z) z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) - sage: coth(z^2) - z^-2 + 1/3*z^2 + O(z^5) + sage: coth(z + z^2) z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) - sage: coth(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: coth(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: coth(z)[0:6] == coth(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from sage.arith.misc import bernoulli from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) + def f(n): + n = ZZ(n) + if n % 2: + return ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) + return ZZ.zero() + return P(f, valuation=-1)(self) def sech(self): r""" @@ -1722,23 +1717,28 @@ def sech(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: sech(z) 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: sech(z^2) - 1 - 1/2*z^4 + O(z^7) - sage: sech(z + z^2) - 1 - 1/2*z^2 - z^3 - 7/24*z^4 + 5/6*z^5 + 839/720*z^6 + O(z^7) - sage: sech(L(0)) - 1 - sage: sech(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: sech(x/(1-y)) + 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: sech(z)[0:6] == sech(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from sage.combinat.combinat import euler_number from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: euler_number(n)/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) + def f(n): + n = ZZ(n) + if n % 2: + return ZZ.zero() + return euler_number(n)/factorial(n) + return P(f, valuation=0)(self) def csch(self): r""" @@ -1749,27 +1749,30 @@ def csch(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: csch(z) z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) - sage: csch(z^2) - z^-2 - 1/6*z^2 + O(z^5) - sage: csch(z + z^2) - z^-1 - 1 + 5/6*z - 7/6*z^2 + 367/360*z^3 - 113/120*z^4 + 15971/15120*z^5 + O(z^6) - sage: csch(L(0)) - Traceback (most recent call last): - ... - ZeroDivisionError: the valuation of the series must be nonnegative - sage: csch(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyLaurentSeriesRing(SR) + sage: csch(z/(1-z)) + z^-1 - 1 - 1/6*z - 1/6*z^2 - 53/360*z^3 - 13/120*z^4 - 787/15120*z^5 + O(z^6) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: csch(z)[0:6] == csch(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from sage.arith.misc import bernoulli from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: (2 * (1 - 2 ** n) * bernoulli(n + 1))/factorial(n + 1) if n % 2 else ZZ.zero(), -1)(self) + def f(n): + n = ZZ(n) + if n % 2: + return 2 * (1 - ZZ(2) ** n) * bernoulli(n + 1)/factorial(n + 1) + return ZZ.zero() + return P(f, valuation=-1)(self) -## Inverse hyperbolic functions + # inverse hyperbolic functions def asinh(self): r""" @@ -1779,23 +1782,29 @@ def asinh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: asinh(z) - z - 1/6*z^3 + 3/40*z^5 + O(z^7) - sage: asinh(z^2) - z^2 - 1/6*z^6 + O(z^7) - sage: asinh(z + z^2) - z + z^2 - 1/6*z^3 - 1/2*z^4 - 17/40*z^5 + 5/24*z^6 + O(z^7) - sage: asinh(L(0)) - 0 - sage: asinh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: asinh(x/(1-y)) + x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: asinh(z)[0:6] == asinh(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: ZZ.zero() if n % 2 == 0 else (((-1) ** ((n - 1)/2)) * factorial(n - 1))/(4 ** ((n - 1)/2) * (factorial((n - 1)/2) ** 2) * n), 0)(self) + def f(n): + n = ZZ(n) + if n % 2: + h = (n - 1) // 2 + return ZZ(-1) ** h * factorial(n - 1)/(ZZ(4) ** h * factorial(h) ** 2 * n) + return ZZ.zero() + return P(f, valuation=1)(self) def atanh(self): r""" @@ -1806,21 +1815,21 @@ def atanh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: atanh(z) z + 1/3*z^3 + 1/5*z^5 + O(z^7) - sage: atanh(z^2) - z^2 + 1/3*z^6 + O(z^7) - sage: atanh(L(0)) - 0 - sage: atanh(z + z^2) - z + z^2 + 1/3*z^3 + z^4 + 6/5*z^5 + 4/3*z^6 + O(z^7) - sage: atanh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: atanh(x/(1-y)) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: atanh(z)[0:6] == atanh(x).series(x, 6).coefficients(sparse=False) + True """ from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/n if n % 2 else ZZ.zero(), 0)(self) + f = P(lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) + return f(self) def acosh(self): r""" @@ -1831,22 +1840,64 @@ def acosh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: acosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: acosh(z^2) - 1 + 1/2*z^4 + O(z^7) - sage: acosh(z + z^2) - 1 + 1/2*z^2 + z^3 + 13/24*z^4 + 1/6*z^5 + 181/720*z^6 + O(z^7) - sage: acosh(L(0)) - 1 - sage: acosh(1 + z) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(SR) + sage: acosh(x/(1-y)) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: acosh(z)[0:6] == acosh(x).series(x, 6).coefficients(sparse=False) + True """ from sage.functions.other import factorial from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - return P(lambda n: 1/factorial(n) if n % 2 == 0 else ZZ.zero(), 0)(self) + f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 == 0 else ZZ.zero(), valuation=0) + return f(self) + + def hypergeometric(self, a, b): + r""" + Return the `{}_{p}F_{q}`-hypergeometric function + `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. + + INPUT:: + + - ``a`` -- the first parameter of the hypergeometric function + - ``b`` -- the second parameter of the hypergeometric function + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: hypergeometric(z, [1, 1], [1]) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: hypergeometric(z, [1, 2], [1]) + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: hypergeometric(z, 1, 1) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: hypergeometric(z, [2, 3], [4]) + 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) + sage: hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: hypergeometric(z, [2, 3], [2]) + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: hypergeometric(z, (1, 1), [1, 1]) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + + """ + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from sage.functions.other import factorial + from sage.arith.misc import rising_factorial + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def coeff(n, c): + num = 1 + for term in range(len(c)): + num *= rising_factorial(c[term], n) + return num + f = P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(ZZ(n))), + valuation=0) + return f(self) class LazyCauchyProductSeries(LazyModuleElement): @@ -2225,6 +2276,16 @@ def __pow__(self, n): 1 - 2*z + z^2 sage: (1 + z)^2 1 + 2*z + z^2 + + We also support the general case:: + + sage: L. = LazyLaurentSeriesRing(SR); a = var("a") + sage: a^z + 1 + log(a)*z + 1/2*log(a)^2*z^2 + 1/6*log(a)^3*z^3 + 1/24*log(a)^4*z^4 + 1/120*log(a)^5*z^5 + 1/720*log(a)^6*z^6 + O(z^7) + + sage: (1 + z)^(1 + z) + 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + """ if n == 0: return self.parent().one() @@ -2242,7 +2303,14 @@ def __pow__(self, n): # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, # constant=cs._constant, degree=deg, valuation=val)) - return generic_power(self, n) + if n in ZZ: + return generic_power(self, n) + + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from sage.functions.other import factorial + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + return exp(self.log() * n) class LazyLaurentSeries(LazyCauchyProductSeries): From 1daff82c075db271ee92e77fccd9afe29cebc800 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 17:47:46 +0200 Subject: [PATCH 079/355] add sqrt, remove arccosh, fix doctests for hypergeometric --- src/sage/rings/lazy_laurent_series.py | 121 +++++++------------------- 1 file changed, 31 insertions(+), 90 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index ebd2116caea..dd9934df5f9 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1203,34 +1203,6 @@ def _neg_(self): return P.element_class(P, coeff_stream._series) return P.element_class(P, CoefficientStream_neg(coeff_stream)) - def is_constant(self): - """ - Return ``True`` if ``self`` is a constant. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: z.is_constant() - False - sage: L(1).is_constant() - True - sage: L(0).is_constant() - True - - sage: L. = LazyTaylorSeriesRing(SR) - sage: x.is_constant() - False - sage: L(pi).is_constant() - True - - """ - coeff_stream = self._coeff_stream - return (isinstance(coeff_stream, CoefficientStream_zero) - or (isinstance(coeff_stream, CoefficientStream_exact) - and not coeff_stream._constant - and len(coeff_stream._initial_coefficients) == 1 - and coeff_stream.order() == 0)) - # === special functions === def exp(self): @@ -1259,10 +1231,6 @@ def exp(self): sage: exp(x/(1-y)).finite_part(3) 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 - sage: L. = LazyLaurentSeriesRing(SR); a = var("a") - sage: exp(L(a)) - e^a - TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") @@ -1270,10 +1238,6 @@ def exp(self): True """ - # if exp(self) happens to be in the base ring we are fine, too - from sage.functions.log import exp - if self.is_constant(): - return self.parent()(exp(self[0])) from .lazy_laurent_series_ring import LazyLaurentSeriesRing from sage.functions.other import factorial P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) @@ -1293,10 +1257,6 @@ def log(self): sage: log((1 + x/(1-y))).finite_part(3) 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x - sage: L. = LazyLaurentSeriesRing(SR); a = var("a") - sage: log(L(a)) - log(a) - TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") @@ -1309,10 +1269,6 @@ def log(self): ValueError: can only compose with a positive valuation series """ - # if log(self) happens to be in the base ring we are fine, too - from sage.functions.log import log - if self.is_constant(): - return self.parent()(log(self[0])) from .lazy_laurent_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) @@ -1774,7 +1730,7 @@ def f(n): # inverse hyperbolic functions - def asinh(self): + def arcsinh(self): r""" Return the inverse of the hyperbolic sine of ``self``. @@ -1806,7 +1762,7 @@ def f(n): return ZZ.zero() return P(f, valuation=1)(self) - def atanh(self): + def arctanh(self): r""" Return the inverse of the hyperbolic tangent of ``self``. @@ -1814,10 +1770,11 @@ def atanh(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: atanh(z) - z + 1/3*z^3 + 1/5*z^5 + O(z^7) + z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) sage: L. = LazyTaylorSeriesRing(SR) sage: atanh(x/(1-y)) + x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: @@ -1831,32 +1788,6 @@ def atanh(self): f = P(lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) return f(self) - def acosh(self): - r""" - Return the inverse of the hyperbolic tangent of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: acosh(z) - 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - - sage: L. = LazyTaylorSeriesRing(SR) - sage: acosh(x/(1-y)) - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(SR); x = var("x") - sage: acosh(z)[0:6] == acosh(x).series(x, 6).coefficients(sparse=False) - True - - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 == 0 else ZZ.zero(), valuation=0) - return f(self) - def hypergeometric(self, a, b): r""" Return the `{}_{p}F_{q}`-hypergeometric function @@ -1870,20 +1801,16 @@ def hypergeometric(self, a, b): EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) - sage: hypergeometric(z, [1, 1], [1]) + sage: z.hypergeometric([1, 1], [1]) 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: hypergeometric(z, [1, 2], [1]) - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: hypergeometric(z, 1, 1) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [4]) - 1 + 3/2*z + 9/5*z^2 + 2*z^3 + 15/7*z^4 + 9/4*z^5 + 7/3*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: hypergeometric(z, [2, 3], [2]) - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: hypergeometric(z, (1, 1), [1, 1]) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: z.hypergeometric([], []) - exp(z) + O(z^7) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: z.hypergeometric([1,1],[1])[0:6] == hypergeometric([1,1],[1], x).series(x, 6).coefficients(sparse=False) + True """ from .lazy_laurent_series_ring import LazyLaurentSeriesRing @@ -2279,10 +2206,7 @@ def __pow__(self, n): We also support the general case:: - sage: L. = LazyLaurentSeriesRing(SR); a = var("a") - sage: a^z - 1 + log(a)*z + 1/2*log(a)^2*z^2 + 1/6*log(a)^3*z^3 + 1/24*log(a)^4*z^4 + 1/120*log(a)^5*z^5 + 1/720*log(a)^6*z^6 + O(z^7) - + sage: L. = LazyLaurentSeriesRing(SR) sage: (1 + z)^(1 + z) 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) @@ -2312,6 +2236,23 @@ def __pow__(self, n): exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) return exp(self.log() * n) + def sqrt(self): + """ + Return ``self^(1/2)``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: sqrt(1+z) + 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: sqrt(1+x/(1-y)) + 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + O(x,y)^7 + + """ + return self ** (1/ZZ(2)) + class LazyLaurentSeries(LazyCauchyProductSeries): r""" From 17d86691e03bc8242da6de99e893e2762d44e158 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 17:54:16 +0200 Subject: [PATCH 080/355] start working on composition for Dirichlet --- .../data_structures/coefficient_stream.py | 10 +- src/sage/rings/lazy_laurent_series.py | 100 ++++++++++-------- src/sage/rings/lazy_laurent_series_ring.py | 2 +- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index 68769ac98da..a68c7f6b61c 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -1249,7 +1249,7 @@ def get_coefficient(self, n): return c -class CoefficientStream_dirichlet_inv(CoefficientStream_unary): +class CoefficientStream_dirichlet_inverse(CoefficientStream_unary): """ Operator for multiplicative inverse of the stream. @@ -1259,9 +1259,9 @@ class CoefficientStream_dirichlet_inv(CoefficientStream_unary): EXAMPLES:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_dirichlet_inv, CoefficientStream_coefficient_function) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_dirichlet_inverse, CoefficientStream_coefficient_function) sage: f = CoefficientStream_coefficient_function(lambda n: 1, ZZ, True, 1) - sage: g = CoefficientStream_dirichlet_inv(f) + sage: g = CoefficientStream_dirichlet_inverse(f) sage: [g[i] for i in range(10)] [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] sage: [moebius(i) for i in range(10)] @@ -1273,9 +1273,9 @@ def __init__(self, series): TESTS:: - sage: from sage.data_structures.coefficient_stream import (CoefficientStream_exact, CoefficientStream_dirichlet_inv) + sage: from sage.data_structures.coefficient_stream import (CoefficientStream_exact, CoefficientStream_dirichlet_inverse) sage: f = CoefficientStream_exact([0, 0], True, constant=1) - sage: g = CoefficientStream_dirichlet_inv(f) + sage: g = CoefficientStream_dirichlet_inverse(f) Traceback (most recent call last): ... AssertionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index a5b9f314adf..85740f0f99f 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -108,7 +108,7 @@ CoefficientStream_uninitialized, CoefficientStream_coefficient_function, CoefficientStream_dirichlet_convolution, - CoefficientStream_dirichlet_inv + CoefficientStream_dirichlet_inverse ) class LazyModuleElement(Element): @@ -212,7 +212,7 @@ def finite_part(self, degree=None): else: m = degree + 1 - v = self.valuation() + v = coeff_stream.order() return L.sum(self[i]*P.monomial(1, i) for i in range(v, m)) def __getitem__(self, n): @@ -398,45 +398,6 @@ def prec(self): """ return infinity - def valuation(self): - r""" - Return the valuation of ``self``. - - This method determines the valuation of the series by looking for a - nonzero coefficient. Hence if the series happens to be zero, then it - may run forever. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = 1/(1 - z) - 1/(1 - 2*z) - sage: s.valuation() - 1 - sage: t = z - z - sage: t.valuation() - +Infinity - sage: M = L(lambda n: n^2, 0) - sage: M.valuation() - 1 - sage: (M - M).valuation() - +Infinity - - Similarly for Dirichlet series:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: mu = L(moebius); mu.valuation() - 1 - sage: (mu - mu).valuation() - +Infinity - sage: g = L(constant=1, valuation=2) - sage: g.valuation() - 2 - sage: (g*g).valuation() - 4 - - """ - return self._coeff_stream.order() - def _richcmp_(self, other, op): r""" Compare ``self` with ``other`` with respect to the comparison @@ -1222,6 +1183,32 @@ class LazyCauchyProductSeries(LazyModuleElement): sage: f 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) """ + def valuation(self): + r""" + Return the valuation of ``self``. + + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: s = 1/(1 - z) - 1/(1 - 2*z) + sage: s.valuation() + 1 + sage: t = z - z + sage: t.valuation() + +Infinity + sage: M = L(lambda n: n^2, 0) + sage: M.valuation() + 1 + sage: (M - M).valuation() + +Infinity + + """ + return self._coeff_stream.order() + def _mul_(self, other): """ Return the product of this series with ``other``. @@ -1580,6 +1567,7 @@ def __pow__(self, n): 1 - 2*z + z^2 sage: (1 + z)^2 1 + 2*z + z^2 + """ if n == 0: return self.parent().one() @@ -2023,6 +2011,9 @@ def __call__(self, g): if isinstance(g, LazyCauchyProductSeries): CS_prod = CoefficientStream_cauchy_product CS_inv = CoefficientStream_cauchy_inverse + elif isinstance(g, LazyDirichletSeries): + CS_prod = CoefficientStream_dirichlet_convolution + CS_inv = CoefficientStream_dirichlet_inverse else: raise NotImplementedError("undefined product coefficient stream") return P.element_class(P, CoefficientStream_composition(self._coeff_stream, @@ -2514,6 +2505,31 @@ class LazyDirichletSeries(LazyModuleElement): sage: g == f True """ + def valuation(self): + r""" + Return the valuation of ``self``. + + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: mu = L(moebius); mu.valuation() + 0 + sage: (mu - mu).valuation() + +Infinity + sage: g = L(constant=1, valuation=2) + sage: g.valuation() + log(2) + sage: (g*g).valuation() + 2*log(2) + + """ + from sage.functions.log import log + return log(self._coeff_stream.order()) + def _mul_(self, other): """ Return the product of this series with ``other``. @@ -2571,7 +2587,7 @@ def __invert__(self): """ P = self.parent() - return P.element_class(P, CoefficientStream_dirichlet_inv(self._coeff_stream)) + return P.element_class(P, CoefficientStream_dirichlet_inverse(self._coeff_stream)) def change_ring(self, ring): """ diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index daea58aebf0..f310067cb1d 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -1358,7 +1358,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: X = L(constant=5, degree=3); X 5/3^z + 5/4^z + 5/5^z + O(1/(6^z)) sage: X.valuation() - 3 + log(3) sage: e = L(moebius); e 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) From cd3f004d5c9163732e8c5aab883624dc9e3a1b8c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 12 Aug 2021 18:07:24 +0200 Subject: [PATCH 081/355] add a (currently failing) testcase --- src/sage/rings/lazy_laurent_series.py | 15 +++++++++++++++ src/sage/rings/lazy_laurent_series_ring.py | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 85740f0f99f..b92309e8936 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1921,6 +1921,21 @@ def __call__(self, g): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series + + We compose the exponential with a Dirichlet series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: e = L(lambda n: 1/factorial(n), 0) + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: f = D(constant=1)-1; f + 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) + + sage: e(f)[0:10] + [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + + sage: sum(f^k/factorial(k) for k in range(10))[0:10] + [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + """ # f = self and compute f(g) P = g.parent() diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index f310067cb1d..f51fd8da86b 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -778,7 +778,7 @@ class LazyTaylorSeriesRing(UniqueRepresentation, Parent): """ Element = LazyTaylorSeries - def __init__(self, base_ring, names, sparse=False, category=None): + def __init__(self, base_ring, names, sparse=True, category=None): """ Initialize ``self``. @@ -1032,7 +1032,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: L(lambda n: n)[3]; Traceback (most recent call last): ... - ValueError: coefficient 1 at degree 1 is not a homogeneous polynomial + ValueError: coefficient 3 at degree 3 is not a homogeneous polynomial sage: L([1, 2, 3]); Traceback (most recent call last): @@ -1207,7 +1207,7 @@ class LazyDirichletSeriesRing(UniqueRepresentation, Parent): """ Element = LazyDirichletSeries - def __init__(self, base_ring, names, sparse=False, category=None): + def __init__(self, base_ring, names, sparse=True, category=None): """ Initialize the ring. From 4aff8a4f7110005867fb278ff94eb0c6de5069fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 12 Aug 2021 19:17:08 -0700 Subject: [PATCH 082/355] sage_setup.library_order: Skip libraries that were not detected --- src/sage_setup/library_order.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/sage_setup/library_order.py b/src/sage_setup/library_order.py index bc04af3fdd9..ef1f47d8d2e 100644 --- a/src/sage_setup/library_order.py +++ b/src/sage_setup/library_order.py @@ -11,23 +11,32 @@ # listed here will be added at the end of the list (without changing # their relative order). from sage.env import cython_aliases -aliases = cython_aliases() -arb_dylib_name = aliases["ARB_LIBRARY"] -library_order_list = aliases["SINGULAR_LIBRARIES"] + [ +modules = ('fflas-ffpack', 'gsl', 'linbox', 'Singular', + 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas') + +aliases = cython_aliases(required_modules=(), optional_modules=modules) + +if "ARB_LIBRARY" in aliases: + arb_dylib_names = [aliases["ARB_LIBRARY"]] +else: + arb_dylib_names = [] + +library_order_list = aliases.get("SINGULAR_LIBRARIES", []) + [ "giac", "intl", "curl", "ec", "ecm" -] + aliases["LINBOX_LIBRARIES"] + aliases["FFLASFFPACK_LIBRARIES"] + aliases["GSL_LIBRARIES"] + [ +] + aliases.get("LINBOX_LIBRARIES", []) + aliases.get("FFLASFFPACK_LIBRARIES", []) + aliases.get("GSL_LIBRARIES", []) + [ "pari", "flint", "ratpoints", "ecl", "glpk", "ppl", - arb_dylib_name, "mpfi", "mpfr", "mpc", "ntl", "gmp", "gmpxx", +] + arb_dylib_names + [ + "mpfi", "mpfr", "mpc", "ntl", "gmp", "gmpxx", "brial", "brial_groebner", "m4rie", -] + aliases["M4RI_LIBRARIES"] + [ +] + aliases.get("M4RI_LIBRARIES", []) + [ "zn_poly", "gap", -] + aliases["GDLIB_LIBRARIES"] + aliases["LIBPNG_LIBRARIES"] + [ - "m", "readline", "Lfunction" , -] + aliases["CBLAS_LIBRARIES"] + aliases["ZLIB_LIBRARIES"] +] + aliases.get("GDLIB_LIBRARIES", []) + aliases.get("LIBPNG_LIBRARIES", []) + [ + "m", "readline", "Lfunction", +] + aliases.get("CBLAS_LIBRARIES", []) + aliases.get("ZLIB_LIBRARIES", []) # Make a dict with library:order pairs, where the order are negative # integers sorted according to library_order_list. When sorting, From a9b2bd6c52f0e49bd877829c2b7922510bc3e153 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 12 Aug 2021 20:33:55 -0700 Subject: [PATCH 083/355] build/pkgs/pyopenssl: Remove --- build/pkgs/pyopenssl/SPKG.rst | 18 ------------------ build/pkgs/pyopenssl/distros/conda.txt | 1 - build/pkgs/pyopenssl/distros/macports.txt | 1 - build/pkgs/pyopenssl/distros/opensuse.txt | 1 - build/pkgs/pyopenssl/distros/repology.txt | 2 -- build/pkgs/pyopenssl/requirements.txt | 2 -- build/pkgs/pyopenssl/type | 1 - 7 files changed, 26 deletions(-) delete mode 100644 build/pkgs/pyopenssl/SPKG.rst delete mode 100644 build/pkgs/pyopenssl/distros/conda.txt delete mode 100644 build/pkgs/pyopenssl/distros/macports.txt delete mode 100644 build/pkgs/pyopenssl/distros/opensuse.txt delete mode 100644 build/pkgs/pyopenssl/distros/repology.txt delete mode 100755 build/pkgs/pyopenssl/requirements.txt delete mode 100644 build/pkgs/pyopenssl/type diff --git a/build/pkgs/pyopenssl/SPKG.rst b/build/pkgs/pyopenssl/SPKG.rst deleted file mode 100644 index 8eeedaee32d..00000000000 --- a/build/pkgs/pyopenssl/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -pyopenssl: Python wrapper module around the OpenSSL library -=========================================================== - -Description ------------ - -Python wrapper module around the OpenSSL library - -License -------- - -Apache License, Version 2.0 - -Upstream Contact ----------------- - -https://pypi.org/project/pyOpenSSL/ - diff --git a/build/pkgs/pyopenssl/distros/conda.txt b/build/pkgs/pyopenssl/distros/conda.txt deleted file mode 100644 index f0bff404425..00000000000 --- a/build/pkgs/pyopenssl/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -pyopenssl diff --git a/build/pkgs/pyopenssl/distros/macports.txt b/build/pkgs/pyopenssl/distros/macports.txt deleted file mode 100644 index eb73f41bc31..00000000000 --- a/build/pkgs/pyopenssl/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-openssl diff --git a/build/pkgs/pyopenssl/distros/opensuse.txt b/build/pkgs/pyopenssl/distros/opensuse.txt deleted file mode 100644 index 353babfd9aa..00000000000 --- a/build/pkgs/pyopenssl/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-pyOpenSSL diff --git a/build/pkgs/pyopenssl/distros/repology.txt b/build/pkgs/pyopenssl/distros/repology.txt deleted file mode 100644 index b3288b190ea..00000000000 --- a/build/pkgs/pyopenssl/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -pyopenssl -python:pyopenssl diff --git a/build/pkgs/pyopenssl/requirements.txt b/build/pkgs/pyopenssl/requirements.txt deleted file mode 100755 index 74e8b70d952..00000000000 --- a/build/pkgs/pyopenssl/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -service_identity -pyopenssl diff --git a/build/pkgs/pyopenssl/type b/build/pkgs/pyopenssl/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/pyopenssl/type +++ /dev/null @@ -1 +0,0 @@ -optional From aa73955c380104eaac26dac315499423480da313 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 14 Aug 2021 11:27:30 +0200 Subject: [PATCH 084/355] two fixes in Laurent element_constructor --- src/sage/rings/lazy_laurent_series_ring.py | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index ad6d6c9cd8c..06b1997497b 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -34,7 +34,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.lazy_laurent_series import LazyModuleElement, LazyLaurentSeries, LazyTaylorSeries, LazyDirichletSeries +from sage.rings.lazy_laurent_series import LazyCauchyProductSeries, LazyLaurentSeries, LazyTaylorSeries, LazyDirichletSeries from sage.structure.global_options import GlobalOptions from sage.symbolic.ring import SR @@ -512,8 +512,6 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No ... ValueError: the valuation must be specified - TESTS: - This gives zero:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') @@ -551,6 +549,24 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: f == g True + We can convert a Taylor series to a Laurent series:: + + sage: P. = QQ[] + sage: L. = LazyLaurentSeriesRing(P) + sage: T. = LazyTaylorSeriesRing(QQ) + sage: s = 1/(1-x-y); L(s) + 1 + (x + y)*z + (x^2 + 2*x*y + y^2)*z^2 + (x^3 + 3*x^2*y + 3*x*y^2 + y^3)*z^3 + (x^4 + 4*x^3*y + 6*x^2*y^2 + 4*x*y^3 + y^4)*z^4 + (x^5 + 5*x^4*y + 10*x^3*y^2 + 10*x^2*y^3 + 5*x*y^4 + y^5)*z^5 + (x^6 + 6*x^5*y + 15*x^4*y^2 + 20*x^3*y^3 + 15*x^2*y^4 + 6*x*y^5 + y^6)*z^6 + O(z^7) + + However, not a Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(ZZ, 't') + sage: m = D(moebius) + sage: L(m) + Traceback (most recent call last): + ... + ValueError: unable to convert 1 - 1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(8^t)) into a lazy Laurent series + + .. TODO:: Add a method to change the sparse/dense implementation. @@ -590,7 +606,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No order=x.valuation(), constant=constant, degree=degree) return self.element_class(self, coeff_stream) - if isinstance(x, LazyModuleElement): + if isinstance(x, LazyCauchyProductSeries): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") From b7b1a03452c461cb158e90980503b873106503be Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 14 Aug 2021 13:41:16 +0200 Subject: [PATCH 085/355] add TODO comments for composition with Dirichlet series --- src/sage/data_structures/coefficient_stream.py | 6 +++--- src/sage/rings/lazy_laurent_series.py | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/coefficient_stream.py b/src/sage/data_structures/coefficient_stream.py index 3b847dd93b2..9e19cb83171 100644 --- a/src/sage/data_structures/coefficient_stream.py +++ b/src/sage/data_structures/coefficient_stream.py @@ -1558,7 +1558,7 @@ def __init__(self, f, g, prod_stream, inv_stream): sage: g = CoefficientStream_coefficient_function(lambda n: n^2, ZZ, True, 1) sage: h = CoefficientStream_composition(f, g, CS_prod, CS_inv) """ - assert g._approximate_order > 0 + assert g._approximate_order > 0 # TODO: wrong if g is a Dirichlet series, need > 1 self._fv = f._approximate_order self._gv = g._approximate_order self._prod_stream = prod_stream @@ -1571,7 +1571,7 @@ def __init__(self, f, g, prod_stream, inv_stream): self._neg_powers.append(self._prod_stream(self._neg_powers[-1], ginv)) # Placeholder None to make this 1-based self._pos_powers = [None, g] - val = self._fv * self._gv + val = self._fv * self._gv # TODO: wrong if g is a Dirichlet series, self._gv ^ self._fv there super().__init__(f, g, f._is_sparse, val) def get_coefficient(self, n): @@ -1595,7 +1595,7 @@ def get_coefficient(self, n): sage: [h.get_coefficient(i) for i in range(10)] [0, 1, 6, 28, 124, 527, 2172, 8755, 34704, 135772] """ - if n < 0: + if n < 0: # TODO: wrong if g is a Dirichlet series, for n <= 0 we get 0 return sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, n // self._gv + 1)) # n > 0 while len(self._pos_powers) <= n // self._gv: diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 96dabe76ee8..09a2c1a8ca0 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1952,13 +1952,13 @@ def __call__(self, g): sage: L. = LazyLaurentSeriesRing(QQ) sage: e = L(lambda n: 1/factorial(n), 0) sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: f = D(constant=1)-1; f + sage: g = D(constant=1)-1; g 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) - sage: e(f)[0:10] + sage: e(g)[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] - sage: sum(f^k/factorial(k) for k in range(10))[0:10] + sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] """ @@ -1991,6 +1991,7 @@ def __call__(self, g): if not isinstance(g, LazyModuleElement): return poly(g) # g also has finite length, compose the polynomials + # TODO: likely wrong if g is a Dirichlet series if isinstance(g._coeff_stream, CoefficientStream_exact) and not g._coeff_stream._constant: R = P._laurent_poly_ring g_poly = g._coeff_stream.polynomial_part(R) @@ -2039,6 +2040,7 @@ def __call__(self, g): # TODO: Implement case for a regular (Laurent)PowerSeries element # as we can use the (default?) order given try: + # TODO: wrong if g is not a CauchyProductSeries g = self.parent()(g) except (TypeError, ValueError): raise NotImplementedError("can only compose with a lazy series") From 1a1f54a6bf3e7b34b3b1b1e0aee1b90ac0987dc6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 14 Aug 2021 16:15:15 +0200 Subject: [PATCH 086/355] move __pow__ up the hierarchy and add (currently failing) doctest --- src/sage/rings/lazy_laurent_series.py | 230 +++++++++++++------------- 1 file changed, 112 insertions(+), 118 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index d4816dd6a87..712f153794d 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1812,6 +1812,118 @@ def coeff(n, c): valuation=0) return f(self) + # === powers === + + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: (1 - z)^-1 + 1 + z + z^2 + O(z^3) + sage: (1 - z)^0 + 1 + sage: (1 - z)^3 + 1 - 3*z + 3*z^2 - z^3 + sage: (1 - z)^-3 + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + We can create a really large power of a monomial, even with + the dense implementation:: + + sage: z^1000000 + z^1000000 + + Lazy Laurent series that have a sparse implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + Lazy Laurent series that are known to be exact can be raised + to the power ``n``:: + + sage: z^2 + z^2 + sage: (1 - z)^2 + 1 - 2*z + z^2 + sage: (1 + z)^2 + 1 + 2*z + z^2 + + We also support the general case:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: (1 + z)^(1 + z) + 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + + """ + if n == 0: + return self.parent().one() + + cs = self._coeff_stream + if (isinstance(cs, CoefficientStream_exact) + and not cs._constant and n in ZZ + and (n > 0 or len(cs._initial_coefficients) == 1)): + P = self.parent() + return P(self.finite_part() ** ZZ(n)) + # ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) + # val = ret.valuation() + # deg = ret.degree() + 1 + # initial_coefficients = [ret[i] for i in range(val, deg)] + # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, + # constant=cs._constant, degree=deg, valuation=val)) + + if n in ZZ: + return generic_power(self, n) + + from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from sage.functions.other import factorial + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + return exp(self.log() * n) + + def sqrt(self): + """ + Return ``self^(1/2)``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: sqrt(1+z) + 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(SR) + sage: sqrt(1+x/(1-y)) + 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + O(x,y)^7 + + This also works for Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(SR, "s") + sage: zeta = D(constant=1) + sage: f = sqrt(zeta) + 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) + sage: f*f - zeta + O(1/(8^s)) + + """ + return self ** (1/ZZ(2)) + class LazyCauchyProductSeries(LazyModuleElement): r""" @@ -2164,107 +2276,6 @@ def _div_(self, other): return P.element_class(P, CoefficientStream_cauchy_product(left, CoefficientStream_cauchy_inverse(right))) - def __pow__(self, n): - """ - Return the ``n``-th power of the series. - - INPUT: - - - ``n`` -- integer; the power to which to raise the series - - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: (1 - z)^-1 - 1 + z + z^2 + O(z^3) - sage: (1 - z)^0 - 1 - sage: (1 - z)^3 - 1 - 3*z + 3*z^2 - z^3 - sage: (1 - z)^-3 - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - We can create a really large power of a monomial, even with - the dense implementation:: - - sage: z^1000000 - z^1000000 - - Lazy Laurent series that have a sparse implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - Lazy Laurent series that are known to be exact can be raised - to the power ``n``:: - - sage: z^2 - z^2 - sage: (1 - z)^2 - 1 - 2*z + z^2 - sage: (1 + z)^2 - 1 + 2*z + z^2 - - We also support the general case:: - - sage: L. = LazyLaurentSeriesRing(SR) - sage: (1 + z)^(1 + z) - 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) - - """ - if n == 0: - return self.parent().one() - - cs = self._coeff_stream - if (isinstance(cs, CoefficientStream_exact) - and not cs._constant and n in ZZ - and (n > 0 or len(cs._initial_coefficients) == 1)): - P = self.parent() - return P(self.finite_part() ** ZZ(n)) - # ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) - # val = ret.valuation() - # deg = ret.degree() + 1 - # initial_coefficients = [ret[i] for i in range(val, deg)] - # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - # constant=cs._constant, degree=deg, valuation=val)) - - if n in ZZ: - return generic_power(self, n) - - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.functions.other import factorial - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) - return exp(self.log() * n) - - def sqrt(self): - """ - Return ``self^(1/2)``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(SR) - sage: sqrt(1+z) - 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) - - sage: L. = LazyTaylorSeriesRing(SR) - sage: sqrt(1+x/(1-y)) - 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + O(x,y)^7 - - """ - return self ** (1/ZZ(2)) - class LazyLaurentSeries(LazyCauchyProductSeries): r""" @@ -3372,23 +3383,6 @@ def change_ring(self, ring): Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) - def __pow__(self, n): - """ - Return the ``n``-th power of the series. - - INPUT: - - - ``n`` -- integer, the power to which to raise the series - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - """ - if n == 0: - return self.parent().one() - - return generic_power(self, n) - def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. From 86925af05516a86f4ee30dc15685b752382aeebb Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 15 Aug 2021 18:18:45 +0200 Subject: [PATCH 087/355] initial version of lazy symmetric functions --- src/sage/rings/all.py | 5 +- src/sage/rings/lazy_laurent_series.py | 87 +++++ src/sage/rings/lazy_laurent_series_ring.py | 362 ++++++++++++++++++++- 3 files changed, 450 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 34aea7ce7b6..0b9f1f446c5 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,10 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing', 'LazyTaylorSeriesRing']) +lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', + 'LazyDirichletSeriesRing', + 'LazyTaylorSeriesRing', + 'LazySymmetricFunctions']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index bc37966fc56..6a893f47cab 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2593,6 +2593,93 @@ def parenthesize(m): return poly +class LazySymmetricFunction(LazyCauchyProductSeries): + r""" + A symmetric function where each degree is computed lazily. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, "x, y") + """ + def change_ring(self, ring): + """ + Return this series with coefficients converted to elements of ``ring``. + + INPUT: + + - ``ring`` -- a ring + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, "z") + """ + from .lazy_laurent_series_ring import LazySymmetricFunctions + Q = LazySymmetricFunctions(ring, names=self.parent().variable_names()) + return Q.element_class(Q, self._coeff_stream) + + def _format_series(self, formatter, format_strings=False): + """ + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: L = LazySymmetricFunctions(QQ, "x, y") + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, CoefficientStream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, CoefficientStream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P.monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly + + class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index a4904ff489a..16a2bb043a5 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -27,6 +27,7 @@ from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields, CompleteDiscreteValuationRings +from sage.categories.tensor import tensor from sage.misc.cachefunc import cached_method @@ -34,7 +35,12 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.lazy_laurent_series import LazyCauchyProductSeries, LazyLaurentSeries, LazyTaylorSeries, LazyDirichletSeries +from sage.combinat.sf.sf import SymmetricFunctions +from sage.rings.lazy_laurent_series import (LazyCauchyProductSeries, + LazyLaurentSeries, + LazyTaylorSeries, + LazySymmetricFunction, + LazyDirichletSeries) from sage.structure.global_options import GlobalOptions from sage.symbolic.ring import SR @@ -880,7 +886,7 @@ class LazyTaylorSeriesRing(UniqueRepresentation, Parent): - ``base_ring`` -- base ring of this Taylor series ring - ``names`` -- name(s) of the generator of this Taylor series ring - - ``sparse`` -- (default: ``False``) whether this series is sparse or not + - ``sparse`` -- (default: ``True``) whether this series is sparse or not EXAMPLES:: @@ -901,6 +907,8 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: L = LazyTaylorSeriesRing(ZZ, 't') sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) """ + if isinstance(names, str): + names = (names, ) self._sparse = sparse if len(names) == 1: self._coeff_ring = base_ring @@ -1302,6 +1310,354 @@ class options(GlobalOptions): checker=lambda x: x in ZZ and x > 0) +###################################################################### + +class LazySymmetricFunctions(UniqueRepresentation, Parent): + """ + Lazy symmetric functions. + + INPUT: + + - ``base_ring`` -- coefficient ring + - ``names`` -- name(s) of the alphabets + - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation + + EXAMPLES:: + + sage: LazySymmetricFunctions(ZZ, 'x') + Lazy Symmetric Functions Ring in x over Integer Ring + + sage: L = LazySymmetricFunctions(QQ, "x, y"); L + Multialphabet Lazy Symmetric Functions Ring in x, y over Rational Field + """ + Element = LazySymmetricFunction + + def __init__(self, base_ring, names, sparse=True, category=None): + """ + Initialize ``self``. + + TESTS:: + + sage: L = LazySymmetricFunctions(ZZ, 't') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + """ + category = Algebras(base_ring.category()) + if base_ring in Fields(): + category &= CompleteDiscreteValuationRings() + elif base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + + if base_ring.is_zero(): + category = category.Finite() + else: + category = category.Infinite() + Parent.__init__(self, base=base_ring, names=names, + category=category) + self._sparse = sparse + n = len(self.variable_names()) + if n == 1: + self._coeff_ring = SymmetricFunctions(base_ring).m() + else: + self._coeff_ring = tensor([SymmetricFunctions(base_ring).m()]*len(self.variable_names())) + self._laurent_poly_ring = self._coeff_ring + + def _repr_(self): + """ + String representation of the lazy symmetric functions ring. + + EXAMPLES:: + + sage: LazySymmetricFunctions(GF(2), 'z') + Lazy Symmetric Functions Ring in z over Finite Field of size 2 + """ + if len(self.variable_names()) == 1: + return "Lazy Symmetric Functions Ring in {} over {}".format(self.variable_name(), self.base_ring()) + generators_rep = ", ".join(self.variable_names()) + return "Multialphabet Lazy Symmetric Functions Ring in {} over {}".format(generators_rep, self.base_ring()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: latex(L) + \Lambda( \Bold{F}_{2} , z) + """ + from sage.misc.latex import latex + generators_rep = ", ".join(self.variable_names()) + return r"\Lambda(" + latex(self.base_ring()) + r", {})".format(generators_rep) + + @cached_method + def monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.monomial(s[2,1], 3) + 2*m[1, 1, 1] + m[2, 1] + + """ + L = self._laurent_poly_ring + return L(c) + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True + + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) + + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + + def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): + """ + Construct a lazy symmetric function from ``x``. + + INPUT: + + - ``x`` -- data used to the define a Taylor series + - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series + - ``degree`` -- (optional) the degree when the symmetric function has finite support + - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + m[] + + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: f = L(lambda i: m([i]), valuation=5, degree=10); f + m[5] + m[6] + m[7] + m[8] + m[9] + + sage: f.coefficient(6) + m[6] + sage: f[20] + 0 + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``:: + + sage: f = L([m[1],m[2],m[3]], valuation=1); f + m[1] + m[2] + m[3] + + .. TODO:: + + Add a method to change the sparse/dense implementation. + + Finally, ``x`` can be a symmetric function:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(ZZ, "x") + sage: L(s.an_element()) + 2*m[] + 2*m[1] + (3*m[1,1]+3*m[2]) + + TESTS:: + + sage: L = LazySymmetricFunctions(ZZ, "x,y") + sage: L(lambda n: 0) + O(x,y)^7 + + sage: L(lambda n: n)[3]; + Traceback (most recent call last): + ... + ValueError: coefficient 3*m[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree + + sage: L([1, 2, 3]); + Traceback (most recent call last): + ... + ValueError: coefficients must be symmetric functions of the correct homogeneous degree + + sage: L(lambda n: n, degree=3); + Traceback (most recent call last): + ... + ValueError: coefficients must be symmetric functions of the correct homogeneous degree + + """ + if valuation is not None: + if valuation < 0: + raise ValueError("the valuation of a lazy symmetric function must be nonnegative") + + R = self._laurent_poly_ring + BR = self.base_ring() + if x is None: + assert degree is None + coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) + return self.element_class(self, coeff_stream) + try: + # Try to build stuff using the polynomial ring constructor + x = R(x) + except (TypeError, ValueError, NotImplementedError): + pass + if x in R: + if not x: + coeff_stream = CoefficientStream_zero(self._sparse) + else: + p_dict = {} + if len(self.variable_names()) == 1: + for f in x.terms(): + d = f.degree() + p_dict[d] = p_dict.get(d, 0) + f + else: + for f in x.terms(): + d = sum(p.size() for p in f.support()) + p_dict[d] = p_dict.get(d, 0) + f + v = min(p_dict.keys()) + d = max(p_dict.keys()) + p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + + coeff_stream = CoefficientStream_exact(p_list, self._sparse, + order=v, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + + if isinstance(x, LazySymmetricFunction): + if x._coeff_stream._is_sparse is self._sparse: + return self.element_class(self, x._coeff_stream) + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + + if len(self.variable_names()) == 1: + def is_homogeneous_of_degree(f, d): + if not f: + return True + try: + return f.homogeneous_degree() == d + except ValueError: + return False + else: + def is_homogeneous_of_degree(f, d): + if not f: + return True + for m in f.monomials(): + for t in m.support(): + if sum(p.size() for p in t) != d: + return False + if isinstance(x, (tuple, list)): + if valuation is None: + valuation = 0 + if degree is None: + degree = valuation + len(x) + p = [R(e) for e in x] + if not all(is_homogeneous_of_degree(e, i) + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + coeff_stream = CoefficientStream_exact(p, self._sparse, + order=valuation, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + if callable(x): + if valuation is None: + valuation = 0 + if degree is not None: + p = [R(x(i)) for i in range(valuation, degree)] + if not all(is_homogeneous_of_degree(e, i) + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + coeff_stream = CoefficientStream_exact(p, self._sparse, + order=valuation, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + if check: + def y(n): + e = R(x(n)) + if is_homogeneous_of_degree(e, n): + return e + raise ValueError("coefficient %s at degree %s is not a symmetric function of the correct homogeneous degree" % (e, n)) + coeff_stream = CoefficientStream_coefficient_function(y, self._coeff_ring, self._sparse, valuation) + else: + coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) + return self.element_class(self, coeff_stream) + raise ValueError(f"unable to convert {x} into a lazy symmetric function") + + def _an_element_(self): + """ + Return a lazy symmetric function in ``self``. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.an_element() + m[] + """ + c = self.base_ring()(1) + R = self._laurent_poly_ring + coeff_stream = CoefficientStream_exact([R.one()], self._sparse, order=1, constant=0) + return self.element_class(self, coeff_stream) + + @cached_method + def one(self): + r""" + Return the constant `1`. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.one() + m[] + """ + R = self._laurent_poly_ring + coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) + return self.element_class(self, coeff_stream) + + @cached_method + def zero(self): + r""" + Return the zero series. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, CoefficientStream_zero(self._sparse)) + + # add options to class + class options(GlobalOptions): + NAME = 'LazySymmetricFunctions' + module = 'sage.rings.lazy_laurent_series_ring' + display_length = dict(default=7, + description='the number of coefficients to display from the valuation', + checker=lambda x: x in ZZ and x > 0) + constant_length = dict(default=3, + description='the number of coefficients to display for nonzero constant series', + checker=lambda x: x in ZZ and x > 0) + + ###################################################################### class LazyDirichletSeriesRing(UniqueRepresentation, Parent): @@ -1311,8 +1667,8 @@ class LazyDirichletSeriesRing(UniqueRepresentation, Parent): INPUT: - ``base_ring`` -- base ring of this Dirichlet series ring - - ``names`` -- name of the generator of this Dirichlet series ring + - ``sparse`` -- (default: ``True``) whether this series is sparse or not EXAMPLES:: From aa8a25078b5c9e7f89e2863e617d9f2782200a12 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 17 Aug 2021 08:57:24 +0200 Subject: [PATCH 088/355] initial and insanely stupid plethysm implementation --- src/sage/rings/lazy_laurent_series.py | 84 ++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 6a893f47cab..348ec55df5e 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2422,7 +2422,8 @@ class LazyTaylorSeries(LazyCauchyProductSeries): True """ def __call__(self, *g): - r"""Return the composition of ``self`` with ``g``. + r""" + Return the composition of ``self`` with ``g``. The arity of ``self`` must be equal to the number of arguments provided. @@ -2599,8 +2600,87 @@ class LazySymmetricFunction(LazyCauchyProductSeries): EXAMPLES:: - sage: L = LazySymmetricFunctions(ZZ, "x, y") + sage: L = LazySymmetricFunctions(ZZ, "x") """ + def __call__(self, *args): + r""" + Return the composition of ``self`` with ``args``. + + The arity of ``self`` must be equal to the number of + arguments provided. + + Given two lazy symmetric functions `f` and `g` over the same + base ring, the composition (or plethysm) `(f \circ g)` is + defined if and only if: + + - `g = 0`, + - `g` is non-zero and `f` has only finitely many non-zero coefficients, + - `g` is non-zero and `val(g) > 0`. + + INPUT: + + - ``args`` -- other (lazy) symmetric functions. + + EXAMPLES:: + + sage: P. = QQ[] + sage: s = SymmetricFunctions(P).s() + sage: L = LazySymmetricFunctions(P, "x") + sage: f = s[2]; g = s[3] + sage: L(f)(L(g)) - L(f(g)) + O(x)^7 + + sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: L(f)(L(g)) - L(f(g)) + O(x)^7 + """ + if len(args) != len(self.parent().variable_names()): + raise ValueError("arity must be equal to the number of arguments provided") + from sage.combinat.sf.sfa import is_SymmetricFunction + if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) for g in args): + raise ValueError("all arguments must be (possibly lazy) symmetric functions") + from sage.misc.lazy_list import lazy_list + if len(args) == 1: + g = args[0] + P = g.parent() + R = P._coeff_ring + BR = P.base_ring() + p = R.realization_of().power() + g_p = CoefficientStream_map_coefficients(g._coeff_stream, lambda c: c, p) + degree_one = [R(x) for x in BR.variable_names_recursive()] + def raise_c(n): + return lambda c: c.subs(**{str(g): x ** n for x in degree_one}) + def scale_part(n): + return lambda m: m.__class__(m.parent(), [i * n for i in m]) + def pn_pleth(f, n): + return f.map_support(scale_part(n)) + def stretched_coefficient(k, n): + q, r = ZZ(n).quo_rem(k) + if r: + return 0 + c = g_p[q] + if c: + return pn_pleth(c.map_coefficients(raise_c(k)), k) + return c + def g_coeff_stream(k): + return CoefficientStream_coefficient_function(lambda n: stretched_coefficient(k, n), + R, P._sparse, 0) + stretched = lazy_list(lambda k: g_coeff_stream(k)) + f_p = CoefficientStream_map_coefficients(self._coeff_stream, lambda c: c, p) + def coefficient(n): + r = R(0) + for i in range(n+1): + r += p._apply_module_morphism(f_p[i], + lambda part: p.prod(sum(stretched[j][h] for h in range(n+1)) + for j in part), + codomain=p).homogeneous_component(n) + return r + else: + raise NotImplementedError + + coeff_stream = CoefficientStream_coefficient_function(coefficient, P._coeff_ring, P._sparse, 0) + return P.element_class(P, coeff_stream) + def change_ring(self, ring): """ Return this series with coefficients converted to elements of ``ring``. From 1a36f592ade820ff533feddbb89c040567f0ec40 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 17 Aug 2021 08:59:38 +0200 Subject: [PATCH 089/355] add (currently failing) doctest for plethysm --- src/sage/rings/lazy_laurent_series.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index 348ec55df5e..b28a9a1ee80 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2633,6 +2633,10 @@ def __call__(self, *args): sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] sage: L(f)(L(g)) - L(f(g)) O(x)^7 + + sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: L(f)(L(q*g)) - L(f(q*g)) + O(x)^7 """ if len(args) != len(self.parent().variable_names()): raise ValueError("arity must be equal to the number of arguments provided") From 03198a02a7522ff2745fe6dd2e0e1a4a80d0dd1b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 17 Aug 2021 11:35:38 +0200 Subject: [PATCH 090/355] fix bug in plethysm --- src/sage/rings/lazy_laurent_series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index b28a9a1ee80..a2b35d63b23 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -2651,9 +2651,9 @@ def __call__(self, *args): BR = P.base_ring() p = R.realization_of().power() g_p = CoefficientStream_map_coefficients(g._coeff_stream, lambda c: c, p) - degree_one = [R(x) for x in BR.variable_names_recursive()] + degree_one = BR.variable_names_recursive() def raise_c(n): - return lambda c: c.subs(**{str(g): x ** n for x in degree_one}) + return lambda c: c.subs(**{x: BR(x) ** n for x in degree_one}) def scale_part(n): return lambda m: m.__class__(m.parent(), [i * n for i in m]) def pn_pleth(f, n): From eb3e88fe6806d49f6b84f80d96dd6cf35ab1ed25 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 17 Aug 2021 12:02:12 +0200 Subject: [PATCH 091/355] more doctests for composition and plethysm --- src/sage/rings/lazy_laurent_series.py | 34 +++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index a2b35d63b23..fad40e5ffec 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1961,6 +1961,18 @@ def __call__(self, g): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + The Frobenius character of the trivial representation can be + expressed as an exponential:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: e = L(lambda n: 1/factorial(n), valuation=0) + sage: p = SymmetricFunctions(QQ).p() + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(QQ, "x") + sage: f = S(lambda n: p[n]/n, valuation=1) + sage: [s(x) for x in e(f)[:5]] + [s[], s[1], s[2], s[3], s[4]] + """ # f = self and compute f(g) P = g.parent() @@ -2637,6 +2649,18 @@ def __call__(self, *args): sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] sage: L(f)(L(q*g)) - L(f(q*g)) O(x)^7 + + The Frobenius character of the permutation action on set + partitions is a plethysm:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(QQ, "x") + sage: E1 = S(lambda n: s[n], valuation=1) + sage: E = 1 + E1 + sage: P = E(E1) + sage: [s(x) for x in P[:5]] + [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + """ if len(args) != len(self.parent().variable_names()): raise ValueError("arity must be equal to the number of arguments provided") @@ -2651,9 +2675,15 @@ def __call__(self, *args): BR = P.base_ring() p = R.realization_of().power() g_p = CoefficientStream_map_coefficients(g._coeff_stream, lambda c: c, p) - degree_one = BR.variable_names_recursive() + try: + degree_one = [BR(x) for x in BR.variable_names_recursive()] + except AttributeError: + try: + degree_one = BR.gens() + except NotImplementedError: + degree_one = [] def raise_c(n): - return lambda c: c.subs(**{x: BR(x) ** n for x in degree_one}) + return lambda c: c.subs(**{str(x): x ** n for x in degree_one}) def scale_part(n): return lambda m: m.__class__(m.parent(), [i * n for i in m]) def pn_pleth(f, n): From ab288d62786a40b9f314d40ca932506d7b6932d9 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 17 Aug 2021 17:38:12 +0200 Subject: [PATCH 092/355] Trac #29581: algorithm for complex vbundles --- .../differentiable/bundle_connection.py | 24 +-- .../characteristic_cohomology_class.py | 163 ++++++++++++++---- 2 files changed, 138 insertions(+), 49 deletions(-) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 3c0c22a2b0d..a3353b820cb 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -266,7 +266,7 @@ def __init__(self, vbundle, name, latex_name=None): "vector bundle") Mutability.__init__(self) self._vbundle = vbundle - self._base_space = vbundle.base_space() + self._domain = vbundle.base_space() self._name = name if latex_name is None: self._latex_name = self._name @@ -394,7 +394,7 @@ def __eq__(self, other): return True if not isinstance(other, BundleConnection): return False - if other._base_space != self._base_space: + if other._domain != self._domain: return False if self._connection_forms == {}: return False @@ -566,7 +566,7 @@ def connection_forms(self, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -832,7 +832,7 @@ def add_connection_form(self, i, j, frame=None): """ self._require_mutable() if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -840,7 +840,7 @@ def add_connection_form(self, i, j, frame=None): if frame not in self._connection_forms: if frame not in self._vbundle._frames: raise ValueError("the {} is not".format(frame) + - " a frame on the {}".format(self._base_space)) + " a frame on the {}".format(self._domain)) self._connection_forms[frame] = self._new_forms(frame) self._del_derived() # deletes the derived quantities return self._connection_forms[frame][(i, j)] @@ -967,7 +967,7 @@ def del_other_forms(self, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -1023,7 +1023,7 @@ def curvature_form(self, i, j, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -1127,13 +1127,13 @@ def __getitem__(self, args): # extract frame from first index: vb = self._vbundle if isinstance(args, (int, Integer, slice)): - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() elif not isinstance(args[0], (int, Integer, slice)): frame = args[0] args = args[1:] else: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() # indexing: if isinstance(args, slice): @@ -1200,13 +1200,13 @@ def __setitem__(self, args, value): # extract frame from first index: vb = self._vbundle if isinstance(args, (int, Integer, slice)): - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() elif not isinstance(args[0], (int, Integer, slice)): frame = args[0] args = args[1:] else: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() # determine indices: if isinstance(args, slice): @@ -1350,7 +1350,7 @@ def display(self, frame=None, vector_frame=None, chart=None, """ vb = self._vbundle if frame is None: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a local frame must be provided") diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 1b4ae025270..70023ee5db9 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1,54 +1,144 @@ from sage.manifolds.differentiable.de_rham_cohomology import DeRhamCohomologyClass +from sage.algebras.finite_gca import FiniteGCAlgebra +from sage.combinat.free_module import IndexedFreeModuleElement +from sage.misc.fast_methods import Singleton +from sage.structure.sage_object import SageObject +from sage.misc.cachefunc import cached_method +from sage.misc.abstract_method import abstract_method +from sage.manifolds.differentiable.affine_connection import AffineConnection +from sage.manifolds.differentiable.bundle_connection import BundleConnection + +class CharacteristicCohomologyClass_Chern(IndexedFreeModuleElement): + r""" -def CharacteristicCohomologyClass(): - pass + """ + def __init__(self, parent, x, name=None, latex_name=None): + r""" -class CharacteristicCohomologyClass_base(DeRhamCohomologyClass): - pass + """ + self._name = name + if latex_name is None: + self._latex_name = self._name + else: + self._latex_name = latex_name + self._mixed_forms = {} # dict. of mixed forms w.r.t. this class + # (key: bundle connection) + super().__init__(parent, x) -class CharacteristicCohomologyClass_complex(CharacteristicCohomologyClass_base): - pass + def _repr_(self): + r""" -class CharacteristicCohomologyClass_real_even(CharacteristicCohomologyClass_base): - pass + """ + if self._name is None: + name = super()._repr_() + else: + name = self._name + vbundle = self.parent()._vbundle + return f'Characteristic cohomology class {name} over the {vbundle}' -class CharacteristicCohomologyClass_real_odd(CharacteristicCohomologyClass_base): - pass + def get_form(self, nab): + r""" + + """ + if nab not in self._mixed_forms: + dom = nab._domain + A = dom.mixed_form_algebra() + + # trivial cases + if self == 1: + self._mixed_forms[nab] = A(dom._one_scalar_field) + elif self == 0: + self._mixed_forms[nab] = A(dom._zero_scalar_field) + else: # non-trivial case + from functools import reduce + + c = ChernAlgorithm().get(nab) + parent = self.parent() + degrees = parent._degrees + grading = parent.print_options()['sorting_key'] + res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] + for ind, coeff in self: + deg = grading(ind) + gen_pow = [fast_wedge_power(c[d], i) for i, d in zip(ind, degrees)] + res[deg] += coeff * reduce(lambda x, y: x.wedge(y), gen_pow) + self._mixed_forms[nab] = A(res) # add result to dict + + return self._mixed_forms[nab] + + representative = get_form + +class CharacteristicCohomologyClassRing_Chern(FiniteGCAlgebra): + r""" + + """ + Element = CharacteristicCohomologyClass_Chern + + def __init__(self, base, vbundle): + r""" + + """ + self._vbundle = vbundle + self._domain = vbundle._base_space + dim = self._domain._dim + ran = min(vbundle._rank, dim // 2) + names = tuple(f'c_{i}({vbundle._name})' for i in range(1, ran + 1)) + degrees = tuple(2*i for i in range(1, ran + 1)) + super().__init__(base=base, names=names, degrees=degrees, + max_degree=dim) #***************************************************************************** # ALGORITHMS #***************************************************************************** -from sage.misc.fast_methods import Singleton -from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method -from sage.misc.abstract_method import abstract_method -from sage.manifolds.differentiable.affine_connection import AffineConnection -from sage.manifolds.differentiable.bundle_connection import BundleConnection +def fast_wedge_power(form, n): + r""" + Return the wedge product power of `form` using a square-and-wedge algorithm. + """ + if n == 0: + return form._domain._one_scalar_field + elif n < 0: + raise ValueError("'n' must be non-negative") + val = form + while not (n & 1): + print(n) + val = val.wedge(val) + n >>= 1 + + # Now multiply together the correct factors form^(2^i) + res = val + n >>= 1 + while n: + val = val.wedge(val) + if n & 1: + res = val.wedge(res) + n >>= 1 + + return res class Algorithm_generic(SageObject): r""" Algorithm class to generate characteristic forms. """ @cached_method - def get(self, nabla): + def get(self, nab): r""" Return the global characteristic form w.r.t. a given connection. """ - if isinstance(nabla, AffineConnection): - vbundle = nabla._domain.tangent_bundle() - elif isinstance(nabla, BundleConnection): - vbundle = nabla._vbundle + if isinstance(nab, AffineConnection): + vbundle = nab._domain.tangent_bundle() + elif isinstance(nab, BundleConnection): + vbundle = nab._vbundle else: - raise TypeError(f'{nabla} must be a connection') - dom = nabla._domain - res = dom.mixed_form() - for frame in dom._get_min_covering(nabla._coefficients): - cmatrix = [[nabla.curvature_form(i, j, frame) + raise TypeError(f'{nab} must be a connection') + dom = nab._domain + res = [dom.diff_form(i) for i in range(dom._dim + 1)] + for frame in dom._get_min_covering(nab._coefficients): + cmatrix = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] for i in vbundle.irange()] res_loc = self.get_local(cmatrix) - res.set_restriction(res_loc) + for form, loc_form in zip(res, res_loc): + form.set_restriction(loc_form) return res @abstract_method @@ -71,20 +161,20 @@ def get_local(self, cmat): dim = dom._dim ran = min(rk, dim//2) fac = I / (2*pi) - res = dom.mixed_form_algebra().one() + res = [dom._one_scalar_field] + res += [dom.diff_form_module(i).zero() for i in range(1, dom._dim + 1)] m = cmat for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / k - res += fac * c + res[2*k] = fac * c for i in range(rk): m[i][i] += c fac *= I / (2*pi) m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - res -= fac * sum(m[i][i] for i in range(rk)) / ran + res[2*ran] = -fac * sum(m[i][i] for i in range(rk)) / ran return res - class PontryaginAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Pontryagin forms. @@ -100,19 +190,20 @@ def get_local(self, cmat): dim = dom._dim ran = min(rk//2, dim//4) fac = -1 / (2*pi)**2 - res = dom.mixed_form_algebra().one() + res = [dom._one_scalar_field] + res += [dom.diff_form_module(i).zero() for i in range(1, dom._dim + 1)] m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / (2*k) - res += fac * c + res[4*k] = fac * c for i in range(rk): m[i][i] += c fac *= -1 / (2*pi)**2 m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - res -= fac * sum(m[i][i] for i in range(rk)) / (2*ran) + res[4*ran] = -fac * sum(m[i][i] for i in range(rk)) / (2*ran) return res class EulerAlgorithm(Singleton, Algorithm_generic): @@ -125,8 +216,6 @@ def get_local(self, cmat): """ from sage.symbolic.constants import pi - dom = cmat[0][0]._domain - A = dom.mixed_form_algebra() rk = len(cmat) ran = rk // 2 m = a = [cmat[i].copy() for i in range(rk)] @@ -142,4 +231,4 @@ def get_local(self, cmat): for j in range(rk)] for i in range(rk)] c = -sum(m[i][i] for i in range(rk)) / (2*rk) c *= (-1/(2*pi))**rk # normalize - return A(c) + return [c] From 932e1280a55deb06b503763481815f67e4fad90d Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 17 Aug 2021 18:45:02 +0200 Subject: [PATCH 093/355] Trac #29581: element constructor --- .../characteristic_cohomology_class.py | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 70023ee5db9..d16075f2758 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1,4 +1,3 @@ -from sage.manifolds.differentiable.de_rham_cohomology import DeRhamCohomologyClass from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement from sage.misc.fast_methods import Singleton @@ -67,6 +66,17 @@ def get_form(self, nab): representative = get_form + def set_name(self, name=None, latex_name=None): + r""" + Set the name and latex name of ``self``. + """ + if name is not None: + self._name = name + if latex_name is None: + self._latex_name = self._name + if latex_name is not None: + self._latex_name = latex_name + class CharacteristicCohomologyClassRing_Chern(FiniteGCAlgebra): r""" @@ -86,6 +96,31 @@ def __init__(self, base, vbundle): super().__init__(base=base, names=names, degrees=degrees, max_degree=dim) + def _element_constructor_(self, x, name=None, latex_name=None): + r""" + + """ + R = self.base_ring() + + if x in R: + one_basis = self.one_basis() + d = {one_basis: R(x)} + elif x in self: + d = x._monomial_coefficients + # x is an element of the basis enumerated set; + # This is a very ugly way of testing this + elif ((hasattr(self._indices, 'element_class') and + isinstance(self._indices.element_class, type) and + isinstance(x, self._indices.element_class)) or + self.parent()(x) == self._indices): + d = {x: R.one()} + elif x in self._indices: + d = {self._indices(x): R.one()} + else: + raise TypeError(f"do not know how to make x (= {x}) an element of self (={self})") + + return self.element_class(self, d, name=name, latex_name=latex_name) + #***************************************************************************** # ALGORITHMS #***************************************************************************** @@ -152,6 +187,11 @@ class ChernAlgorithm(Singleton, Algorithm_generic): def get_local(self, cmat): r""" Return the local Chern forms for a given curvature matrix. + + .. ALGORITHM:: + + The algorithm is based on the Faddeev-LeVerrier algorithm for the + characteristic polynomial. """ from sage.symbolic.constants import pi from sage.libs.pynac.pynac import I @@ -182,6 +222,11 @@ class PontryaginAlgorithm(Singleton, Algorithm_generic): def get_local(self, cmat): r""" Return the local Pontryagin forms for a given curvature matrix. + + .. ALGORITHM:: + + The algorithm is based on the Faddeev-LeVerrier algorithm for the + characteristic polynomial. """ from sage.symbolic.constants import pi @@ -213,6 +258,11 @@ class EulerAlgorithm(Singleton, Algorithm_generic): def get_local(self, cmat): r""" Return the local Euler form for a given curvature matrix. + + .. ALGORITHM:: + + The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for + the Pfaffian. """ from sage.symbolic.constants import pi From 6688740017097a79d7995101889cea097ee5c653 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 17 Aug 2021 19:13:43 +0200 Subject: [PATCH 094/355] Trac #29581: naming --- .../characteristic_cohomology_class.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index d16075f2758..efdc4479375 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -15,10 +15,11 @@ def __init__(self, parent, x, name=None, latex_name=None): r""" """ - self._name = name - if latex_name is None: - self._latex_name = self._name - else: + if name is not None: + self._name = name + if latex_name is None: + self._latex_name = self._name + if latex_name is not None: self._latex_name = latex_name self._mixed_forms = {} # dict. of mixed forms w.r.t. this class # (key: bundle connection) @@ -33,8 +34,22 @@ def _repr_(self): else: name = self._name vbundle = self.parent()._vbundle + name = f'({name})({vbundle._name})' return f'Characteristic cohomology class {name} over the {vbundle}' + def _latex_(self): + r""" + + """ + if self._latex_name is None: + latex = super()._latex_() + else: + latex = self._name + vbundle = self.parent()._vbundle + latex = r'\left(' + latex + r'\right)\right(' + latex += vbundle._latex_name + r'\right)' + return latex + def get_form(self, nab): r""" @@ -91,7 +106,7 @@ def __init__(self, base, vbundle): self._domain = vbundle._base_space dim = self._domain._dim ran = min(vbundle._rank, dim // 2) - names = tuple(f'c_{i}({vbundle._name})' for i in range(1, ran + 1)) + names = tuple(f'c_{i}' for i in range(1, ran + 1)) degrees = tuple(2*i for i in range(1, ran + 1)) super().__init__(base=base, names=names, degrees=degrees, max_degree=dim) From 61291f406b886abb9a509955355da749fc99a8d6 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 17 Aug 2021 19:15:38 +0200 Subject: [PATCH 095/355] Trac #29581: minor fixes --- .../differentiable/characteristic_cohomology_class.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index efdc4479375..6963f4ceb7c 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -15,11 +15,10 @@ def __init__(self, parent, x, name=None, latex_name=None): r""" """ - if name is not None: - self._name = name - if latex_name is None: - self._latex_name = self._name - if latex_name is not None: + self._name = name + if latex_name is None: + self._latex_name = self._name + else: self._latex_name = latex_name self._mixed_forms = {} # dict. of mixed forms w.r.t. this class # (key: bundle connection) @@ -120,7 +119,7 @@ def _element_constructor_(self, x, name=None, latex_name=None): if x in R: one_basis = self.one_basis() d = {one_basis: R(x)} - elif x in self: + elif isinstance(x, CharacteristicCohomologyClass_Chern): d = x._monomial_coefficients # x is an element of the basis enumerated set; # This is a very ugly way of testing this From 60318775e9c530c32280ba1bfa819cb9ac978bd1 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 17 Aug 2021 22:51:56 +0200 Subject: [PATCH 096/355] Trac #29581: return only list of generators --- .../characteristic_cohomology_class.py | 79 ++++++++++++------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 6963f4ceb7c..3aee80e4963 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -34,7 +34,7 @@ def _repr_(self): name = self._name vbundle = self.parent()._vbundle name = f'({name})({vbundle._name})' - return f'Characteristic cohomology class {name} over the {vbundle}' + return f'Characteristic cohomology class {name} over the {vbundle}' def _latex_(self): r""" @@ -43,7 +43,7 @@ def _latex_(self): if self._latex_name is None: latex = super()._latex_() else: - latex = self._name + latex = self._latex_name vbundle = self.parent()._vbundle latex = r'\left(' + latex + r'\right)\right(' latex += vbundle._latex_name + r'\right)' @@ -67,30 +67,52 @@ def get_form(self, nab): c = ChernAlgorithm().get(nab) parent = self.parent() - degrees = parent._degrees grading = parent.print_options()['sorting_key'] res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] for ind, coeff in self: deg = grading(ind) - gen_pow = [fast_wedge_power(c[d], i) for i, d in zip(ind, degrees)] + gen_pow = [fast_wedge_power(f, i) for f, i in zip(c, ind)] res[deg] += coeff * reduce(lambda x, y: x.wedge(y), gen_pow) - self._mixed_forms[nab] = A(res) # add result to dict + + # prepare result: + res = A(res) + + # preparse names (put brackets around) + vbundle = self.parent()._vbundle + if self._name is None: + name = f'({super()._repr_()})' + else: + name = f'({self._name})' + if self._latex_name is None: + latex_name = r'\left(' + super()._latex_() + r'\right)' + else: + latex_name = r'\left(' + self._latex_name + r'\right)' + # appendix + append_name = f'({vbundle._name}, {nab._name})' + append_latex_name = r'\left(' + vbundle._latex_name + append_latex_name += ', ' + nab._latex_name + r'\right)' + + # set names of components + for i in range(dom._dim // 2 + 1): + comp_name = name + f'_{i}' + append_name + comp_latex_name = latex_name + r'_{' + str(i) + '}' + comp_latex_name += append_latex_name + res[2*i].set_name(name=comp_name, + latex_name=comp_latex_name) + + # set global names + res._name = name + append_name + res._latex_name = latex_name + append_latex_name + + res.set_immutable() # set result immutable + + # add result to dict + self._mixed_forms[nab] = res return self._mixed_forms[nab] representative = get_form - def set_name(self, name=None, latex_name=None): - r""" - Set the name and latex name of ``self``. - """ - if name is not None: - self._name = name - if latex_name is None: - self._latex_name = self._name - if latex_name is not None: - self._latex_name = latex_name - class CharacteristicCohomologyClassRing_Chern(FiniteGCAlgebra): r""" @@ -171,7 +193,8 @@ class Algorithm_generic(SageObject): @cached_method def get(self, nab): r""" - Return the global characteristic form w.r.t. a given connection. + Return the global characteristic forms of the generators w.r.t. a given + connection. """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() @@ -180,14 +203,18 @@ def get(self, nab): else: raise TypeError(f'{nab} must be a connection') dom = nab._domain - res = [dom.diff_form(i) for i in range(dom._dim + 1)] + res = [] # will be specified within first iteration for frame in dom._get_min_covering(nab._coefficients): cmatrix = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] for i in vbundle.irange()] res_loc = self.get_local(cmatrix) + if not res: + # until now, degrees of generators were unknown + res = [dom.diff_form(loc_form.degree()) for loc_form in res_loc] for form, loc_form in zip(res, res_loc): form.set_restriction(loc_form) + # TODO: make res immutable? return res @abstract_method @@ -215,18 +242,17 @@ def get_local(self, cmat): dim = dom._dim ran = min(rk, dim//2) fac = I / (2*pi) - res = [dom._one_scalar_field] - res += [dom.diff_form_module(i).zero() for i in range(1, dom._dim + 1)] + res = [] m = cmat for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / k - res[2*k] = fac * c + res.append(fac * c) for i in range(rk): m[i][i] += c fac *= I / (2*pi) m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - res[2*ran] = -fac * sum(m[i][i] for i in range(rk)) / ran + res.append(-fac * sum(m[i][i] for i in range(rk)) / ran) return res class PontryaginAlgorithm(Singleton, Algorithm_generic): @@ -249,20 +275,19 @@ def get_local(self, cmat): dim = dom._dim ran = min(rk//2, dim//4) fac = -1 / (2*pi)**2 - res = [dom._one_scalar_field] - res += [dom.diff_form_module(i).zero() for i in range(1, dom._dim + 1)] + res = [] m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / (2*k) - res[4*k] = fac * c + res.append(fac * c) for i in range(rk): m[i][i] += c fac *= -1 / (2*pi)**2 m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - res[4*ran] = -fac * sum(m[i][i] for i in range(rk)) / (2*ran) + res.append(-fac * sum(m[i][i] for i in range(rk)) / (2*ran)) return res class EulerAlgorithm(Singleton, Algorithm_generic): @@ -293,6 +318,6 @@ def get_local(self, cmat): m[i][i] += c m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - c = -sum(m[i][i] for i in range(rk)) / (2*rk) + c = -sum(m[i][i] for i in range(rk)) / (2*rk) # Pfaffian mod sign c *= (-1/(2*pi))**rk # normalize return [c] From 0c7587f759b9555404fd417ee042e99fbb4ae02d Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 10:51:18 +0200 Subject: [PATCH 097/355] Trac #29581: parent deals with different cases, element stays generic --- .../characteristic_cohomology_class.py | 148 ++++++++++++------ .../pseudo_riemannian_submanifold.py | 14 +- 2 files changed, 115 insertions(+), 47 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 3aee80e4963..2bb387aa6e6 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1,3 +1,16 @@ +r""" +Characteristic cohomology classes +""" + +#****************************************************************************** +# Copyright (C) 2021 Michael Jung +# +# 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. +# https://www.gnu.org/licenses/ +#****************************************************************************** + from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement from sage.misc.fast_methods import Singleton @@ -7,10 +20,12 @@ from sage.manifolds.differentiable.affine_connection import AffineConnection from sage.manifolds.differentiable.bundle_connection import BundleConnection -class CharacteristicCohomologyClass_Chern(IndexedFreeModuleElement): + +class CharacteristicCohomologyClass(IndexedFreeModuleElement): r""" """ + def __init__(self, parent, x, name=None, latex_name=None): r""" @@ -20,7 +35,7 @@ def __init__(self, parent, x, name=None, latex_name=None): self._latex_name = self._name else: self._latex_name = latex_name - self._mixed_forms = {} # dict. of mixed forms w.r.t. this class + self._mixed_forms = {} # dict. of characteristic forms of `self` # (key: bundle connection) super().__init__(parent, x) @@ -34,7 +49,7 @@ def _repr_(self): name = self._name vbundle = self.parent()._vbundle name = f'({name})({vbundle._name})' - return f'Characteristic cohomology class {name} over the {vbundle}' + return f'Characteristic cohomology class {name} of the {vbundle}' def _latex_(self): r""" @@ -65,20 +80,24 @@ def get_form(self, nab): else: # non-trivial case from functools import reduce - c = ChernAlgorithm().get(nab) parent = self.parent() + + gen_algorithm = parent._algorithm # this is a list + # give list of representatives of generators + gen_forms = sum(a.get(nab) for a in gen_algorithm) grading = parent.print_options()['sorting_key'] - res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] - for ind, coeff in self: + res = [dom.diff_form_module(i).zero() + for i in range(dom._dim + 1)] + for ind, c in self: deg = grading(ind) - gen_pow = [fast_wedge_power(f, i) for f, i in zip(c, ind)] - res[deg] += coeff * reduce(lambda x, y: x.wedge(y), gen_pow) + gen_pow = [fast_wedge_power(f, i) + for f, i in zip(gen_forms, ind)] + res[deg] += c * reduce(lambda x, y: x.wedge(y), gen_pow) - # prepare result: - res = A(res) + res = A(res) # convert result into mixed form - # preparse names (put brackets around) - vbundle = self.parent()._vbundle + # preparse names + vbundle = parent._vbundle if self._name is None: name = f'({super()._repr_()})' else: @@ -93,12 +112,16 @@ def get_form(self, nab): append_latex_name += ', ' + nab._latex_name + r'\right)' # set names of components - for i in range(dom._dim // 2 + 1): + from sage.arith.misc import gcd + + step = gcd(parent._degrees) # step size of (possibly) non-zero + for i in range(dom._dim // step + 1): + # enumerate (possibly) non-zero components comp_name = name + f'_{i}' + append_name comp_latex_name = latex_name + r'_{' + str(i) + '}' comp_latex_name += append_latex_name - res[2*i].set_name(name=comp_name, - latex_name=comp_latex_name) + res[step * i].set_name(name=comp_name, + latex_name=comp_latex_name) # set global names res._name = name + append_name @@ -106,18 +129,18 @@ def get_form(self, nab): res.set_immutable() # set result immutable - # add result to dict - self._mixed_forms[nab] = res + self._mixed_forms[nab] = res # cache result in dict return self._mixed_forms[nab] representative = get_form -class CharacteristicCohomologyClassRing_Chern(FiniteGCAlgebra): + +class CharacteristicCohomologyClassRing(FiniteGCAlgebra): r""" """ - Element = CharacteristicCohomologyClass_Chern + Element = CharacteristicCohomologyClass def __init__(self, base, vbundle): r""" @@ -126,22 +149,39 @@ def __init__(self, base, vbundle): self._vbundle = vbundle self._domain = vbundle._base_space dim = self._domain._dim - ran = min(vbundle._rank, dim // 2) - names = tuple(f'c_{i}' for i in range(1, ran + 1)) - degrees = tuple(2*i for i in range(1, ran + 1)) + rk = vbundle._rank + # if vbundle is complex: + ran = min(rk, dim // 2) + names = [f'c_{i}' for i in range(1, ran + 1)] + degrees = [2 * i for i in range(1, ran + 1)] + self._algorithm = [ChernAlgorithm()] + # if vbundle is real: + # ran = min(rk // 2, dim // 4) + # names = [f'p_{i}' for i in range(1, ran + 1)] + # degrees = [4 * i for i in range(1, ran + 1)] + # self._algorithm = [PontryaginAlgorithm()] + # if vbundle is orientable: + # names += ['e'] + # degrees += [rk] + # # TODO: add relation e^2=p_k for dim=2*k + # # add algorithm for additional generator + # self._algorithm += [EulerAlgorithm()] + + names = tuple(names) # hashable + degrees = tuple(degrees) # hashable super().__init__(base=base, names=names, degrees=degrees, max_degree=dim) def _element_constructor_(self, x, name=None, latex_name=None): r""" - + Convert ``x`` into ``self``. """ R = self.base_ring() if x in R: one_basis = self.one_basis() d = {one_basis: R(x)} - elif isinstance(x, CharacteristicCohomologyClass_Chern): + elif isinstance(x, CharacteristicCohomologyClass): d = x._monomial_coefficients # x is an element of the basis enumerated set; # This is a very ugly way of testing this @@ -153,17 +193,20 @@ def _element_constructor_(self, x, name=None, latex_name=None): elif x in self._indices: d = {self._indices(x): R.one()} else: - raise TypeError(f"do not know how to make x (= {x}) an element of self (={self})") + raise TypeError(f"do not know how to make x (= {x}) " + f"an element of self (={self})") return self.element_class(self, d, name=name, latex_name=latex_name) -#***************************************************************************** + +# ***************************************************************************** # ALGORITHMS -#***************************************************************************** +# ***************************************************************************** def fast_wedge_power(form, n): r""" - Return the wedge product power of `form` using a square-and-wedge algorithm. + Return the wedge product power of `form` using a square-and-wedge + algorithm. """ if n == 0: return form._domain._one_scalar_field @@ -186,10 +229,12 @@ def fast_wedge_power(form, n): return res + class Algorithm_generic(SageObject): r""" - Algorithm class to generate characteristic forms. + Algorithm class to compute the characteristic forms of the generators. """ + @cached_method def get(self, nab): r""" @@ -211,7 +256,8 @@ def get(self, nab): res_loc = self.get_local(cmatrix) if not res: # until now, degrees of generators were unknown - res = [dom.diff_form(loc_form.degree()) for loc_form in res_loc] + res = [dom.diff_form(loc_form.degree()) + for loc_form in res_loc] for form, loc_form in zip(res, res_loc): form.set_restriction(loc_form) # TODO: make res immutable? @@ -219,15 +265,21 @@ def get(self, nab): @abstract_method def get_local(self, cmat): + r""" + Abstract method to get the local forms of the generators w.r.t. a given + curvature matrix `cmat`. + """ pass + class ChernAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Chern forms. """ + def get_local(self, cmat): r""" - Return the local Chern forms for a given curvature matrix. + Return the local Chern forms w.r.t. a given curvature matrix. .. ALGORITHM:: @@ -240,8 +292,8 @@ def get_local(self, cmat): dom = cmat[0][0]._domain rk = len(cmat) dim = dom._dim - ran = min(rk, dim//2) - fac = I / (2*pi) + ran = min(rk, dim // 2) + fac = I / (2 * pi) res = [] m = cmat for k in range(1, ran): @@ -249,19 +301,21 @@ def get_local(self, cmat): res.append(fac * c) for i in range(rk): m[i][i] += c - fac *= I / (2*pi) + fac *= I / (2 * pi) m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] res.append(-fac * sum(m[i][i] for i in range(rk)) / ran) return res + class PontryaginAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Pontryagin forms. """ + def get_local(self, cmat): r""" - Return the local Pontryagin forms for a given curvature matrix. + Return the local Pontryagin forms w.r.t. a given curvature matrix. .. ALGORITHM:: @@ -273,30 +327,32 @@ def get_local(self, cmat): dom = cmat[0][0]._domain rk = len(cmat) dim = dom._dim - ran = min(rk//2, dim//4) - fac = -1 / (2*pi)**2 + ran = min(rk // 2, dim // 4) + fac = -1 / (2 * pi) ** 2 res = [] m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] for k in range(1, ran): - c = -sum(m[i][i] for i in range(rk)) / (2*k) + c = -sum(m[i][i] for i in range(rk)) / (2 * k) res.append(fac * c) for i in range(rk): m[i][i] += c - fac *= -1 / (2*pi)**2 + fac *= -1 / (2 * pi) ** 2 m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - res.append(-fac * sum(m[i][i] for i in range(rk)) / (2*ran)) + res.append(-fac * sum(m[i][i] for i in range(rk)) / (2 * ran)) return res + class EulerAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Euler forms. """ + def get_local(self, cmat): r""" - Return the local Euler form for a given curvature matrix. + Return the local Euler form for w.r.t. a given curvature matrix. .. ALGORITHM:: @@ -309,15 +365,15 @@ def get_local(self, cmat): ran = rk // 2 m = a = [cmat[i].copy() for i in range(rk)] for i in range(0, rk, 2): - m[i], m[i+1] = m[i+1], m[i] # swap entries + m[i], m[i + 1] = m[i + 1], m[i] # swap entries for k in range(rk): - m[k][i+1] = -m[k][i+1] + m[k][i + 1] = -m[k][i + 1] for k in range(1, ran): - c = -sum(m[i][i] for i in range(rk)) / (2*k) + c = -sum(m[i][i] for i in range(rk)) / (2 * k) for i in range(rk): m[i][i] += c m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - c = -sum(m[i][i] for i in range(rk)) / (2*rk) # Pfaffian mod sign - c *= (-1/(2*pi))**rk # normalize + c = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign + c *= (-1 / (2 * pi)) ** rk # normalize return [c] diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 5e5869d929f..42fb46700c1 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -537,7 +537,7 @@ def first_fundamental_form(self): """ if self._first_fundamental_form is None: - self._first_fundamental_form = self.metric() + self._first_fundamental_form = super().metric() self._first_fundamental_form.set( self._immersion.pullback(self.ambient_metric())) self._first_fundamental_form.set_name("gamma", r"\gamma") @@ -545,6 +545,18 @@ def first_fundamental_form(self): induced_metric = first_fundamental_form + def metric(self, name=None, signature=None, latex_name=None, + dest_map=None): + r""" + Return the induced metric on ``self`` or define a new metric tensor on + the manifold. + + """ + if name is None and self._metric is None: + return self.first_fundamental_form() + return super().metric(name=name, signature=signature, + latex_name=latex_name, dest_map=dest_map) + @cached_method def difft(self): r""" From 28d2d84271a3e1516556a8364b1114dd6edaa992 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 10:54:44 +0200 Subject: [PATCH 098/355] Trac #29581: revert mistaken merge --- .../pseudo_riemannian_submanifold.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 42fb46700c1..5e5869d929f 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -537,7 +537,7 @@ def first_fundamental_form(self): """ if self._first_fundamental_form is None: - self._first_fundamental_form = super().metric() + self._first_fundamental_form = self.metric() self._first_fundamental_form.set( self._immersion.pullback(self.ambient_metric())) self._first_fundamental_form.set_name("gamma", r"\gamma") @@ -545,18 +545,6 @@ def first_fundamental_form(self): induced_metric = first_fundamental_form - def metric(self, name=None, signature=None, latex_name=None, - dest_map=None): - r""" - Return the induced metric on ``self`` or define a new metric tensor on - the manifold. - - """ - if name is None and self._metric is None: - return self.first_fundamental_form() - return super().metric(name=name, signature=signature, - latex_name=latex_name, dest_map=dest_map) - @cached_method def difft(self): r""" From 2cabd839d55e5c0f3ba2f8d0194bcae6ce31397c Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 11:06:57 +0200 Subject: [PATCH 099/355] Trac #29581: add some comments --- .../differentiable/characteristic_cohomology_class.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 2bb387aa6e6..362811571a2 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -352,7 +352,7 @@ class EulerAlgorithm(Singleton, Algorithm_generic): def get_local(self, cmat): r""" - Return the local Euler form for w.r.t. a given curvature matrix. + Return the local Euler form w.r.t. a given curvature matrix. .. ALGORITHM:: @@ -376,4 +376,7 @@ def get_local(self, cmat): for j in range(rk)] for i in range(rk)] c = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign c *= (-1 / (2 * pi)) ** rk # normalize + + # TODO: incorporate orientation (overwrite `get`?) and metric + return [c] From 1a9b7d924d6f082cbd4ab3c96951bec0f2087a0b Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 14:41:57 +0200 Subject: [PATCH 100/355] Trac #29581: compute Euler forms for arbitrary positively oriented frames --- .../characteristic_cohomology_class.py | 89 ++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 362811571a2..19672a6807d 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -17,8 +17,9 @@ from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method -from sage.manifolds.differentiable.affine_connection import AffineConnection -from sage.manifolds.differentiable.bundle_connection import BundleConnection +from .affine_connection import AffineConnection +from .bundle_connection import BundleConnection +from .levi_civita_connection import LeviCivitaConnection class CharacteristicCohomologyClass(IndexedFreeModuleElement): @@ -83,7 +84,9 @@ def get_form(self, nab): parent = self.parent() gen_algorithm = parent._algorithm # this is a list - # give list of representatives of generators + # concatenate generators + print(gen_algorithm[0].get(nab)) + print(gen_algorithm[1].get(nab)) gen_forms = sum(a.get(nab) for a in gen_algorithm) grading = parent.print_options()['sorting_key'] res = [dom.diff_form_module(i).zero() @@ -127,7 +130,7 @@ def get_form(self, nab): res._name = name + append_name res._latex_name = latex_name + append_latex_name - res.set_immutable() # set result immutable + res.set_immutable() self._mixed_forms[nab] = res # cache result in dict @@ -150,22 +153,26 @@ def __init__(self, base, vbundle): self._domain = vbundle._base_space dim = self._domain._dim rk = vbundle._rank - # if vbundle is complex: - ran = min(rk, dim // 2) - names = [f'c_{i}' for i in range(1, ran + 1)] - degrees = [2 * i for i in range(1, ran + 1)] - self._algorithm = [ChernAlgorithm()] - # if vbundle is real: - # ran = min(rk // 2, dim // 4) - # names = [f'p_{i}' for i in range(1, ran + 1)] - # degrees = [4 * i for i in range(1, ran + 1)] - # self._algorithm = [PontryaginAlgorithm()] - # if vbundle is orientable: - # names += ['e'] - # degrees += [rk] - # # TODO: add relation e^2=p_k for dim=2*k - # # add algorithm for additional generator - # self._algorithm += [EulerAlgorithm()] + if vbundle._field_type == 'complex': + ran = min(rk, dim // 2) + names = [f'c_{i}' for i in range(1, ran + 1)] + degrees = [2 * i for i in range(1, ran + 1)] + self._algorithm = [ChernAlgorithm()] + elif vbundle._field_type == 'real': + ran = min(rk // 2, dim // 4) + names = [f'p_{i}' for i in range(1, ran + 1)] + degrees = [4 * i for i in range(1, ran + 1)] + self._algorithm = [PontryaginAlgorithm()] + if vbundle.has_orientation(): + # add Euler class generator + names += ['e'] + degrees += [rk] + self._algorithm += [EulerAlgorithm()] + # TODO: add relation e^2=p_k for dim=2*k + else: + raise TypeError(f'Characteristic cohomology classes not supported ' + f'for vector bundles with ' + f'field type {vbundle._field_type}') names = tuple(names) # hashable degrees = tuple(degrees) # hashable @@ -248,8 +255,14 @@ def get(self, nab): else: raise TypeError(f'{nab} must be a connection') dom = nab._domain + # if the bundle is orientable, we always opt for positively + # oriented frames due to unification between Pontryagin and Euler class + if vbundle.has_orientation(): + frames = vbundle.orientation() + else: + frames = nab._coefficients res = [] # will be specified within first iteration - for frame in dom._get_min_covering(nab._coefficients): + for frame in dom._get_min_covering(frames): cmatrix = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] for i in vbundle.irange()] @@ -260,7 +273,7 @@ def get(self, nab): for loc_form in res_loc] for form, loc_form in zip(res, res_loc): form.set_restriction(loc_form) - # TODO: make res immutable? + # TODO: make `res` immutable? return res @abstract_method @@ -350,9 +363,26 @@ class EulerAlgorithm(Singleton, Algorithm_generic): Algorithm class to generate Euler forms. """ + @cached_method + def get(self, nab): + r""" + Return the global characteristic forms of the generators w.r.t. a given + connection. + """ + if not isinstance(nab, LeviCivitaConnection): + raise TypeError('Euler forms are currently only supported for ' + 'Levi-Civita connections') + [e] = super().get(nab) # apply algorithm; not the Euler form yet + g = nab._metric + det = g.det() + if det.is_trivial_zero(): + raise ValueError(f'metric {g} must be non-degenerate') + res = e / abs(det.sqrt()) # this is the Euler form + return [res] + def get_local(self, cmat): r""" - Return the local Euler form w.r.t. a given curvature matrix. + Return the normalized Pfaffian w.r.t. a given curvature matrix. .. ALGORITHM:: @@ -369,14 +399,11 @@ def get_local(self, cmat): for k in range(rk): m[k][i + 1] = -m[k][i + 1] for k in range(1, ran): - c = -sum(m[i][i] for i in range(rk)) / (2 * k) + e = -sum(m[i][i] for i in range(rk)) / (2 * k) for i in range(rk): - m[i][i] += c + m[i][i] += e m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - c = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign - c *= (-1 / (2 * pi)) ** rk # normalize - - # TODO: incorporate orientation (overwrite `get`?) and metric - - return [c] + e = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign + e *= (-1 / (2 * pi)) ** rk # normalize + return [e] From 815392c4bcf2a6177cecbcc24ae3dc73372fe743 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 18:58:49 +0200 Subject: [PATCH 101/355] Trac #29581: fix some bugs + treat Euler case --- .../characteristic_cohomology_class.py | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 19672a6807d..9b4bc49d5c3 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -80,14 +80,14 @@ def get_form(self, nab): self._mixed_forms[nab] = A(dom._zero_scalar_field) else: # non-trivial case from functools import reduce + from itertools import chain parent = self.parent() gen_algorithm = parent._algorithm # this is a list # concatenate generators - print(gen_algorithm[0].get(nab)) - print(gen_algorithm[1].get(nab)) - gen_forms = sum(a.get(nab) for a in gen_algorithm) + gen_forms = list(chain.from_iterable(a.get(nab) + for a in gen_algorithm)) grading = parent.print_options()['sorting_key'] res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] @@ -255,14 +255,8 @@ def get(self, nab): else: raise TypeError(f'{nab} must be a connection') dom = nab._domain - # if the bundle is orientable, we always opt for positively - # oriented frames due to unification between Pontryagin and Euler class - if vbundle.has_orientation(): - frames = vbundle.orientation() - else: - frames = nab._coefficients res = [] # will be specified within first iteration - for frame in dom._get_min_covering(frames): + for frame in dom._get_min_covering(nab._coefficients): cmatrix = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] for i in vbundle.irange()] @@ -306,6 +300,8 @@ def get_local(self, cmat): rk = len(cmat) dim = dom._dim ran = min(rk, dim // 2) + if ran < 1: + return [] # nothing to compute fac = I / (2 * pi) res = [] m = cmat @@ -341,6 +337,8 @@ def get_local(self, cmat): rk = len(cmat) dim = dom._dim ran = min(rk // 2, dim // 4) + if ran < 2: + return [] # nothing to compute fac = -1 / (2 * pi) ** 2 res = [] m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) @@ -372,12 +370,28 @@ def get(self, nab): if not isinstance(nab, LeviCivitaConnection): raise TypeError('Euler forms are currently only supported for ' 'Levi-Civita connections') - [e] = super().get(nab) # apply algorithm; not the Euler form yet + dom = nab._domain + vbundle = dom.tangent_bundle() + rk = vbundle._rank + if not vbundle.has_orientation(): + raise ValueError('Euler forms can only be defined for orientable ' + 'vector bundles') + if rk % 2 != 0: + raise ValueError('Euler forms are currently only supported for ' + 'vector bundles with odd rank') + res = dom.diff_form(rk) g = nab._metric - det = g.det() - if det.is_trivial_zero(): - raise ValueError(f'metric {g} must be non-degenerate') - res = e / abs(det.sqrt()) # this is the Euler form + for frame in dom._get_min_covering(vbundle.orientation()): + cmatrix = [[nab.curvature_form(i, j, frame) + for j in vbundle.irange()] + for i in vbundle.irange()] + res_loc = self.get_local(cmatrix) # not the local Euler form + det = g.det(frame) + if det.is_trivial_zero(): + raise ValueError(f'metric {g} must be non-degenerate') + sqrt_det = det.abs().sqrt() + res.set_restriction(res_loc / sqrt_det) # local Euler form + # TODO: make `res` immutable? return [res] def get_local(self, cmat): @@ -405,5 +419,5 @@ def get_local(self, cmat): m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] e = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign - e *= (-1 / (2 * pi)) ** rk # normalize - return [e] + e *= (-1 / (2 * pi)) ** ran # normalize + return e From 62ff48af88ee24979df68297551a540a47dbc1a3 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 18:59:38 +0200 Subject: [PATCH 102/355] Trac #29581: leave comment on to-do --- .../manifolds/differentiable/characteristic_cohomology_class.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 9b4bc49d5c3..7db5b66d33b 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -386,6 +386,7 @@ def get(self, nab): for j in vbundle.irange()] for i in vbundle.irange()] res_loc = self.get_local(cmatrix) # not the local Euler form + # TODO: multiply cmatrix with metric tensor det = g.det(frame) if det.is_trivial_zero(): raise ValueError(f'metric {g} must be non-degenerate') From 5b8632d7b5ac52bfe943660b26ffabe35b2c7a8f Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 22:22:13 +0200 Subject: [PATCH 103/355] Trac #29581: euler form algorithm finished --- .../characteristic_cohomology_class.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 7db5b66d33b..782ab80a921 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -257,10 +257,9 @@ def get(self, nab): dom = nab._domain res = [] # will be specified within first iteration for frame in dom._get_min_covering(nab._coefficients): - cmatrix = [[nab.curvature_form(i, j, frame) - for j in vbundle.irange()] - for i in vbundle.irange()] - res_loc = self.get_local(cmatrix) + cmat = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] + for i in vbundle.irange()] + res_loc = self.get_local(cmat) if not res: # until now, degrees of generators were unknown res = [dom.diff_form(loc_form.degree()) @@ -382,11 +381,12 @@ def get(self, nab): res = dom.diff_form(rk) g = nab._metric for frame in dom._get_min_covering(vbundle.orientation()): - cmatrix = [[nab.curvature_form(i, j, frame) - for j in vbundle.irange()] - for i in vbundle.irange()] - res_loc = self.get_local(cmatrix) # not the local Euler form - # TODO: multiply cmatrix with metric tensor + # (G_s * Ω_s)_ij = g(R(.,.)s_i, s_j) + gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame) + for j in vbundle.irange()) + for k in vbundle.irange()] for i in vbundle.irange()] + res_loc = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const. + # e = 1 / sqrt(|det(G_s)|) * Pf(G_s * Ω_s) mod const. det = g.det(frame) if det.is_trivial_zero(): raise ValueError(f'metric {g} must be non-degenerate') @@ -419,6 +419,6 @@ def get_local(self, cmat): m[i][i] += e m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] - e = -sum(m[i][i] for i in range(rk)) / (2 * rk) # Pfaffian mod sign + e = -sum(m[i][i] for i in range(rk)) / (2 * ran) # Pfaffian mod sign e *= (-1 / (2 * pi)) ** ran # normalize return e From 4afc9f0d0ce1212516c67f6d04617151ef4d0ea3 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 23:01:17 +0200 Subject: [PATCH 104/355] Trac #29581: compute forms only on demand --- .../characteristic_cohomology_class.py | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 782ab80a921..974aa3afe96 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -80,21 +80,17 @@ def get_form(self, nab): self._mixed_forms[nab] = A(dom._zero_scalar_field) else: # non-trivial case from functools import reduce - from itertools import chain parent = self.parent() + algorithm = parent._algorithm - gen_algorithm = parent._algorithm # this is a list - # concatenate generators - gen_forms = list(chain.from_iterable(a.get(nab) - for a in gen_algorithm)) grading = parent.print_options()['sorting_key'] res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] for ind, c in self: deg = grading(ind) - gen_pow = [fast_wedge_power(f, i) - for f, i in zip(gen_forms, ind)] + gen_pow = [algorithm.get_gen_pow(nab, i, ind[i]) + for i in range(len(ind))] res[deg] += c * reduce(lambda x, y: x.wedge(y), gen_pow) res = A(res) # convert result into mixed form @@ -157,17 +153,17 @@ def __init__(self, base, vbundle): ran = min(rk, dim // 2) names = [f'c_{i}' for i in range(1, ran + 1)] degrees = [2 * i for i in range(1, ran + 1)] - self._algorithm = [ChernAlgorithm()] + self._algorithm = ChernAlgorithm() elif vbundle._field_type == 'real': ran = min(rk // 2, dim // 4) names = [f'p_{i}' for i in range(1, ran + 1)] degrees = [4 * i for i in range(1, ran + 1)] - self._algorithm = [PontryaginAlgorithm()] + self._algorithm = PontryaginAlgorithm() if vbundle.has_orientation(): # add Euler class generator - names += ['e'] - degrees += [rk] - self._algorithm += [EulerAlgorithm()] + names = ['e'] + names + degrees = [rk] + degrees + self._algorithm = PontryaginEulerAlgorithm() # TODO: add relation e^2=p_k for dim=2*k else: raise TypeError(f'Characteristic cohomology classes not supported ' @@ -277,6 +273,14 @@ def get_local(self, cmat): """ pass + @cached_method + def get_gen_pow(self, nab, i, n): + r""" + Return the `n`-th power of the `i`-th generator. + """ + if n == 0: + return nab._domain._one_scalar_field # no computation necessary + return fast_wedge_power(self.get(nab)[i], n) class ChernAlgorithm(Singleton, Algorithm_generic): r""" @@ -385,7 +389,7 @@ def get(self, nab): gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame) for j in vbundle.irange()) for k in vbundle.irange()] for i in vbundle.irange()] - res_loc = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const. + [res_loc] = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const. # e = 1 / sqrt(|det(G_s)|) * Pf(G_s * Ω_s) mod const. det = g.det(frame) if det.is_trivial_zero(): @@ -421,4 +425,28 @@ def get_local(self, cmat): for j in range(rk)] for i in range(rk)] e = -sum(m[i][i] for i in range(rk)) / (2 * ran) # Pfaffian mod sign e *= (-1 / (2 * pi)) ** ran # normalize - return e + return [e] + + +class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): + r""" + + """ + def get_local(self, cmat): + r""" + + """ + res = [EulerAlgorithm().get_local(cmat)] # first entry is Euler class + res += PontryaginAlgorithm().get_local(cmat) # rest Pontryagin + return res + + @cached_method + def get_gen_pow(self, nab, i, n): + r""" + Return the `n`-th power of the `i`-th generator. + """ + if n == 0: + return nab._domain._one_scalar_field # no computation necessary + if i == 0: + return fast_wedge_power(EulerAlgorithm().get(nab)[0], n) + return fast_wedge_power(PontryaginAlgorithm().get(nab)[i-1], n) From 201831f1338973a6c5eefb6c9ee61592f9e38f0f Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 18 Aug 2021 23:25:53 +0200 Subject: [PATCH 105/355] Trac #29581: commenting improved --- .../characteristic_cohomology_class.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 974aa3afe96..a13c2047f5f 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -276,7 +276,7 @@ def get_local(self, cmat): @cached_method def get_gen_pow(self, nab, i, n): r""" - Return the `n`-th power of the `i`-th generator. + Return the `n`-th power of the `i`-th generator's characteristic form. """ if n == 0: return nab._domain._one_scalar_field # no computation necessary @@ -430,13 +430,34 @@ def get_local(self, cmat): class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): r""" - + Algorithm class to generate Euler and Pontryagin forms. """ + @cached_method + def get(self, nab): + r""" + Return the global characteristic forms of the generators w.r.t. a given + connection. + + OUTPUT: + + - a list containing the global Euler form in the first entry, and the + global Pontryagin forms in the remaining entries. + + """ + return EulerAlgorithm().get(nab) + PontryaginAlgorithm().get(nab) + def get_local(self, cmat): r""" + Return the local Euler and Pontryagin forms w.r.t. a given curvature + matrix. + + OUTPUT: + + - a list containing the local Euler form in the first entry, and the + local Pontryagin forms in the remaining entries. """ - res = [EulerAlgorithm().get_local(cmat)] # first entry is Euler class + res = EulerAlgorithm().get_local(cmat) # first entry is Euler class res += PontryaginAlgorithm().get_local(cmat) # rest Pontryagin return res From e17fe37d0ea5ecdd1e9932145b908037ed0261cd Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 19 Aug 2021 11:09:51 +0200 Subject: [PATCH 106/355] Trac #29581: comments further improved + _repr_ method --- .../characteristic_cohomology_class.py | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index a13c2047f5f..3e2ff7c8500 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -161,6 +161,7 @@ def __init__(self, base, vbundle): self._algorithm = PontryaginAlgorithm() if vbundle.has_orientation(): # add Euler class generator + # Euler should be first entry; see `PontryaginEulerAlgorithm` names = ['e'] + names degrees = [rk] + degrees self._algorithm = PontryaginEulerAlgorithm() @@ -170,6 +171,9 @@ def __init__(self, base, vbundle): f'for vector bundles with ' f'field type {vbundle._field_type}') + if not names or not degrees: + raise ValueError(f'cannot find any generators') + names = tuple(names) # hashable degrees = tuple(degrees) # hashable super().__init__(base=base, names=names, degrees=degrees, @@ -201,6 +205,14 @@ def _element_constructor_(self, x, name=None, latex_name=None): return self.element_class(self, d, name=name, latex_name=latex_name) + def _repr_(self): + r""" + + """ + vbundle = self.parent()._vbundle + repr = f'Algebra of characteristic cohomology classes of the {vbundle}' + return repr + # ***************************************************************************** # ALGORITHMS @@ -243,6 +255,11 @@ def get(self, nab): r""" Return the global characteristic forms of the generators w.r.t. a given connection. + + OUTPUT: + + - a list containing the generator's global characteristic forms + """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() @@ -269,7 +286,12 @@ def get(self, nab): def get_local(self, cmat): r""" Abstract method to get the local forms of the generators w.r.t. a given - curvature matrix `cmat`. + curvature matrix ``cmat``. + + OUTPUT: + + - a list containing the generator's local characteristic forms + """ pass @@ -282,6 +304,7 @@ def get_gen_pow(self, nab, i, n): return nab._domain._one_scalar_field # no computation necessary return fast_wedge_power(self.get(nab)[i], n) + class ChernAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Chern forms. @@ -291,6 +314,10 @@ def get_local(self, cmat): r""" Return the local Chern forms w.r.t. a given curvature matrix. + OUTPUT: + + - a list containing the local characteristic Chern forms + .. ALGORITHM:: The algorithm is based on the Faddeev-LeVerrier algorithm for the @@ -329,6 +356,10 @@ def get_local(self, cmat): r""" Return the local Pontryagin forms w.r.t. a given curvature matrix. + OUTPUT: + + - a list containing the local characteristic Pontryagin forms + .. ALGORITHM:: The algorithm is based on the Faddeev-LeVerrier algorithm for the @@ -369,6 +400,11 @@ def get(self, nab): r""" Return the global characteristic forms of the generators w.r.t. a given connection. + + OUTPUT: + + - a list containing the global characteristic Euler form + """ if not isinstance(nab, LeviCivitaConnection): raise TypeError('Euler forms are currently only supported for ' @@ -403,6 +439,19 @@ def get_local(self, cmat): r""" Return the normalized Pfaffian w.r.t. a given curvature matrix. + The normalization is given by the factor + `\left(\frac{1}{2 \pi}\right)^{\frac{k}{2}}`, where `k` is the + dimension of the curvature matrix. + + OUTPUT: + + - a list containing the normalized Pfaffian of a given curvature form + + .. NOTE:: + + The result is the local Euler form if ``cmat`` is given w.r.t. an + orthonormal oriented frame. + .. ALGORITHM:: The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for @@ -432,6 +481,7 @@ class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Euler and Pontryagin forms. """ + @cached_method def get(self, nab): r""" From 8e3263c69f8099d8dcbf9faf07999304642c7222 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 19 Aug 2021 15:07:19 +0200 Subject: [PATCH 107/355] Trac #29581: deprecate alias and more --- .../characteristic_cohomology_class.py | 19 +++++++++- .../manifolds/differentiable/vector_bundle.py | 38 ++++++++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 3e2ff7c8500..7ca8e99f448 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -132,7 +132,22 @@ def get_form(self, nab): return self._mixed_forms[nab] - representative = get_form + def representative(self, nab=None): + r""" + Return any representative of ``self``. + + INPUT: + + - ``nab`` -- (default: ``None``) if stated, return the representative + w.r.t. to the connection ``nab``; otherwise an arbitrary already + computed representative will be chosen + + """ + if nab is None: + if not self._mixed_forms: + raise AttributeError('cannot pick a representative') + return next(iter(self._mixed_forms.values())) + return self.get_form(nab) class CharacteristicCohomologyClassRing(FiniteGCAlgebra): @@ -209,7 +224,7 @@ def _repr_(self): r""" """ - vbundle = self.parent()._vbundle + vbundle = self._vbundle repr = f'Algebra of characteristic cohomology classes of the {vbundle}' return repr diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index c40d4d2acf3..709ff479196 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -35,6 +35,8 @@ from sage.rings.real_mpfr import RR from sage.manifolds.vector_bundle import TopologicalVectorBundle from sage.rings.infinity import infinity +from sage.misc.superseded import deprecated_function_alias +from sage.rings.rational_field import QQ class DifferentiableVectorBundle(TopologicalVectorBundle): r""" @@ -163,7 +165,37 @@ def bundle_connection(self, name, latex_name=None): from .bundle_connection import BundleConnection return BundleConnection(self, name, latex_name) - def characteristic_class(self, func, **kwargs): + def characteristic_cohomology_class_ring(self, base=QQ): + r""" + Return the characteristic cohomology class ring of ``self`` over + a given base. + + INPUT: + + - ``base`` -- (default: ``QQ``) base over which the ring should be + constructed; typically that would be `\ZZ`, `\QQ`, `\RR` or the + symbolic ring + + EXAMPLES:: + + sage: M = Manifold(4, 'M', start_index=1) + sage: R = M.tangent_bundle().characteristic_cohomology_class_ring() + sage: R + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + sage: p1 = R.gen(0); p1 + Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM + over the 4-dimensional differentiable manifold M + sage: 1 + p1 + Characteristic cohomology class (1 + p_1)(TM) of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + + """ + from .characteristic_cohomology_class import CharacteristicCohomologyClassRing + + return CharacteristicCohomologyClassRing(base, self) + + def characteristic_cohomology_class(self, func, **kwargs): r""" Return a characteristic class of the given type with respect to the given function. @@ -233,7 +265,7 @@ def characteristic_class(self, func, **kwargs): sage: TM = M.tangent_bundle(); TM Tangent bundle TM over the 4-dimensional Lorentzian manifold M - sage: p = TM.characteristic_class('Pontryagin'); p + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p Characteristic class p of multiplicative type associated to x + 1 on the Tangent bundle TM over the 4-dimensional Lorentzian manifold M @@ -270,6 +302,8 @@ def characteristic_class(self, func, **kwargs): return CharacteristicClass(self, func, class_type=class_type, name=name, latex_name=latex_name) + characteristic_class = deprecated_function_alias(29581, characteristic_cohomology_class) + def diff_degree(self): r""" Return the vector bundle's degree of differentiability. From d6f5d5b5f468b4801a191f68df16152e7a8c7276 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 25 Aug 2021 22:47:49 +0200 Subject: [PATCH 108/355] backport into Dirichlet --- src/sage/rings/all.py | 5 +- src/sage/rings/lazy_laurent_series.py | 438 ----------- src/sage/rings/lazy_laurent_series_ring.py | 797 --------------------- 3 files changed, 1 insertion(+), 1239 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 0b9f1f446c5..02a6eb56f91 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,10 +120,7 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', - 'LazyDirichletSeriesRing', - 'LazyTaylorSeriesRing', - 'LazySymmetricFunctions']) +lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index fad40e5ffec..46535e68974 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -196,9 +196,6 @@ def finite_part(self, degree=None): sage: f = L([1,0,0,2,0,0,0,3], valuation=2); f.finite_part() 3/9^s + 2/5^s + 1/2^s - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = 1/(1+x+y^2); f.finite_part(3) - -x^3 + 2*x*y^2 + x^2 - y^2 - x + 1 """ P = self.parent() L = P._laurent_poly_ring @@ -1066,17 +1063,6 @@ def _acted_upon_(self, scalar, self_on_left): sage: 1 * M is M True - We take care of noncommutative base rings:: - - sage: M = MatrixSpace(ZZ, 2) - sage: L. = LazyTaylorSeriesRing(M) - sage: m = M([[1, 1],[0, 1]]) - sage: n = M([[1, 0],[1, 1]]) - sage: a = L(lambda k: n^k) - sage: (m*a - a*m)[3] - [ 3 0] - [ 0 -3] - """ # With the current design, the coercion model does not have # enough information to detect a priori that this method only @@ -1289,26 +1275,6 @@ def _mul_(self, other): sage: M * L.one() is M True - Similarly for Taylor series:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: (1 - x)*(1 - y) - 1 + (-x-y) + x*y - sage: (1 - x)*(1 - y)*(1 - z) - 1 + (-x-y-z) + (x*y+x*z+y*z) + (-x*y*z) - - We take care of noncommutative base rings:: - - sage: M = MatrixSpace(ZZ, 2) - sage: L. = LazyTaylorSeriesRing(M) - sage: m = M([[1, 1],[0, 1]]) - sage: n = M([[1, 0],[1, 1]]) - sage: a = 1/(1-m*t) - sage: b = 1 + n*t - sage: (b*a-a*b)[20] - [-19 0] - [ 0 19] - Multiplication of series with eventually constant coefficients may yield another such series:: @@ -1322,16 +1288,6 @@ def _mul_(self, other): sage: s1 * t1 - (s * t).approximate_series(42) O(z^42) - Noncommutative:: - - sage: M = MatrixSpace(ZZ, 2) - sage: L. = LazyTaylorSeriesRing(M) - sage: a = L([m], degree=1) - sage: b = n*~(1-t) - sage: (a*b)[0] - [2 1] - [1 1] - """ P = self.parent() left = self._coeff_stream @@ -1961,18 +1917,6 @@ def __call__(self, g): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] - The Frobenius character of the trivial representation can be - expressed as an exponential:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: e = L(lambda n: 1/factorial(n), valuation=0) - sage: p = SymmetricFunctions(QQ).p() - sage: s = SymmetricFunctions(QQ).s() - sage: S = LazySymmetricFunctions(QQ, "x") - sage: f = S(lambda n: p[n]/n, valuation=1) - sage: [s(x) for x in e(f)[:5]] - [s[], s[1], s[2], s[3], s[4]] - """ # f = self and compute f(g) P = g.parent() @@ -2412,388 +2356,6 @@ def _format_series(self, formatter, format_strings=False): return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) -class LazyTaylorSeries(LazyCauchyProductSeries): - r""" - A Taylor series where the coefficients are computed lazily. - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = 1 / (1 - x^2 + y^3); f - 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 - sage: P. = PowerSeriesRing(ZZ, default_prec=101) - sage: g = 1 / (1 - x^2 + y^3); f[100] - g[100] - 0 - - Lazy Taylor series is picklable:: - - sage: g = loads(dumps(f)) - sage: g - 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 - sage: g == f - True - """ - def __call__(self, *g): - r""" - Return the composition of ``self`` with ``g``. - - The arity of ``self`` must be equal to the number of - arguments provided. - - Given two Taylor Series `f` and `g` over the same base ring, the - composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - - - `g = 0` and `val(f) >= 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. - - INPUT: - - - ``g`` -- other series, all of the same parent. - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(QQ) - sage: M. = LazyTaylorSeriesRing(ZZ) - sage: g1 = 1/(1-x); g2 = x+y^2 - sage: p = a^2 + b + 1 - sage: p(g1, g2) - g1^2 - g2 - 1 - O(x,y,z)^7 - - sage: L. = LazyTaylorSeriesRing(QQ) - sage: M. = LazyTaylorSeriesRing(QQ) - - The number of mappings from a set with `m` elements to a set - with `n` elements:: - - sage: Ea = M(lambda n: 1/factorial(n)) - sage: Ex = L(lambda n: 1/factorial(n)*x^n) - sage: Ea(Ex*y)[5] - 1/24*x^4*y + 2/3*x^3*y^2 + 3/4*x^2*y^3 + 1/6*x*y^4 + 1/120*y^5 - - So, there are `3! 2! 2/3 = 8` mappings from a three element - set to a two element set. - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = 1/(1-x-y) - sage: f(f) - Traceback (most recent call last): - ... - ValueError: arity of must be equal to the number of arguments provided - - """ - if len(g) != len(self.parent().variable_names()): - raise ValueError("arity of must be equal to the number of arguments provided") - - # f has finite length - if isinstance(self._coeff_stream, CoefficientStream_exact) and not self._coeff_stream._constant: - # constant polynomial - poly = self.finite_part() - if poly.is_constant(): - return self - return poly(g) - - g0 = g[0] - P = g0.parent() - R = P._coeff_ring - if len(g) == 1: - # we assume that the valuation of self[i](g) is at least i - def coefficient(n): - r = R(0) - for i in range(n+1): - r += self[i]*(g0 ** i)[n] - return r - else: - def coefficient(n): - r = R(0) - for i in range(n+1): - r += self[i](g)[n] - return r - coeff_stream = CoefficientStream_coefficient_function(coefficient, P._coeff_ring, P._sparse, 0) - return P.element_class(P, coeff_stream) - - def change_ring(self, ring): - """ - Return this series with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: s = 2 + z - sage: t = s.change_ring(QQ) - sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) - sage: t.parent() - Lazy Taylor Series Ring in z over Rational Field - """ - from .lazy_laurent_series_ring import LazyTaylorSeriesRing - Q = LazyTaylorSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - - def _format_series(self, formatter, format_strings=False): - """ - Return nonzero ``self`` formatted by ``formatter``. - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(QQ) - sage: f = 1 / (2 - x^2 + y) - sage: f._format_series(repr) - '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' - - sage: f = (2 - x^2 + y) - sage: f._format_series(repr) - '2 + y + (-x^2)' - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, CoefficientStream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length - - atomic_repr = P._coeff_ring._repr_option('element_is_atomic') - mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, CoefficientStream_exact) or cs._constant: - if P._coeff_ring is P.base_ring(): - bigO = ["O(%s)" % P.monomial(1, m)] - else: - bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] - else: - bigO = [] - - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - - return poly - - -class LazySymmetricFunction(LazyCauchyProductSeries): - r""" - A symmetric function where each degree is computed lazily. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(ZZ, "x") - """ - def __call__(self, *args): - r""" - Return the composition of ``self`` with ``args``. - - The arity of ``self`` must be equal to the number of - arguments provided. - - Given two lazy symmetric functions `f` and `g` over the same - base ring, the composition (or plethysm) `(f \circ g)` is - defined if and only if: - - - `g = 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. - - INPUT: - - - ``args`` -- other (lazy) symmetric functions. - - EXAMPLES:: - - sage: P. = QQ[] - sage: s = SymmetricFunctions(P).s() - sage: L = LazySymmetricFunctions(P, "x") - sage: f = s[2]; g = s[3] - sage: L(f)(L(g)) - L(f(g)) - O(x)^7 - - sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] - sage: L(f)(L(g)) - L(f(g)) - O(x)^7 - - sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] - sage: L(f)(L(q*g)) - L(f(q*g)) - O(x)^7 - - The Frobenius character of the permutation action on set - partitions is a plethysm:: - - sage: s = SymmetricFunctions(QQ).s() - sage: S = LazySymmetricFunctions(QQ, "x") - sage: E1 = S(lambda n: s[n], valuation=1) - sage: E = 1 + E1 - sage: P = E(E1) - sage: [s(x) for x in P[:5]] - [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] - - """ - if len(args) != len(self.parent().variable_names()): - raise ValueError("arity must be equal to the number of arguments provided") - from sage.combinat.sf.sfa import is_SymmetricFunction - if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) for g in args): - raise ValueError("all arguments must be (possibly lazy) symmetric functions") - from sage.misc.lazy_list import lazy_list - if len(args) == 1: - g = args[0] - P = g.parent() - R = P._coeff_ring - BR = P.base_ring() - p = R.realization_of().power() - g_p = CoefficientStream_map_coefficients(g._coeff_stream, lambda c: c, p) - try: - degree_one = [BR(x) for x in BR.variable_names_recursive()] - except AttributeError: - try: - degree_one = BR.gens() - except NotImplementedError: - degree_one = [] - def raise_c(n): - return lambda c: c.subs(**{str(x): x ** n for x in degree_one}) - def scale_part(n): - return lambda m: m.__class__(m.parent(), [i * n for i in m]) - def pn_pleth(f, n): - return f.map_support(scale_part(n)) - def stretched_coefficient(k, n): - q, r = ZZ(n).quo_rem(k) - if r: - return 0 - c = g_p[q] - if c: - return pn_pleth(c.map_coefficients(raise_c(k)), k) - return c - def g_coeff_stream(k): - return CoefficientStream_coefficient_function(lambda n: stretched_coefficient(k, n), - R, P._sparse, 0) - stretched = lazy_list(lambda k: g_coeff_stream(k)) - f_p = CoefficientStream_map_coefficients(self._coeff_stream, lambda c: c, p) - def coefficient(n): - r = R(0) - for i in range(n+1): - r += p._apply_module_morphism(f_p[i], - lambda part: p.prod(sum(stretched[j][h] for h in range(n+1)) - for j in part), - codomain=p).homogeneous_component(n) - return r - else: - raise NotImplementedError - - coeff_stream = CoefficientStream_coefficient_function(coefficient, P._coeff_ring, P._sparse, 0) - return P.element_class(P, coeff_stream) - - def change_ring(self, ring): - """ - Return this series with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(ZZ, "z") - """ - from .lazy_laurent_series_ring import LazySymmetricFunctions - Q = LazySymmetricFunctions(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - - def _format_series(self, formatter, format_strings=False): - """ - Return nonzero ``self`` formatted by ``formatter``. - - TESTS:: - - sage: L = LazySymmetricFunctions(QQ, "x, y") - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, CoefficientStream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length - - atomic_repr = P._coeff_ring._repr_option('element_is_atomic') - mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, CoefficientStream_exact) or cs._constant: - if P._coeff_ring is P.base_ring(): - bigO = ["O(%s)" % P.monomial(1, m)] - else: - bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] - else: - bigO = [] - - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - - return poly - - class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index 16a2bb043a5..e0a8cb44de1 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -34,12 +34,8 @@ from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.lazy_laurent_series import (LazyCauchyProductSeries, LazyLaurentSeries, - LazyTaylorSeries, - LazySymmetricFunction, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions from sage.symbolic.ring import SR @@ -554,16 +550,6 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: f == g True - We can convert a Taylor series to a Laurent series:: - - sage: P. = QQ[] - sage: L. = LazyLaurentSeriesRing(P) - sage: T. = LazyTaylorSeriesRing(QQ) - sage: s = 1/(1-x-y); L(s) - 1 + (x + y)*z + (x^2 + 2*x*y + y^2)*z^2 + (x^3 + 3*x^2*y + 3*x*y^2 + y^3)*z^3 + (x^4 + 4*x^3*y + 6*x^2*y^2 + 4*x*y^3 + y^4)*z^4 + (x^5 + 5*x^4*y + 10*x^3*y^2 + 10*x^2*y^3 + 5*x*y^4 + y^5)*z^5 + (x^6 + 6*x^5*y + 15*x^4*y^2 + 20*x^3*y^3 + 15*x^2*y^4 + 6*x*y^5 + y^6)*z^6 + O(z^7) - - However, not a Dirichlet series:: - sage: D = LazyDirichletSeriesRing(ZZ, 't') sage: m = D(moebius) sage: L(m) @@ -876,789 +862,6 @@ def series(self, coefficient, valuation, constant=None, degree=None): constant=constant, degree=degree) return t -###################################################################### - -class LazyTaylorSeriesRing(UniqueRepresentation, Parent): - """ - Lazy Taylor series ring. - - INPUT: - - - ``base_ring`` -- base ring of this Taylor series ring - - ``names`` -- name(s) of the generator of this Taylor series ring - - ``sparse`` -- (default: ``True``) whether this series is sparse or not - - EXAMPLES:: - - sage: LazyTaylorSeriesRing(ZZ, 't') - Lazy Taylor Series Ring in t over Integer Ring - - sage: L. = LazyTaylorSeriesRing(QQ); L - Multivariate Lazy Taylor Series Ring in x, y over Rational Field - """ - Element = LazyTaylorSeries - - def __init__(self, base_ring, names, sparse=True, category=None): - """ - Initialize ``self``. - - TESTS:: - - sage: L = LazyTaylorSeriesRing(ZZ, 't') - sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) - """ - if isinstance(names, str): - names = (names, ) - self._sparse = sparse - if len(names) == 1: - self._coeff_ring = base_ring - else: - self._coeff_ring = PolynomialRing(base_ring, names) - self._laurent_poly_ring = PolynomialRing(base_ring, names) - category = Algebras(base_ring.category()) - if base_ring in Fields(): - category &= CompleteDiscreteValuationRings() - elif base_ring in IntegralDomains(): - category &= IntegralDomains() - elif base_ring in Rings().Commutative(): - category = category.Commutative() - - if base_ring.is_zero(): - category = category.Finite() - else: - category = category.Infinite() - Parent.__init__(self, base=base_ring, names=names, - category=category) - - def _repr_(self): - """ - String representation of this Taylor series ring. - - EXAMPLES:: - - sage: LazyTaylorSeriesRing(GF(2), 'z') - Lazy Taylor Series Ring in z over Finite Field of size 2 - """ - if len(self.variable_names()) == 1: - return "Lazy Taylor Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) - generators_rep = ", ".join(self.variable_names()) - return "Multivariate Lazy Taylor Series Ring in {} over {}".format(generators_rep, self.base_ring()) - - def _latex_(self): - r""" - Return a latex representation of ``self``. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(GF(2), 'z') - sage: latex(L) - \Bold{F}_{2} [\![z]\!] - """ - from sage.misc.latex import latex - generators_rep = ", ".join(self.variable_names()) - return latex(self.base_ring()) + r"[\![{}]\!]".format(generators_rep) - - @cached_method - def monomial(self, c, n): - r""" - Return the interpretation of the coefficient ``c`` at index ``n``. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.monomial(2, 3) - 2*z^3 - """ - m = len(self.variable_names()) - L = self._laurent_poly_ring - if m == 1: - return L(c) * L.gen() ** n - return L(c) - - @cached_method - def gen(self, n=0): - """ - Return the ``n``-th generator of ``self``. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.gen() - z - sage: L.gen(3) - Traceback (most recent call last): - ... - IndexError: there is only one generator - """ - m = len(self.variable_names()) - if n > m: - if m == 1: - raise IndexError("there is only one generator") - raise IndexError("there are only %s generators" % m) - - R = self._laurent_poly_ring - if len(self.variable_names()) == 1: - coeff_stream = CoefficientStream_exact([1], self._sparse, constant=ZZ.zero(), order=1) - else: - coeff_stream = CoefficientStream_exact([R.gen(n)], self._sparse, constant=ZZ.zero(), order=1) - return self.element_class(self, coeff_stream) - - def ngens(self): - r""" - Return the number of generators of ``self``. - - This is always 1. - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L.ngens() - 1 - """ - return len(self.variable_names()) - - @cached_method - def gens(self): - """ - Return the generators of ``self``. - - EXAMPLES:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L.gens() - (z,) - sage: (1+z)^2 - 1 + 2*z + z^2 - sage: 1/(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ... - """ - return tuple([self.gen(n) for n in range(self.ngens())]) - - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - - def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): - """ - Construct a Taylor series from ``x``. - - INPUT: - - - ``x`` -- data used to the define a Taylor series - - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - - ``constant`` -- (optional) the eventual constant of the series - - ``degree`` -- (optional) the degree when the series is ``constant`` - - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(GF(2), 'z') - sage: L(2) - 0 - sage: L(3) - 1 - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L(lambda i: i, 5, 1, 10) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - sage: L(lambda i: i, 5, (1, 10)) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - - sage: X = L(constant=5, degree=2); X - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: X.valuation() - 2 - - sage: e = L(lambda n: n+1); e - 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - sage: f = e^-1; f - 1 - 2*z + z^2 + O(z^7) - sage: f.coefficient(10) - 0 - sage: f[20] - 0 - - sage: L(valuation=2, constant=1) - z^2 + z^3 + z^4 + O(z^5) - sage: L(constant=1) - 1 + z + z^2 + O(z^3) - - Alternatively, ``x`` can be a list of elements of the base ring. - Then these elements are read as coefficients of the terms of - degrees starting from the ``valuation``. In this case, ``constant`` - may be just an element of the base ring instead of a tuple or can be - simply omitted if it is zero:: - - sage: f = L([1,2,3,4], 1); f - z + 2*z^2 + 3*z^3 + 4*z^4 - - sage: g = L([1,3,5,7,9], 5, -1); g - z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) - - .. TODO:: - - Add a method to change the sparse/dense implementation. - - Finally, ``x`` can be a polynomial:: - - sage: P. = QQ[] - sage: p = x + 3*x^2 + x^5 - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L(p) - x + 3*x^2 + x^5 - - sage: L(p, valuation=0) - 1 + 3*x + x^4 - - sage: P. = QQ[] - sage: p = x + y^2 + x*y - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L(p) - x + (x*y+y^2) - - TESTS:: - - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: L(constant=1) - Traceback (most recent call last): - ... - ValueError: constant must be zero for multivariate Taylor series - - sage: L(lambda n: 0) - O(x,y)^7 - - sage: L(lambda n: n)[3]; - Traceback (most recent call last): - ... - ValueError: coefficient 3 at degree 3 is not a homogeneous polynomial - - sage: L([1, 2, 3]); - Traceback (most recent call last): - ... - ValueError: unable to convert [1, 2, 3] into a lazy Taylor series - - sage: L(lambda n: n, degree=3); - Traceback (most recent call last): - ... - ValueError: coefficients must be homogeneous polynomials of the correct degree - - """ - if valuation is not None: - if valuation < 0: - raise ValueError("the valuation of a Taylor series must be positive") - if len(self.variable_names()) > 1: - raise ValueError(f"valuation must not be specified for multivariate Taylor series") - - R = self._laurent_poly_ring - BR = self.base_ring() - if x is None: - assert degree is None - coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) - return self.element_class(self, coeff_stream) - try: - # Try to build stuff using the polynomial ring constructor - x = R(x) - except (TypeError, ValueError): - pass - if isinstance(constant, (tuple, list)): - constant, degree = constant - if constant is not None: - if len(self.variable_names()) > 1 and constant: - raise ValueError(f"constant must be zero for multivariate Taylor series") - constant = BR(constant) - if x in R: - if not x and not constant: - coeff_stream = CoefficientStream_zero(self._sparse) - else: - if not x: - coeff_stream = CoefficientStream_exact([], self._sparse, - order=valuation, - degree=degree, - constant=constant) - return self.element_class(self, coeff_stream) - - if len(self.variable_names()) == 1: - v = x.valuation() - d = x.degree() - p_list = [x[i] for i in range(v, d + 1)] - if valuation is not None: - v = valuation - else: - p_dict = x.homogeneous_components() - v = min(p_dict.keys()) - d = max(p_dict.keys()) - p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] - - coeff_stream = CoefficientStream_exact(p_list, self._sparse, - order=v, - constant=constant, - degree=degree) - return self.element_class(self, coeff_stream) - - if isinstance(x, LazyTaylorSeries): - if x._coeff_stream._is_sparse is self._sparse: - return self.element_class(self, x._coeff_stream) - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") - if callable(x): - if valuation is None: - valuation = 0 - if degree is not None: - if constant is None: - constant = ZZ.zero() - z = R.gen() - if len(self.variable_names()) == 1: - p = [BR(x(i)) for i in range(valuation, degree)] - else: - p = [R(x(i)) for i in range(valuation, degree)] - if not all(e.is_homogeneous() and e.degree() == i - for i, e in enumerate(p, valuation)): - raise ValueError("coefficients must be homogeneous polynomials of the correct degree") - coeff_stream = CoefficientStream_exact(p, self._sparse, - order=valuation, - constant=constant, - degree=degree) - return self.element_class(self, coeff_stream) - if check and len(self.variable_names()) > 1: - def y(n): - e = R(x(n)) - if not e or e.is_homogeneous() and e.degree() == n: - return e - raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) - coeff_stream = CoefficientStream_coefficient_function(y, self._coeff_ring, self._sparse, valuation) - else: - coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) - return self.element_class(self, coeff_stream) - raise ValueError(f"unable to convert {x} into a lazy Taylor series") - - def _an_element_(self): - """ - Return a Taylor series in ``self``. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.an_element() - z + z^2 + z^3 + z^4 + ... - """ - c = self.base_ring()(1) - R = self._laurent_poly_ring - coeff_stream = CoefficientStream_exact([R.one()], self._sparse, order=1, constant=c) - return self.element_class(self, coeff_stream) - - @cached_method - def one(self): - r""" - Return the constant series `1`. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.one() - 1 - """ - R = self._laurent_poly_ring - coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) - return self.element_class(self, coeff_stream) - - @cached_method - def zero(self): - r""" - Return the zero series. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.zero() - 0 - """ - return self.element_class(self, CoefficientStream_zero(self._sparse)) - - # add options to class - class options(GlobalOptions): - NAME = 'LazyTaylorSeriesRing' - module = 'sage.rings.lazy_laurent_series_ring' - display_length = dict(default=7, - description='the number of coefficients to display from the valuation', - checker=lambda x: x in ZZ and x > 0) - constant_length = dict(default=3, - description='the number of coefficients to display for nonzero constant series', - checker=lambda x: x in ZZ and x > 0) - - -###################################################################### - -class LazySymmetricFunctions(UniqueRepresentation, Parent): - """ - Lazy symmetric functions. - - INPUT: - - - ``base_ring`` -- coefficient ring - - ``names`` -- name(s) of the alphabets - - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation - - EXAMPLES:: - - sage: LazySymmetricFunctions(ZZ, 'x') - Lazy Symmetric Functions Ring in x over Integer Ring - - sage: L = LazySymmetricFunctions(QQ, "x, y"); L - Multialphabet Lazy Symmetric Functions Ring in x, y over Rational Field - """ - Element = LazySymmetricFunction - - def __init__(self, base_ring, names, sparse=True, category=None): - """ - Initialize ``self``. - - TESTS:: - - sage: L = LazySymmetricFunctions(ZZ, 't') - sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) - """ - category = Algebras(base_ring.category()) - if base_ring in Fields(): - category &= CompleteDiscreteValuationRings() - elif base_ring in IntegralDomains(): - category &= IntegralDomains() - elif base_ring in Rings().Commutative(): - category = category.Commutative() - - if base_ring.is_zero(): - category = category.Finite() - else: - category = category.Infinite() - Parent.__init__(self, base=base_ring, names=names, - category=category) - self._sparse = sparse - n = len(self.variable_names()) - if n == 1: - self._coeff_ring = SymmetricFunctions(base_ring).m() - else: - self._coeff_ring = tensor([SymmetricFunctions(base_ring).m()]*len(self.variable_names())) - self._laurent_poly_ring = self._coeff_ring - - def _repr_(self): - """ - String representation of the lazy symmetric functions ring. - - EXAMPLES:: - - sage: LazySymmetricFunctions(GF(2), 'z') - Lazy Symmetric Functions Ring in z over Finite Field of size 2 - """ - if len(self.variable_names()) == 1: - return "Lazy Symmetric Functions Ring in {} over {}".format(self.variable_name(), self.base_ring()) - generators_rep = ", ".join(self.variable_names()) - return "Multialphabet Lazy Symmetric Functions Ring in {} over {}".format(generators_rep, self.base_ring()) - - def _latex_(self): - r""" - Return a latex representation of ``self``. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(GF(2), 'z') - sage: latex(L) - \Lambda( \Bold{F}_{2} , z) - """ - from sage.misc.latex import latex - generators_rep = ", ".join(self.variable_names()) - return r"\Lambda(" + latex(self.base_ring()) + r", {})".format(generators_rep) - - @cached_method - def monomial(self, c, n): - r""" - Return the interpretation of the coefficient ``c`` at index ``n``. - - EXAMPLES:: - - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(ZZ, 'z') - sage: L.monomial(s[2,1], 3) - 2*m[1, 1, 1] + m[2, 1] - - """ - L = self._laurent_poly_ring - return L(c) - - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - - def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): - """ - Construct a lazy symmetric function from ``x``. - - INPUT: - - - ``x`` -- data used to the define a Taylor series - - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - - ``degree`` -- (optional) the degree when the symmetric function has finite support - - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(GF(2), 'z') - sage: L(2) - 0 - sage: L(3) - m[] - - sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(ZZ, 'z') - sage: f = L(lambda i: m([i]), valuation=5, degree=10); f - m[5] + m[6] + m[7] + m[8] + m[9] - - sage: f.coefficient(6) - m[6] - sage: f[20] - 0 - - Alternatively, ``x`` can be a list of elements of the base ring. - Then these elements are read as coefficients of the terms of - degrees starting from the ``valuation``:: - - sage: f = L([m[1],m[2],m[3]], valuation=1); f - m[1] + m[2] + m[3] - - .. TODO:: - - Add a method to change the sparse/dense implementation. - - Finally, ``x`` can be a symmetric function:: - - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(ZZ, "x") - sage: L(s.an_element()) - 2*m[] + 2*m[1] + (3*m[1,1]+3*m[2]) - - TESTS:: - - sage: L = LazySymmetricFunctions(ZZ, "x,y") - sage: L(lambda n: 0) - O(x,y)^7 - - sage: L(lambda n: n)[3]; - Traceback (most recent call last): - ... - ValueError: coefficient 3*m[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree - - sage: L([1, 2, 3]); - Traceback (most recent call last): - ... - ValueError: coefficients must be symmetric functions of the correct homogeneous degree - - sage: L(lambda n: n, degree=3); - Traceback (most recent call last): - ... - ValueError: coefficients must be symmetric functions of the correct homogeneous degree - - """ - if valuation is not None: - if valuation < 0: - raise ValueError("the valuation of a lazy symmetric function must be nonnegative") - - R = self._laurent_poly_ring - BR = self.base_ring() - if x is None: - assert degree is None - coeff_stream = CoefficientStream_uninitialized(self._sparse, valuation) - return self.element_class(self, coeff_stream) - try: - # Try to build stuff using the polynomial ring constructor - x = R(x) - except (TypeError, ValueError, NotImplementedError): - pass - if x in R: - if not x: - coeff_stream = CoefficientStream_zero(self._sparse) - else: - p_dict = {} - if len(self.variable_names()) == 1: - for f in x.terms(): - d = f.degree() - p_dict[d] = p_dict.get(d, 0) + f - else: - for f in x.terms(): - d = sum(p.size() for p in f.support()) - p_dict[d] = p_dict.get(d, 0) + f - v = min(p_dict.keys()) - d = max(p_dict.keys()) - p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] - - coeff_stream = CoefficientStream_exact(p_list, self._sparse, - order=v, - constant=0, - degree=degree) - return self.element_class(self, coeff_stream) - - if isinstance(x, LazySymmetricFunction): - if x._coeff_stream._is_sparse is self._sparse: - return self.element_class(self, x._coeff_stream) - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") - - if len(self.variable_names()) == 1: - def is_homogeneous_of_degree(f, d): - if not f: - return True - try: - return f.homogeneous_degree() == d - except ValueError: - return False - else: - def is_homogeneous_of_degree(f, d): - if not f: - return True - for m in f.monomials(): - for t in m.support(): - if sum(p.size() for p in t) != d: - return False - if isinstance(x, (tuple, list)): - if valuation is None: - valuation = 0 - if degree is None: - degree = valuation + len(x) - p = [R(e) for e in x] - if not all(is_homogeneous_of_degree(e, i) - for i, e in enumerate(p, valuation)): - raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") - coeff_stream = CoefficientStream_exact(p, self._sparse, - order=valuation, - constant=0, - degree=degree) - return self.element_class(self, coeff_stream) - if callable(x): - if valuation is None: - valuation = 0 - if degree is not None: - p = [R(x(i)) for i in range(valuation, degree)] - if not all(is_homogeneous_of_degree(e, i) - for i, e in enumerate(p, valuation)): - raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") - coeff_stream = CoefficientStream_exact(p, self._sparse, - order=valuation, - constant=0, - degree=degree) - return self.element_class(self, coeff_stream) - if check: - def y(n): - e = R(x(n)) - if is_homogeneous_of_degree(e, n): - return e - raise ValueError("coefficient %s at degree %s is not a symmetric function of the correct homogeneous degree" % (e, n)) - coeff_stream = CoefficientStream_coefficient_function(y, self._coeff_ring, self._sparse, valuation) - else: - coeff_stream = CoefficientStream_coefficient_function(x, self._coeff_ring, self._sparse, valuation) - return self.element_class(self, coeff_stream) - raise ValueError(f"unable to convert {x} into a lazy symmetric function") - - def _an_element_(self): - """ - Return a lazy symmetric function in ``self``. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(ZZ, 'z') - sage: L.an_element() - m[] - """ - c = self.base_ring()(1) - R = self._laurent_poly_ring - coeff_stream = CoefficientStream_exact([R.one()], self._sparse, order=1, constant=0) - return self.element_class(self, coeff_stream) - - @cached_method - def one(self): - r""" - Return the constant `1`. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(ZZ, 'z') - sage: L.one() - m[] - """ - R = self._laurent_poly_ring - coeff_stream = CoefficientStream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) - return self.element_class(self, coeff_stream) - - @cached_method - def zero(self): - r""" - Return the zero series. - - EXAMPLES:: - - sage: L = LazySymmetricFunctions(ZZ, 'z') - sage: L.zero() - 0 - """ - return self.element_class(self, CoefficientStream_zero(self._sparse)) - - # add options to class - class options(GlobalOptions): - NAME = 'LazySymmetricFunctions' - module = 'sage.rings.lazy_laurent_series_ring' - display_length = dict(default=7, - description='the number of coefficients to display from the valuation', - checker=lambda x: x in ZZ and x > 0) - constant_length = dict(default=3, - description='the number of coefficients to display for nonzero constant series', - checker=lambda x: x in ZZ and x > 0) - - -###################################################################### class LazyDirichletSeriesRing(UniqueRepresentation, Parent): """ From 2d42314ea3eb8558fabc31cc05ebd742dbaf7673 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 25 Aug 2021 23:34:49 +0200 Subject: [PATCH 109/355] remove gen --- src/sage/rings/lazy_laurent_series.py | 2 +- src/sage/rings/lazy_laurent_series_ring.py | 51 ---------------------- 2 files changed, 1 insertion(+), 52 deletions(-) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_laurent_series.py index b059160e6b0..8821ad12dc9 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_laurent_series.py @@ -1047,7 +1047,7 @@ def _acted_upon_(self, scalar, self_on_left): Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: g = L.gen(2) + sage: g = L([0,1]) sage: 2 * g 2/2^z sage: -1 * g diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_laurent_series_ring.py index cd868f44195..a236bf6ddb0 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_laurent_series_ring.py @@ -930,57 +930,6 @@ def monomial(self, c, n): L = self._laurent_poly_ring return L(c) * L(n) ** -L(self.variable_name()) - @cached_method - def gen(self, n=1): - """ - Return the `n`-th generator of this Dirichlet series ring. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.gen() - 1 - sage: L.gen(4) - 1/(4^z) - - """ - assert n >= 1 - coeff_stream = Stream_exact([1], self._sparse, order=n, constant=ZZ.zero()) - return self.element_class(self, coeff_stream) - - def ngens(self): - """ - Return the number of generators of this Dirichlet series ring. - - This is always `\infty`. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, "s") - sage: L.ngens() - +Infinity - """ - return infinity - - @cached_method - def gens(self): - """ - Return the tuple of the generator. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: L.gens() - Lazy family ((i))_{i in Positive integers} - sage: L.gens()[2] - 1/(2^z) - - """ - from sage.sets.family import Family - from sage.sets.positive_integers import PositiveIntegers - - return Family(PositiveIntegers(), lambda n: self.gen(n)) - def _coerce_map_from_(self, S): """ Return ``True`` if a coercion from ``S`` exists. From 2bed0f56700538653a0257ef97dbcb680361d4ae Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Aug 2021 18:22:18 +1000 Subject: [PATCH 110/355] Renaming file to lazy_series*.py to reflect contents. --- src/doc/en/reference/power_series/index.rst | 4 ++-- src/sage/rings/all.py | 2 +- .../rings/{lazy_laurent_series.py => lazy_series.py} | 12 ++++++------ ...zy_laurent_series_ring.py => lazy_series_ring.py} | 9 +++++---- 4 files changed, 14 insertions(+), 13 deletions(-) rename src/sage/rings/{lazy_laurent_series.py => lazy_series.py} (99%) rename src/sage/rings/{lazy_laurent_series_ring.py => lazy_series_ring.py} (99%) diff --git a/src/doc/en/reference/power_series/index.rst b/src/doc/en/reference/power_series/index.rst index bdb582b5e74..dba377477f1 100644 --- a/src/doc/en/reference/power_series/index.rst +++ b/src/doc/en/reference/power_series/index.rst @@ -15,8 +15,8 @@ Power Series Rings and Laurent Series Rings sage/rings/laurent_series_ring sage/rings/laurent_series_ring_element - sage/rings/lazy_laurent_series - sage/rings/lazy_laurent_series_ring + sage/rings/lazy_series + sage/rings/lazy_series_ring sage/rings/puiseux_series_ring sage/rings/puiseux_series_ring_element diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 02a6eb56f91..a8a1da9ff3d 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,7 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) +lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_series.py similarity index 99% rename from src/sage/rings/lazy_laurent_series.py rename to src/sage/rings/lazy_series.py index 8821ad12dc9..0d95e83935a 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_series.py @@ -1,9 +1,9 @@ r""" -Lazy Laurent Series +Lazy Series -A lazy Laurent series is a Laurent series whose coefficients are -computed on demand. Therefore, unlike the usual Laurent series in -Sage, lazy Laurent series have infinite precision. +A lazy series is a series whose coefficients are computed on demand. +Therefore, unlike the usual Laurent/power/etc. series in Sage, +lazy series have infinite precision. EXAMPLES: @@ -1679,7 +1679,7 @@ def change_ring(self, ring): sage: M ^-1 z^-1 - 2 + z + O(z^6) """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) @@ -2468,7 +2468,7 @@ def change_ring(self, ring): sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) """ - from .lazy_laurent_series_ring import LazyDirichletSeriesRing + from .lazy_series_ring import LazyDirichletSeriesRing Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) return Q.element_class(Q, self._coeff_stream) diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_series_ring.py similarity index 99% rename from src/sage/rings/lazy_laurent_series_ring.py rename to src/sage/rings/lazy_series_ring.py index a236bf6ddb0..9e6c4b747b2 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1,5 +1,5 @@ r""" -Lazy Laurent Series Rings +Lazy Series Rings AUTHORS: @@ -33,7 +33,7 @@ from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.lazy_laurent_series import (LazyCauchyProductSeries, +from sage.rings.lazy_series import (LazyCauchyProductSeries, LazyLaurentSeries, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -770,7 +770,7 @@ class options(GlobalOptions): 7 """ NAME = 'LazyLaurentSeriesRing' - module = 'sage.rings.lazy_laurent_series_ring' + module = 'sage.rings.lazy_series_ring' display_length = dict(default=7, description='the number of coefficients to display from the valuation', checker=lambda x: x in ZZ and x > 0) @@ -1102,10 +1102,11 @@ def zero(self): # add options to class class options(GlobalOptions): NAME = 'LazyDirichletSeriesRing' - module = 'sage.rings.lazy_laurent_series_ring' + module = 'sage.rings.lazy_series_ring' display_length = dict(default=7, description='the number of coefficients to display from the valuation', checker=lambda x: x in ZZ and x > 0) constant_length = dict(default=3, description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) + From 5eac29b8fc0e23d770b8014e7c3ae43baee52511 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Aug 2021 19:08:32 +1000 Subject: [PATCH 111/355] Writing more consistent composition code and fixing Dirichlet input bugs. --- src/sage/rings/lazy_series.py | 66 ++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0d95e83935a..5f878a4de63 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -107,6 +107,7 @@ Stream_exact, Stream_uninitialized, Stream_shift, + Stream_function, Stream_dirichlet_convolve, Stream_dirichlet_invert ) @@ -1917,13 +1918,38 @@ def __call__(self, g): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + sage: g = D([1,0,1,1,2]); g + sage: e(g)[0:10] + sage: sum(g^k/factorial(k) for k in range(10))[0:10] + + The output parent is always the common parent between the base ring + of `f` and the parent of `g` or extended to the corresponding + lazy series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: R. = ZZ[] + sage: parent(z(x)) + Univariate Polynomial Ring in x over Rational Field + sage: parent(z(R.zero())) + Univariate Polynomial Ring in x over Rational Field + sage: parent(z(0)) + Rational Field + sage: f = 1 / (1 - z) + sage: f(x) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x^7) + sage: three = L(3)(x^2); three + 3 + sage: parent(three) + Univariate Polynomial Ring in x over Rational Field """ # f = self and compute f(g) - P = g.parent() + from sage.structure.element import get_coercion_model + cm = get_coercion_model() + P = cm.common_parent(self.base_ring(), g.parent()) # f = 0 if isinstance(self._coeff_stream, Stream_zero): - return self + return P.zero() # g = 0 case if ((not isinstance(g, LazyModuleElement) and not g) @@ -1943,12 +1969,15 @@ def __call__(self, g): R = self.parent()._laurent_poly_ring poly = self._coeff_stream._polynomial_part(R) if poly.is_constant(): - return self + return P(poly[0]) if not isinstance(g, LazyModuleElement): return poly(g) # g also has finite length, compose the polynomials - # TODO: likely wrong if g is a Dirichlet series - if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: + # We optimize composition when g is not a Dirichlet series + # by composing the polynomial parts explicitly + if (not isinstance(g, LazyDirichletSeries) + and isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): R = P._laurent_poly_ring g_poly = g._coeff_stream._polynomial_part(R) try: @@ -1991,22 +2020,35 @@ def __call__(self, g): ret += poly[v] * gp return ret - # g != 0 and val(g) > 0 + # f is not known to have finite length and g != 0 with val(g) > 0 if not isinstance(g, LazyModuleElement): + # Check to see if it belongs to a polynomial ring + # that we can extend to a lazy series ring + from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + if isinstance(P, PolynomialRing_general): + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + R = LazyLaurentSeriesRing(P.base_ring(), P.variable_names(), P.is_sparse()) + g = R(P(g)) + return self(g) + # TODO: Implement case for a regular (Laurent)PowerSeries element # as we can use the (default?) order given - try: - # TODO: wrong if g is not a CauchyProductSeries - g = self.parent()(g) - except (TypeError, ValueError): - raise NotImplementedError("can only compose with a lazy series") + raise NotImplementedError("can only compose with a lazy series") + # Perhaps we just don't yet know if the valuation is positive if g._coeff_stream._approximate_order <= 0: if any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 - coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) + if isinstance(g, LazyCauchyProductSeries): + coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) + return P.element_class(P, coeff_stream) + + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + return sum(self[i] * (g**i)[n] for i in range(n+1)) + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) return P.element_class(P, coeff_stream) compose = __call__ From db1ae9479051ea0e4aca62a6e4608f0ff1b18502 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Aug 2021 20:07:39 +1000 Subject: [PATCH 112/355] Catching bad valuation in composition with Dirichlet. Adding doctests. Misc tweaks. --- src/sage/data_structures/stream.py | 33 +++++++++++++- src/sage/rings/lazy_series.py | 70 +++++++++++++++++++++++------- src/sage/rings/lazy_series_ring.py | 20 +++++---- 3 files changed, 98 insertions(+), 25 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index fde31466238..e13cefcc6f7 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1423,11 +1423,22 @@ class Stream_dirichlet_convolve(Stream_binary): sage: u = Stream_dirichlet_convolve(g, f) sage: [u[i] for i in range(1, 10)] [1, 3, 4, 7, 6, 12, 8, 15, 13] - """ def __init__(self, left, right): """ Initalize ``self``. + + sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) + sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: g = Stream_exact([1], True, constant=0) + sage: Stream_dirichlet_convolve(f, g) + Traceback (most recent call last): + ... + AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 + sage: Stream_dirichlet_convolve(g, f) + Traceback (most recent call last): + ... + AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 """ if left._is_sparse != right._is_sparse: raise NotImplementedError @@ -1447,6 +1458,16 @@ def get_coefficient(self, n): - ``n`` -- integer; the degree for the coefficient + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) + sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: g = Stream_exact([0], True, constant=1) + sage: h = Stream_dirichlet_convolve(f, g) + sage: h.get_coefficient(7) + 8 + sage: [h[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] """ c = ZZ.zero() for k in divisors(n): @@ -1500,6 +1521,16 @@ def get_coefficient(self, n): INPUT: - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 3], True, constant=2) + sage: g = Stream_dirichlet_invert(f) + sage: g.get_coefficient(6) + 2/27 + sage: [g[i] for i in range(8)] + [0, 1/3, -2/9, -2/9, -2/27, -2/9, 2/27, -2/9] """ if n == 1: return self._ainv diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 5f878a4de63..ee890929129 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1918,9 +1918,24 @@ def __call__(self, g): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] - sage: g = D([1,0,1,1,2]); g + sage: g = D([0,1,0,1,1,2]); g + 1/(2^s) + 1/(4^s) + 1/(5^s) + 2/6^s sage: e(g)[0:10] + [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] sage: sum(g^k/factorial(k) for k in range(10))[0:10] + [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] + + sage: e(D([1,0,1])) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + sage: e5 = L(e, degree=5); e5 + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + sage: e5(g) + 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) + sage: sum(e5[k] * g^k for k in range(5)) + 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) The output parent is always the common parent between the base ring of `f` and the parent of `g` or extended to the corresponding @@ -2041,14 +2056,16 @@ def __call__(self, g): raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 - if isinstance(g, LazyCauchyProductSeries): - coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) + if isinstance(g, LazyDirichletSeries): + if g._coeff_stream._approximate_order == 1 and g._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + return sum(self[i] * (g**i)[n] for i in range(n+1)) + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) return P.element_class(P, coeff_stream) - # we assume that the valuation of self[i](g) is at least i - def coefficient(n): - return sum(self[i] * (g**i)[n] for i in range(n+1)) - coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) return P.element_class(P, coeff_stream) compose = __call__ @@ -2376,7 +2393,7 @@ def _format_series(self, formatter, format_strings=False): if not cs._constant: return formatter(poly) m = cs._degree + P.options.constant_length - poly += sum([cs._constant * z**k for k in range(cs._degree, m)]) + poly += sum(cs._constant * z**k for k in range(cs._degree, m)) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) # This is an inexact series @@ -2393,12 +2410,6 @@ class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. - INPUT: - - - ``parent`` -- The base ring for the series - - - ``coeff_stream`` -- The auxiliary class that handles the coefficient stream - EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, "z") @@ -2435,7 +2446,6 @@ def valuation(self): log(2) sage: (g*g).valuation() 2*log(2) - """ from sage.functions.log import log return log(self._coeff_stream.order()) @@ -2466,6 +2476,14 @@ def _mul_(self, other): True sage: mu * L.one() is mu True + + sage: d1 = L([0,0,1,2,3]) + sage: d2 = L([0,1,2,3]) + sage: d1 * d2 + 1/(6^z) + 2/8^z + 2/9^z + 3/10^z + 7/12^z + O(1/(13^z)) + + sage: d1 * d2 # not tested - exact result + 1/(6^z) + 2/8^z + 2/9^z + 3/10^z + 7/12^z + 6/15^z + 6/16^z + 9/20^z """ P = self.parent() left = self._coeff_stream @@ -2479,6 +2497,17 @@ def _mul_(self, other): and right.order() == 1): return self coeff = Stream_dirichlet_convolve(left, right) + # Performing exact arithmetic is slow because the series grow large + # very quickly as we are multiplying the degree + #if (isinstance(left, Stream_exact) and not left._constant + # and isinstance(right, Stream_exact) and not right._constant): + # # Product of finite length Dirichlet series, + # # so the result has finite length + # deg = (left._degree - 1) * (right._degree - 1) + 1 + # order = left._approximate_order * right._approximate_order + # coeff_vals = [coeff[i] for i in range(order, deg)] + # return P.element_class(P, Stream_exact(coeff_vals, coeff._is_sparse, + # constant=left._constant, order=order, degree=deg)) return P.element_class(P, coeff) def __invert__(self): @@ -2524,6 +2553,9 @@ def _format_series(self, formatter, format_strings=False): sage: f = L(constant=1) sage: f._format_series(repr) '1 + 1/(2^s) + 1/(3^s) + O(1/(4^s))' + sage: f._format_series(unicode_art) + -s -s + 1 + 2 + 3 + O(1/(4^s)) sage: L([1,-1,1])._format_series(repr) '1 - 1/(2^s) + 1/(3^s)' @@ -2532,6 +2564,13 @@ def _format_series(self, formatter, format_strings=False): -s -s 1 + -2 + 3 + sage: R. = QQ[] + sage: L = LazyDirichletSeriesRing(R, "s") + sage: L([1,-1 + x,1/3])._format_series(ascii_art) + ( -s) + (3 ) + ( -s ) (---) + (1) + (2 *(x - 1)) + ( 3 ) """ P = self.parent() cs = self._coeff_stream @@ -2586,3 +2625,4 @@ def parenthesize(m): poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") return poly + diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 9e6c4b747b2..9f7b25dc425 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -963,13 +963,14 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No INPUT: - - ``x`` -- a Dirichlet series, a Dirichlet polynomial, a Python function, or a list of elements in the base ring + - ``x`` -- a Dirichlet series, a Dirichlet polynomial, a Python + function, or a list of elements in the base ring - - ``constant`` -- either ``None`` (default: ``None``) or pair of an element of the base ring and an integer + - ``constant`` -- integer (optional); pair of + an element of the base ring and an integer EXAMPLES:: - sage: L = LazyDirichletSeriesRing(ZZ, 'z') sage: L(3) 3 @@ -1007,13 +1008,14 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No ... ValueError: positive characteristic not allowed for Dirichlet series - TODO:: + .. TODO:: - Add a method to make a copy of self._sparse. + Add a method to make a copy of ``self._sparse``. """ if valuation is None: valuation = 1 - assert valuation > 0, "the valuation of a Dirichlet series must be positive" + if valuation <= 0: + raise ValueError("the valuation of a Dirichlet series must be positive") if x is None: return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) @@ -1036,9 +1038,9 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No x = [x] if isinstance(x, (tuple, list)): coeff_stream = Stream_exact(x, self._sparse, - order=valuation, - constant=constant, - degree=degree) + order=valuation, + constant=constant, + degree=degree) return self.element_class(self, coeff_stream) if isinstance(x, LazyDirichletSeries): From f2dbe33a2293b24d2d54daf035a12ab96f2a3721 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 26 Aug 2021 15:40:02 +0200 Subject: [PATCH 113/355] set correct approximate valuation 1 for composition with Dirichlet series --- src/sage/rings/lazy_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index ee890929129..825b5bac9eb 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2062,7 +2062,7 @@ def __call__(self, g): # we assume that the valuation of self[i](g) is at least i def coefficient(n): return sum(self[i] * (g**i)[n] for i in range(n+1)) - coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) From 2d5d9d461c883cb87a0b9b0c58bf55013229884b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 26 Aug 2021 15:48:29 +0200 Subject: [PATCH 114/355] remove obsolete comments --- src/sage/data_structures/stream.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index e13cefcc6f7..59b705c3fcd 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1577,7 +1577,7 @@ def __init__(self, f, g): sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) sage: h = Stream_cauchy_compose(f, g) """ - assert g._approximate_order > 0 # TODO: wrong if g is a Dirichlet series, need > 1 + assert g._approximate_order > 0 self._fv = f._approximate_order self._gv = g._approximate_order if self._fv < 0: @@ -1589,7 +1589,7 @@ def __init__(self, f, g): self._neg_powers.append(Stream_cauchy_mul(self._neg_powers[-1], ginv)) # Placeholder None to make this 1-based. self._pos_powers = [None, g] - val = self._fv * self._gv # TODO: wrong if g is a Dirichlet series, self._gv ^ self._fv there + val = self._fv * self._gv super().__init__(f, g, f._is_sparse, val) def get_coefficient(self, n): @@ -1611,7 +1611,7 @@ def get_coefficient(self, n): sage: [h.get_coefficient(i) for i in range(10)] [0, 1, 6, 28, 124, 527, 2172, 8755, 34704, 135772] """ - if n < 0: # TODO: wrong if g is a Dirichlet series, for n <= 0 we get 0 + if n < 0: return sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, n // self._gv + 1)) # n > 0 while len(self._pos_powers) <= n // self._gv: From 158f39221a4b69638b414723dbb1f5ccb53cfb94 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Aug 2021 10:48:04 +1000 Subject: [PATCH 115/355] Add cheap check against approx order in Dirichlet convoluation stream. --- src/sage/data_structures/stream.py | 2 ++ src/sage/rings/lazy_series.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 59b705c3fcd..deeebfa099c 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1471,6 +1471,8 @@ def get_coefficient(self, n): """ c = ZZ.zero() for k in divisors(n): + if k < self._left._approximate_order or n // k < self._right._approximate_order: + continue val = self._left[k] if val: c += val * self._right[n//k] diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 825b5bac9eb..6a359e2a584 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -659,6 +659,15 @@ def define(self, s): Traceback (most recent call last): ... ValueError: series already defined + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(QQ) + sage: e = L(lambda n: 1/factorial(n), 0) + sage: g = D(None, valuation=2) + sage: o = D(constant=1, valuation=2) + sage: g.define(o * e(g)) + sage: g + 1/(2^s) + 1/(3^s) + 2/4^s + 1/(5^s) + 3/6^s + 1/(7^s) + 9/2/8^s + O(1/(9^s)) """ if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") From 5a5924962b0e5cd3cbf026668eef3008c535e452 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Aug 2021 10:53:56 +1000 Subject: [PATCH 116/355] Better approximate order for Dirichlet series and test in __call__. --- src/sage/rings/lazy_series.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 6a359e2a584..6ca7049bbe9 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1999,7 +1999,7 @@ def __call__(self, g): # g also has finite length, compose the polynomials # We optimize composition when g is not a Dirichlet series # by composing the polynomial parts explicitly - if (not isinstance(g, LazyDirichletSeries) + if (isinstance(g, LazyCauchyProductSeries) and isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant): R = P._laurent_poly_ring @@ -2066,8 +2066,10 @@ def __call__(self, g): g._coeff_stream._approximate_order = 1 if isinstance(g, LazyDirichletSeries): - if g._coeff_stream._approximate_order == 1 and g._coeff_stream[1] != 0: - raise ValueError("can only compose with a positive valuation series") + if g._coeff_stream._approximate_order == 1: + if g._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 2 # we assume that the valuation of self[i](g) is at least i def coefficient(n): return sum(self[i] * (g**i)[n] for i in range(n+1)) From 045d6e71efb655b942da474f206c68cdb42d955b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 27 Aug 2021 14:29:46 +0200 Subject: [PATCH 117/355] take care of zero stream in Dirichlet _mul_ --- src/sage/rings/lazy_series.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 07974339c80..71c991d384b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -313,7 +313,7 @@ def map_coefficients(self, func, ring=None): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: s = L(lambda n: n-1); s 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + ... - sage: s = s.map_coefficients(lambda c: c + 1); s + sage: s.map_coefficients(lambda c: c + 1) 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... TESTS:: @@ -2499,10 +2499,21 @@ def _mul_(self, other): sage: d1 * d2 # not tested - exact result 1/(6^z) + 2/8^z + 2/9^z + 3/10^z + 7/12^z + 6/15^z + 6/16^z + 9/20^z + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(D) + sage: zeta = D(constant=1) + sage: 1/(1-t*zeta) + (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 + (1 + 3/2^s + 3/3^s + 6/4^s + 3/5^s + 9/6^s + 3/7^s + O(1/(8^s)))*t^3 + (1 + 4/2^s + 4/3^s + 10/4^s + 4/5^s + 16/6^s + 4/7^s + O(1/(8^s)))*t^4 + (1 + 5/2^s + 5/3^s + 15/4^s + 5/5^s + 25/6^s + 5/7^s + O(1/(8^s)))*t^5 + (1 + 6/2^s + 6/3^s + 21/4^s + 6/5^s + 36/6^s + 6/7^s + O(1/(8^s)))*t^6 + O(t^7) + """ P = self.parent() left = self._coeff_stream right = other._coeff_stream + if isinstance(left, Stream_zero): + return self + if isinstance(right, Stream_zero): + return other if (isinstance(left, Stream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.order() == 1): From d3479c7a788eef058d416df9331884830287f1a9 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 27 Aug 2021 22:38:27 +0200 Subject: [PATCH 118/355] remove some of symbolics from sage.geometry --- src/sage/geometry/convex_set.py | 13 ++++--- src/sage/geometry/polyhedron/base.py | 2 +- src/sage/geometry/polyhedron/constructor.py | 5 ++- src/sage/geometry/polyhedron/parent.py | 5 ++- src/sage/geometry/polyhedron/plot.py | 3 +- .../geometry/polyhedron/representation.py | 35 ++++++++++--------- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index fda6fa9d374..82ce25e48c6 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -859,11 +859,14 @@ def _test_contains(self, tester=None, **options): ext_space = self.ambient_vector_space(AA) ext_space_point = ext_space(space_point) tester.assertEqual(contains_space_point, self.contains(ext_space_point)) - from sage.symbolic.ring import SR - symbolic_space = self.ambient_vector_space(SR) - symbolic_space_point = symbolic_space(space_point) - # Only test that it can accept SR vectors without error. - self.contains(symbolic_space_point) + try: + from sage.symbolic.ring import SR + symbolic_space = self.ambient_vector_space(SR) + symbolic_space_point = symbolic_space(space_point) + # Only test that it can accept SR vectors without error. + self.contains(symbolic_space_point) + except ImportError: + pass # Test that elements returned by some_elements are contained. try: points = self.some_elements() diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 040e09f7df8..a3fb4a6d2b7 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1824,7 +1824,7 @@ def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=Non sage: c = polytopes.cube() sage: c.Hrepresentation_str(separator=', ', style='positive') - '1 >= x0, 1 >= x1, 1 >= x2, x0 + 1 >= 0, x2 + 1 >= 0, x1 + 1 >= 0' + '1 >= x0, 1 >= x1, 1 >= x2, 1 + x0 >= 0, 1 + x2 >= 0, 1 + x1 >= 0' """ pretty_hs = [h.repr_pretty(split=True, latex=latex, style=style, **kwds) for h in self.Hrepresentation()] shift = any(pretty_h[2].startswith('-') for pretty_h in pretty_hs) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 7f68ca41ce0..351fd2e2bc8 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -649,7 +649,10 @@ def Polyhedron(vertices=None, rays=None, lines=None, if base_ring not in Rings(): raise ValueError('invalid base ring') - from sage.symbolic.ring import SR + try: + from sage.symbolic.ring import SR + except ImportError: + SR = None if base_ring is not SR and not base_ring.is_exact(): # TODO: remove this hack? if base_ring is RR: diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 7f14eb0766e..070917c00ef 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -145,7 +145,10 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * else: raise ValueError("no default backend for computations with {}".format(base_ring)) - from sage.symbolic.ring import SR + try: + from sage.symbolic.ring import SR + except ImportError: + SR = None if backend == 'ppl' and base_ring is QQ: return Polyhedra_QQ_ppl(base_ring, ambient_dim, backend) elif backend == 'ppl' and base_ring is ZZ: diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 7b4eace75ef..728ccec4988 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -11,6 +11,8 @@ # https://www.gnu.org/licenses/ ######################################################################## +from math import pi + from sage.rings.all import RDF from sage.structure.sage_object import SageObject from sage.modules.free_module_element import vector @@ -18,7 +20,6 @@ from sage.matrix.special import diagonal_matrix from sage.misc.functional import norm from sage.misc.latex import LatexExpr -from sage.symbolic.constants import pi from sage.structure.sequence import Sequence from sage.plot.all import Graphics, point2d, line2d, arrow, polygon2d diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 1fcefddd53b..0e28267b23b 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -712,7 +712,7 @@ def _latex_(self): ....: print(latex(h)) x_{0} + x_{1} - x_{2} = 1 x_{0} \geq 0 - 2 \, x_{0} + x_{1} \geq -1 + 2x_{0} + x_{1} \geq -1 """ return self.repr_pretty(latex=True) @@ -1690,15 +1690,16 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, sage: print(repr_pretty((1, -1, -1, 1), PolyhedronRepresentation.EQUATION)) -x0 - x1 + x2 == -1 """ - from sage.misc.latex import latex as latex_function - from sage.modules.free_module_element import vector - from sage.symbolic.ring import SR + from sage.misc.repr import repr_lincomb - coeffs = vector(coefficients) + coeffs = list(coefficients) if indices is None: indices = range(len(coeffs)-1) - vars = vector([1] + list(SR(prefix + '{}'.format(i)) for i in indices)) - f = latex_function if latex else repr + vars = [1] + if latex: + vars += ['x_{{{}}}'.format(i) for i in indices] + else: + vars += ['x{}'.format(i) for i in indices] if type == PolyhedronRepresentation.EQUATION: rel = '=' if latex else '==' elif type == PolyhedronRepresentation.INEQUALITY: @@ -1710,18 +1711,20 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, raise NotImplementedError( 'no pretty printing available: wrong type {}'.format(type)) + rvars = range(len(vars)) + if style == 'positive': - pos_part = vector([max(c, 0) for c in coeffs]) - neg_part = pos_part - coeffs - assert coeffs == pos_part - neg_part - left_part = f(pos_part*vars) - right_part = f(neg_part*vars) + pos_part = [max(c, 0) for c in coeffs] + neg_part = [pos_part[i] - coeffs[i] for i in rvars] + assert all(coeffs[i] == pos_part[i] - neg_part[i] for i in rvars) + left_part = repr_lincomb([[vars[i], pos_part[i]] for i in rvars], is_latex=latex, strip_one=True) + right_part = repr_lincomb([[vars[i], neg_part[i]] for i in rvars], is_latex=latex, strip_one=True) elif style == '>=': - left_part = f(coeffs[1:]*vars[1:]) - right_part = f(-coeffs[0]) + left_part = repr_lincomb([[vars[i], coeffs[i]] for i in rvars[1:]], is_latex=latex) + right_part = repr_lincomb([[vars[0], -coeffs[0]]], is_latex=latex, strip_one=True) elif style == '<=': - left_part = f(-coeffs[1:]*vars[1:]) - right_part = f(coeffs[0]) + left_part = repr_lincomb([[vars[i], -coeffs[i]] for i in rvars[1:]], is_latex=latex) + right_part = repr_lincomb([[vars[0], coeffs[0]]], is_latex=latex, strip_one=True) else: raise NotImplementedError('no pretty printing available: wrong style {}'.format(style)) From 676111f658dc3def03ad1b76437ec41feec0f729 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 27 Aug 2021 20:54:11 -0700 Subject: [PATCH 119/355] sage_setup.library_order: Take module list from new variables sage.env.default_{required,optional}_modules --- src/sage/env.py | 25 ++++++++++++++++++++----- src/sage_setup/library_order.py | 5 ++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 2205c4f6573..c18085d663b 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -397,18 +397,27 @@ def get_cblas_pc_module_name() -> str: cblas_pc_modules = CBLAS_PC_MODULES.split(':') return next((blas_lib for blas_lib in cblas_pc_modules if pkgconfig.exists(blas_lib))) -def cython_aliases(required_modules=('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', - 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas'), - optional_modules=('lapack',)): + +default_required_modules = ('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', + 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas') + + +default_optional_modules = ('lapack',) + + +def cython_aliases(required_modules=None, + optional_modules=None): """ Return the aliases for compiling Cython code. These aliases are macros which can occur in ``# distutils`` headers. INPUT: - - ``required_modules`` -- iterable of ``str`` values. + - ``required_modules`` -- (default: taken from ``default_required_modules``) + iterable of ``str`` values. - - ``optional_modules`` -- iterable of ``str`` values. + - ``optional_modules`` -- (default: taken from ``default_optional_modules``) + iterable of ``str`` values. EXAMPLES:: @@ -451,6 +460,12 @@ def cython_aliases(required_modules=('fflas-ffpack', 'givaro', 'gsl', 'linbox', import pkgconfig import itertools + if required_modules is None: + required_modules = default_required_modules + + if optional_modules is None: + optional_modules = default_optional_modules + aliases = {} for lib, required in itertools.chain(((lib, True) for lib in required_modules), diff --git a/src/sage_setup/library_order.py b/src/sage_setup/library_order.py index ef1f47d8d2e..8830d44a955 100644 --- a/src/sage_setup/library_order.py +++ b/src/sage_setup/library_order.py @@ -10,10 +10,9 @@ # important in particular for Cygwin. Any libraries which are not # listed here will be added at the end of the list (without changing # their relative order). -from sage.env import cython_aliases +from sage.env import cython_aliases, default_required_modules, default_optional_modules -modules = ('fflas-ffpack', 'gsl', 'linbox', 'Singular', - 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas') +modules = default_required_modules + default_optional_modules aliases = cython_aliases(required_modules=(), optional_modules=modules) From 74d324f37e20c80488d38f1f4e8c22c0a3e02108 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 29 Aug 2021 17:59:58 +0200 Subject: [PATCH 120/355] Trac #29851: add sequences --- .../characteristic_cohomology_class.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 7ca8e99f448..e623c53a2d3 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -228,6 +228,50 @@ def _repr_(self): repr = f'Algebra of characteristic cohomology classes of the {vbundle}' return repr + def multiplicative_sequence(self, q): + r""" + Turn the polynomial ``q`` into its multiplicative sequence. + + OUTPUT: + + - A symmetric polynomial representing the multiplicative sequence. + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + from sage.misc.misc_c import prod + + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() + + # Get the multiplicative sequence in the monomial basis: + mon_pol = m._from_dict({p: prod(q[i] for i in p) + for k in range(len(q.degree())) + for p in Partitions(k)}) + return Sym.e()(mon_pol) + + def additive_sequence(self, q): + r""" + Turn the polynomial ``q`` into its additive sequence. + + OUTPUT: + + - A symmetric polynomial representing the additive sequence. + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() + rk = self._vbundle._rank + + # Express the additive sequence in the monomial basis, the 0th + # order term must be treated separately: + m_dict = {Partitions(0)([]): rk * q[0]} + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree())}) + mon_pol = m._from_dict(m_dict) + return Sym.e()(mon_pol) # ***************************************************************************** # ALGORITHMS From 1f51ca73c5e5ab0ac1a5e5361b1100198c765dd1 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 29 Aug 2021 18:04:20 +0200 Subject: [PATCH 121/355] Trac #29851: sequences as static functions --- .../characteristic_cohomology_class.py | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index e623c53a2d3..265ed251e1d 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -228,54 +228,59 @@ def _repr_(self): repr = f'Algebra of characteristic cohomology classes of the {vbundle}' return repr - def multiplicative_sequence(self, q): - r""" - Turn the polynomial ``q`` into its multiplicative sequence. +# ***************************************************************************** +# ALGORITHMS +# ***************************************************************************** - OUTPUT: +def multiplicative_sequence(q): + r""" + Turn the polynomial ``q`` into its multiplicative sequence. - - A symmetric polynomial representing the multiplicative sequence. - """ - from sage.combinat.sf.sf import SymmetricFunctions - from sage.combinat.partition import Partitions - from sage.misc.misc_c import prod + OUTPUT: - R = q.parent().base_ring() - Sym = SymmetricFunctions(R) - m = Sym.m() + - A symmetric polynomial representing the multiplicative sequence. + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + from sage.misc.misc_c import prod - # Get the multiplicative sequence in the monomial basis: - mon_pol = m._from_dict({p: prod(q[i] for i in p) - for k in range(len(q.degree())) - for p in Partitions(k)}) - return Sym.e()(mon_pol) + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() - def additive_sequence(self, q): - r""" - Turn the polynomial ``q`` into its additive sequence. + # Get the multiplicative sequence in the monomial basis: + mon_pol = m._from_dict({p: prod(q[i] for i in p) + for k in range(len(q.degree())) + for p in Partitions(k)}) + return Sym.e()(mon_pol) - OUTPUT: +def additive_sequence(q, rk): + r""" + Turn the polynomial ``q`` into its additive sequence. - - A symmetric polynomial representing the additive sequence. - """ - from sage.combinat.sf.sf import SymmetricFunctions - from sage.combinat.partition import Partitions + INPUT: - R = q.parent().base_ring() - Sym = SymmetricFunctions(R) - m = Sym.m() - rk = self._vbundle._rank + - ``q`` -- polynomial to turn into its additive sequence. + - ``rk`` -- rank of the underlying vector bundle - # Express the additive sequence in the monomial basis, the 0th - # order term must be treated separately: - m_dict = {Partitions(0)([]): rk * q[0]} - m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree())}) - mon_pol = m._from_dict(m_dict) - return Sym.e()(mon_pol) + OUTPUT: + + - A symmetric polynomial representing the additive sequence. + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() + + # Express the additive sequence in the monomial basis, the 0th + # order term must be treated separately: + m_dict = {Partitions(0)([]): rk * q[0]} + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree())}) + mon_pol = m._from_dict(m_dict) + return Sym.e()(mon_pol) -# ***************************************************************************** -# ALGORITHMS -# ***************************************************************************** def fast_wedge_power(form, n): r""" From ffa79bb0e94248699da3b73946310aa8eefa9516 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 29 Aug 2021 18:10:04 +0200 Subject: [PATCH 122/355] Trac #29851: improve doc --- .../differentiable/characteristic_cohomology_class.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 265ed251e1d..68c865f834e 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -275,7 +275,7 @@ def additive_sequence(q, rk): m = Sym.m() # Express the additive sequence in the monomial basis, the 0th - # order term must be treated separately: + # order term must be treated separately; here comes ``rk`` into play: m_dict = {Partitions(0)([]): rk * q[0]} m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree())}) mon_pol = m._from_dict(m_dict) @@ -362,7 +362,8 @@ def get_local(self, cmat): @cached_method def get_gen_pow(self, nab, i, n): r""" - Return the `n`-th power of the `i`-th generator's characteristic form. + Return the `n`-th power of the `i`-th generator's characteristic form + w.r.t ``nab``. """ if n == 0: return nab._domain._one_scalar_field # no computation necessary @@ -578,7 +579,7 @@ def get_local(self, cmat): @cached_method def get_gen_pow(self, nab, i, n): r""" - Return the `n`-th power of the `i`-th generator. + Return the `n`-th power of the `i`-th generator w.r.t ``nab``. """ if n == 0: return nab._domain._one_scalar_field # no computation necessary From 1965cb563b6e1468427d44e0c9aadd0545587ba5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 29 Aug 2021 18:20:19 +0200 Subject: [PATCH 123/355] add composition with a degree 1 polynomial --- src/sage/rings/lazy_series.py | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 71c991d384b..6d96d1eab16 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -93,6 +93,7 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.arith.power import generic_power from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, @@ -2553,7 +2554,45 @@ def __invert__(self): P = self.parent() return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream)) + def __call__(self, p): + r""" + Return the composition of ``self`` with a linear polynomial ``p``. + + Return the series with the variable `s` replaced by a linear + polynomial `a\cdot s + b`, for nonzero `a`. + + EXAMPLES:: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: P. = QQ[] + sage: Z = D(constant=1) + sage: from sage.arith.misc import dedekind_psi + sage: Psi = D(dedekind_psi) + sage: Z(s)*Z(s-1)/Z(2*s) - Psi + O(1/(8^s)) + + sage: Z(s)*Z(s-1)/Z(2*s-2) - (1/Psi).map_coefficients(abs) + O(1/(8^s)) + + """ + P = self.parent() + R = PolynomialRing(ZZ, P.variable_name()) + p = R(p) + if p.degree() != 1: + raise ValueError("the argument must be a linear polynomial of degree 1 with integer coefficients") + coeff_stream = self._coeff_stream + b, a = p + def coefficient(m): + m = ZZ(m) + try: + n = m.nth_root(a) + return coeff_stream[n] * n ** (-b) + except ValueError: + return 0 + return P.element_class(P, Stream_function(coefficient, P._coeff_ring, P._sparse, 1)) + def change_ring(self, ring): + """ Return this series with coefficients converted to elements of ``ring``. From e50e141887735a40abf2d0d7373256fb08797bdf Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 29 Aug 2021 19:51:59 +0200 Subject: [PATCH 124/355] fix convolution with 2-zeta --- src/sage/rings/lazy_series.py | 41 +++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 71c991d384b..198d5503b4b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2475,34 +2475,35 @@ def _mul_(self, other): TESTS:: - sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: g = L(constant=1); g - 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) - sage: g*g - 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: zeta = D(constant=1); zeta + 1 + 1/(2^s) + 1/(3^s) + O(1/(4^s)) + sage: zeta * zeta + 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) sage: [number_of_divisors(n) for n in range(1, 8)] [1, 2, 2, 3, 2, 4, 2] - sage: mu = L(moebius); mu - 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) - sage: g*mu - 1 + O(1/(8^z)) - sage: L.one() * mu is mu + sage: mu = D(moebius); mu + 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) + sage: zeta * mu + 1 + O(1/(8^s)) + sage: D.one() * mu is mu True - sage: mu * L.one() is mu + sage: mu * D.one() is mu True - sage: d1 = L([0,0,1,2,3]) - sage: d2 = L([0,1,2,3]) + sage: zeta*(2-zeta) + 1 - 1/(4^s) - 2/6^s + O(1/(8^s)) + + sage: d1 = D([0,0,1,2,3]) + sage: d2 = D([0,1,2,3]) sage: d1 * d2 - 1/(6^z) + 2/8^z + 2/9^z + 3/10^z + 7/12^z + O(1/(13^z)) + 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + O(1/(13^s)) sage: d1 * d2 # not tested - exact result - 1/(6^z) + 2/8^z + 2/9^z + 3/10^z + 7/12^z + 6/15^z + 6/16^z + 9/20^z + 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + 6/15^s + 6/16^s + 9/20^s - sage: D = LazyDirichletSeriesRing(QQ, "s") sage: L. = LazyLaurentSeriesRing(D) - sage: zeta = D(constant=1) sage: 1/(1-t*zeta) (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 + (1 + 3/2^s + 3/3^s + 6/4^s + 3/5^s + 9/6^s + 3/7^s + O(1/(8^s)))*t^3 + (1 + 4/2^s + 4/3^s + 10/4^s + 4/5^s + 16/6^s + 4/7^s + O(1/(8^s)))*t^4 + (1 + 5/2^s + 5/3^s + 15/4^s + 5/5^s + 25/6^s + 5/7^s + O(1/(8^s)))*t^5 + (1 + 6/2^s + 6/3^s + 21/4^s + 6/5^s + 36/6^s + 6/7^s + O(1/(8^s)))*t^6 + O(t^7) @@ -2515,13 +2516,15 @@ def _mul_(self, other): if isinstance(right, Stream_zero): return other if (isinstance(left, Stream_exact) + and not left._constant and left._initial_coefficients == (P._coeff_ring.one(),) and left.order() == 1): - return other # self == 1 + return other # self == 1 if (isinstance(right, Stream_exact) + and not right._constant and right._initial_coefficients == (P._coeff_ring.one(),) and right.order() == 1): - return self + return self # other == 1 coeff = Stream_dirichlet_convolve(left, right) # Performing exact arithmetic is slow because the series grow large # very quickly as we are multiplying the degree From 6e16034e896732cec40c99d558af8f75637c604e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 30 Aug 2021 12:21:14 +1000 Subject: [PATCH 125/355] Adding more optional sirocco markers. --- src/sage/libs/sirocco.pyx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 47504bd9d2a..7cebb9f2ef4 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -38,7 +38,7 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 EXAMPLES:: - sage: from sage.libs.sirocco import contpath_mp + sage: from sage.libs.sirocco import contpath_mp # optional - sirocco sage: from sage.rings.real_mpfr import RR sage: pol = list(map(RR, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) sage: contpath_mp(2, pol, RR(0), RR(0), 53) # optional - sirocco # abs tol 1e-15 @@ -99,7 +99,7 @@ cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNum EXAMPLES:: - sage: from sage.libs.sirocco import contpath_mp_comps + sage: from sage.libs.sirocco import contpath_mp_comps # optional - sirocco sage: from sage.rings.real_mpfr import RR sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) @@ -191,7 +191,7 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): EXAMPLES:: - sage: from sage.libs.sirocco import contpath + sage: from sage.libs.sirocco import contpath # optional - sirocco sage: from sage.rings.real_mpfr import RR sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) sage: contpath(2, pol, RR(0), RR(0)) # optional - sirocco # abs tol 1e-15 @@ -246,7 +246,7 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li EXAMPLES:: - sage: from sage.libs.sirocco import contpath_comps + sage: from sage.libs.sirocco import contpath_comps # optional - sirocco sage: from sage.rings.real_mpfr import RR sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) @@ -292,3 +292,4 @@ cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, li free(c_otherdegrees) free(c_othercoefs) return l + From 266c3dd3e3b14346cd2b4b1554d8b5c581c22e6e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Aug 2021 22:37:15 -0700 Subject: [PATCH 126/355] sage.symbolic.ring.UnderscoreSageMorphism.__init__: Call sympy_init This makes sure that all _sage_ methods have been patched into sympy classes. This is preparation for https://github.com/sympy/sympy/pull/21958, which removes the old sympy-provided _sage_ methods. --- src/sage/symbolic/ring.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 5338e12fece..724781b22e0 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1401,6 +1401,8 @@ cdef class UnderscoreSageMorphism(Morphism): import sage.categories.homset from sage.sets.pythonclass import Set_PythonType Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(t), R)) + from sage.interfaces.sympy import sympy_init + sympy_init() cpdef Element _call_(self, a): """ From 1da92af79b6b8aaa1d48210e7d153ced192b9411 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Aug 2021 09:58:12 +1000 Subject: [PATCH 127/355] Reverting to "backward" option for dot2tex graph layout. --- src/sage/categories/loop_crystals.py | 4 +-- src/sage/graphs/generic_graph.py | 52 +++++++++++++++++----------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 06bd9f55a17..f7d65416481 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -120,9 +120,7 @@ def digraph(self, subset=None, index_set=None): G = Crystals().parent_class.digraph(self, subset, index_set) if have_dot2tex(): def eopt(u_v_label): - if u_v_label[2] == 0: - return {"dir": "back"} - return {} + return {"backward": u_v_label[2] == 0} G.set_latex_options(edge_options=eopt) return G diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f82c9be11ac..75485617d13 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -20656,6 +20656,7 @@ def graphviz_string(self, **options): - ``"label_style"`` (``"string"`` or ``"latex"``) - ``"edge_string"`` (``"--"`` or ``"->"``) - ``"dir"`` (``"forward"``, ``"back"``, ``"both"`` or ``"none"``) + - ``"backward"`` (boolean) Here we state that the graph should be laid out so that edges starting from ``1`` are going backward (e.g. going up instead of @@ -20746,6 +20747,29 @@ def graphviz_string(self, **options): node_3 -> node_4 [dir=both]; } + We test the same graph and ``'dir'`` edge options but with + ``backward=True``:: + + sage: def edge_options(data): + ....: u,v,label = data + ....: if label == 'a': return {'dir':'forward', 'backward':True} + ....: if label == 'b': return {'dir':'back', 'backward':True} + ....: if label == 'c': return {'dir':'none', 'backward':True} + ....: if label == 'd': return {'dir':'both', 'backward':True} + sage: print(G.graphviz_string(edge_options=edge_options)) + digraph { + node_0 [label="0"]; + node_1 [label="1"]; + node_2 [label="2"]; + node_3 [label="3"]; + node_4 [label="4"]; + + node_1 -> node_0 [dir=back]; + node_2 -> node_1; + node_3 -> node_2 [dir=none]; + node_4 -> node_3 [dir=both]; + } + TESTS: The following digraph has tuples as vertices:: @@ -20873,20 +20897,6 @@ def graphviz_string(self, **options): ... ValueError: edge_string(='<-') in edge_options dict for the edge (0, 1) should be '--' or '->' - - The ``'backward'`` parameter of an edge option is deprecated since - :trac:`31381`:: - - sage: edges = [(0,1,'a'), (1,2,'b'), (2,3,'c'), (3,4,'d')] - sage: G = DiGraph(edges) - sage: def edge_options(data): - ....: u,v,label = data - ....: return {'backward':True} if label == 'a' else {} - sage: _ = G.graphviz_string(edge_options=edge_options) - doctest:...: DeprecationWarning: parameter {'backward':True} (in edge_options) - is deprecated. Use {'dir':'back'} instead. - See https://trac.sagemath.org/31381 for details. - """ from sage.graphs.dot2tex_utils import quoted_latex, quoted_str @@ -20978,6 +20988,7 @@ def graphviz_string(self, **options): for u, v, label in self.edge_iterator(): edge_options = { 'dir': default_edge_dir, + 'backward': False, 'dot': None, 'edge_string': default_edge_string, 'color' : default_color, @@ -20992,12 +21003,6 @@ def graphviz_string(self, **options): "edge ({}, {}) should be '--' " "or '->'".format(edge_options['edge_string'], u, v)) - if 'backward' in edge_options and edge_options['backward']: - deprecation(31381, "parameter {'backward':True} (in edge_options) is" - " deprecated. Use {'dir':'back'} instead.") - del edge_options['backward'] - edge_options['dir'] = 'back' - dot_options = [] if edge_options['dot'] is not None: @@ -21019,6 +21024,13 @@ def graphviz_string(self, **options): dot_options.append('color = "%s"' % col) + if edge_options['backward']: + u, v = v, u + if edge_options['dir'] == 'forward': + edge_options['dir'] = 'back' + elif edge_options['dir'] == 'back': + edge_options['dir'] = 'forward' + if edge_options['dir'] == default_edge_dir: pass elif edge_options['dir'] in ['forward', 'back', 'both', 'none']: From 91a84500ee29a71f950ef1e964e0f3c5b7d1cc27 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 31 Aug 2021 21:38:59 +0200 Subject: [PATCH 128/355] leading coefficient must be positive --- src/sage/rings/lazy_series.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 747ff71c33c..feace8949fb 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2562,7 +2562,7 @@ def __call__(self, p): Return the composition of ``self`` with a linear polynomial ``p``. Return the series with the variable `s` replaced by a linear - polynomial `a\cdot s + b`, for nonzero `a`. + polynomial `a\cdot s + b`, for positive `a`. EXAMPLES:: @@ -2585,6 +2585,8 @@ def __call__(self, p): raise ValueError("the argument must be a linear polynomial of degree 1 with integer coefficients") coeff_stream = self._coeff_stream b, a = p + if a < 0: + raise ValueError("the leading coefficient must be positive") def coefficient(m): m = ZZ(m) try: From 9a31db0c48dfe9d2b21a4d692b3a60a3f07b546a Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 31 Aug 2021 22:48:36 +0200 Subject: [PATCH 129/355] fix LazyDirichletSeriesRing.one --- src/sage/rings/lazy_series_ring.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 16e940b8dff..9206ed1d9a1 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1085,8 +1085,11 @@ def one(self): sage: L = LazyDirichletSeriesRing(ZZ, 'z') sage: L.one() 1 + sage: ~L.one() + 1 + O(1/(8^z)) """ - return self.element_class(self, Stream_exact([1], self._sparse, order=1)) + R = self.base_ring() + return self.element_class(self, Stream_exact([R.one()], self._sparse, order=1)) @cached_method def zero(self): From a0a5c0f4d65c700469b9ee09fb5df708eeded600 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 31 Aug 2021 20:45:14 -0700 Subject: [PATCH 130/355] src/sage/sets/real_set.py, src/sage/categories/sets_cat.py: Update doctests to accept sympy 1.9 --- src/sage/categories/sets_cat.py | 2 +- src/sage/sets/real_set.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 3ba6e7e90a6..74f7621ce18 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1710,7 +1710,7 @@ def _sympy_(self): sage: list(sF) [1, 2, 3] sage: from sympy import FiniteSet - sage: FiniteSet.fromiter(sF) + sage: FiniteSet.fromiter(sF) # random - this output format is sympy >= 1.9 FiniteSet(1, 2, 3) sage: RR._sympy_().is_finite_set diff --git a/src/sage/sets/real_set.py b/src/sage/sets/real_set.py index b8fcf1d7500..149d7245669 100644 --- a/src/sage/sets/real_set.py +++ b/src/sage/sets/real_set.py @@ -452,8 +452,10 @@ def _sympy_(self): sage: RealSet.open_closed(0, 1)[0]._sympy_() Interval.Lopen(0, 1) - sage: RealSet.point(0)[0]._sympy_() - FiniteSet(0) + sage: RealSet.point(0)[0]._sympy_() # random - this output format is sympy >= 1.9 + {0} + sage: type(_) + sage: RealSet.open(0,1)[0]._sympy_() Interval.open(0, 1) sage: RealSet.open(-oo,1)[0]._sympy_() @@ -2388,10 +2390,10 @@ def _sympy_(self): sage: RealSet()._sympy_() EmptySet - sage: RealSet.point(5)._sympy_() - FiniteSet(5) - sage: (RealSet.point(1).union(RealSet.point(2)))._sympy_() - FiniteSet(1, 2) + sage: RealSet.point(5)._sympy_() # random - this output format is sympy >= 1.9 + {5} + sage: (RealSet.point(1).union(RealSet.point(2)))._sympy_() # random + {1, 2} sage: (RealSet(1, 2).union(RealSet.closed(3, 4)))._sympy_() Union(Interval.open(1, 2), Interval(3, 4)) sage: RealSet(-oo, oo)._sympy_() From f30863c42113fecbc85b5acbd26e49cec122d032 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 1 Sep 2021 11:00:09 +0200 Subject: [PATCH 131/355] deal with series whose coefficients are Dirichlet series --- src/sage/data_structures/stream.py | 19 ++++ src/sage/rings/lazy_series_ring.py | 136 +++++++++++++++++------------ 2 files changed, 97 insertions(+), 58 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 71f18956cd7..552aeafcc19 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -188,6 +188,25 @@ def __init__(self, is_sparse, approximate_order): self._offset = approximate_order self._iter = self.iterate_coefficients() + def is_nonzero(self): + r""" + Return ``True`` if and only if the cache contains a nonzero element. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: CS = Stream_function(lambda n: 1/n, ZZ, False, 1) + sage: CS.is_nonzero() + False + sage: CS[1] + 1 + sage: CS.is_nonzero() + True + """ + if self._is_sparse: + return any(self._cache.values()) + return any(self._cache) + def __getstate__(self): """ Build the dictionary for pickling ``self``. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 6f725f73b8e..d57f3222543 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -509,6 +509,21 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No We note that ``e`` builds correctly because ``R`` additionally requires the valuation to be specified. + In the next example the argument is interpreted as a constant + polynomial, which happens to be a Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(D) + sage: L(lambda n: 1/factorial(n), valuation=0) + (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) + + We can also specify that the given function should be + interpreted as the coefficients of the Laurent series:: + + sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + + TESTS: Checking the valuation is consistent:: @@ -600,6 +615,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No .. TODO:: Add a method to change the sparse/dense implementation. + """ if valuation is not None and valuation not in ZZ: raise ValueError("the valuation must be an integer") @@ -609,13 +625,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError("the valuation must be specified") return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) + if coefficients is not None and (not isinstance(x, int) or x): + raise ValueError("coefficients must be None if x is provided") + R = self._laurent_poly_ring BR = self.base_ring() - try: - # Try to build stuff using the polynomial ring constructor - x = R(x) - except (TypeError, ValueError): - pass if isinstance(constant, (tuple, list)): constant, degree = constant if isinstance(degree, (tuple, list)): @@ -623,65 +637,72 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No if constant is not None: constant = BR(constant) - # If x has been converted to the Laurent polynomial ring - if parent(x) is R: - if not x and not constant: - return self.zero() - if x and valuation is not None: - x = x.shift(valuation - x.valuation()) - if degree is None and not x: - if valuation is None: - raise ValueError("you must specify the degree for the polynomial 0") - degree = valuation - if x == R.zero(): - coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) - return self.element_class(self, coeff_stream) - initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] - coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=x.valuation(), constant=constant, degree=degree) - return self.element_class(self, coeff_stream) - - if isinstance(x, LazyCauchyProductSeries): - if x._coeff_stream._is_sparse is not self._sparse: - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") - - # If x is known to be 0 - if isinstance(x._coeff_stream, Stream_zero): - if not constant: - return x - if degree is None: + if coefficients is None: + try: + # Try to build stuff using the polynomial ring constructor + x = R(x) + except (TypeError, ValueError): + pass + + # If x has been converted to the Laurent polynomial ring + if parent(x) is R: + if not x and not constant: + return self.zero() + if x and valuation is not None: + x = x.shift(valuation - x.valuation()) + if degree is None and not x: if valuation is None: raise ValueError("you must specify the degree for the polynomial 0") degree = valuation - coeff_stream = Stream_exact([], self._sparse, order=degree, - constant=constant) - return self.element_class(self, coeff_stream) - - # Make the result exact - if degree is not None: - # truncate the series and then possibly make constant - x_val = x.valuation() - if not valuation: - valuation = x_val - initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] - if not any(initial_coefficients): - if not constant: - return self.zero() - # We learned some stuff about x; pass it along - x._coeff_stream._approximate_order += len(initial_coefficients) - initial_coefficients = [] + if x == R.zero(): + coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) + return self.element_class(self, coeff_stream) + initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=valuation, constant=constant, degree=degree) + order=x.valuation(), constant=constant, degree=degree) return self.element_class(self, coeff_stream) - # We are just possibly shifting the result - ret = self.element_class(self, x._coeff_stream) - if valuation is None: - return ret - return x.shift(valuation - ret.valuation()) + if isinstance(x, LazyCauchyProductSeries): + if x._coeff_stream._is_sparse is not self._sparse: + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + + # If x is known to be 0 + if isinstance(x._coeff_stream, Stream_zero): + if not constant: + return x + if degree is None: + if valuation is None: + raise ValueError("you must specify the degree for the polynomial 0") + degree = valuation + coeff_stream = Stream_exact([], self._sparse, order=degree, + constant=constant) + return self.element_class(self, coeff_stream) + + # Make the result exact + if degree is not None: + # truncate the series and then possibly make constant + x_val = x.valuation() + if not valuation: + valuation = x_val + initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] + if not any(initial_coefficients): + if not constant: + return self.zero() + # We learned some stuff about x; pass it along + x._coeff_stream._approximate_order += len(initial_coefficients) + initial_coefficients = [] + coeff_stream = Stream_exact(initial_coefficients, self._sparse, + order=valuation, constant=constant, degree=degree) + return self.element_class(self, coeff_stream) + + # We are just possibly shifting the result + ret = self.element_class(self, x._coeff_stream) + if valuation is None: + return ret + return x.shift(valuation - ret.valuation()) - if x is None and coefficients is not None: + else: x = coefficients if callable(x): @@ -1166,4 +1187,3 @@ class options(GlobalOptions): constant_length = dict(default=3, description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) - From cd348793ac23838da3545555f0d59d24f34eeace Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 2 Sep 2021 08:59:17 +0200 Subject: [PATCH 132/355] add characteristic --- src/sage/rings/lazy_series_ring.py | 35 ++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index d57f3222543..d4e0771e815 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -34,8 +34,8 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.lazy_series import (LazyCauchyProductSeries, - LazyLaurentSeries, - LazyDirichletSeries) + LazyLaurentSeries, + LazyDirichletSeries) from sage.structure.global_options import GlobalOptions from sage.symbolic.ring import SR @@ -267,6 +267,24 @@ def _latex_(self): from sage.misc.latex import latex return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.characteristic() + 0 + sage: R. = LazyLaurentSeriesRing(GF(11)); R + Lazy Laurent Series Ring in w over Finite Field of size 11 + sage: R.characteristic() + 11 + + """ + return self.base_ring().characteristic() + def is_sparse(self): """ Return whether ``self`` is sparse or not. @@ -989,6 +1007,19 @@ def _repr_(self): """ return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "s") + sage: L.characteristic() + 0 + """ + return self.base_ring().characteristic() + @cached_method def monomial(self, c, n): r""" From 60985084970fbb5c48ee4da2ede2cbd7ef652df4 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 2 Sep 2021 08:59:35 +0200 Subject: [PATCH 133/355] remove caching of monomial --- src/sage/rings/lazy_series_ring.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index d4e0771e815..eda0b06bdd7 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -301,7 +301,6 @@ def is_sparse(self): """ return self._sparse - @cached_method def monomial(self, c, n): r""" Return the interpretation of the coefficient ``c`` at index ``n``. @@ -1020,7 +1019,6 @@ def characteristic(self): """ return self.base_ring().characteristic() - @cached_method def monomial(self, c, n): r""" Return the interpretation of the coefficient ``c`` at index ``n``. From dd0b11a763f980260cc7285c55f8d62d5cfed7ea Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 2 Sep 2021 09:06:46 +0200 Subject: [PATCH 134/355] adapt doc of LazyLaurenSeriesRing._element_constructor_, begin to make LazyDirichletSeriesRing._element_constructor_ consistent --- src/sage/rings/lazy_series_ring.py | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index eda0b06bdd7..aeb5d156874 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -414,10 +414,10 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No - ``x`` -- data used to the define a Laurent series - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - - ``constant`` -- (optional) the eventual constant of the series - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``constant`` -- (optional) the eventual constant of the series - ``coefficients`` -- (optional) a callable that defines the - coefficients of the series; ignored if ``x`` is not ``None``; + coefficients of the series; must be ``None`` if ``x`` is provided; see note below If ``valuation`` is specified and ``x`` is convertible into a Laurent @@ -437,9 +437,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No the base ring. If instead the input is to be treated as the function giving the coefficients of the lazy series being cosntructed, then use the ``coefficients`` argument in this - case and leave ``x`` as ``None``. - - If ``x`` is given ``coefficients`` is ignored. + case and do not provide ``x``. EXAMPLES:: @@ -540,7 +538,6 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - TESTS: Checking the valuation is consistent:: @@ -1059,17 +1056,17 @@ def _coerce_map_from_base_ring(self): # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. return self._generic_coerce_map(self.base_ring()) - def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None): + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None): """ Construct a Dirichlet series from ``x``. INPUT: - - ``x`` -- a Dirichlet series, a Dirichlet polynomial, a Python - function, or a list of elements in the base ring - - - ``constant`` -- integer (optional); pair of - an element of the base ring and an integer + - ``x`` -- data used to the define a Dirichlet series + - ``valuation`` -- integer (optional); integer; a lower bound for + the valuation of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``constant`` -- (optional) the eventual constant of the series EXAMPLES:: @@ -1100,7 +1097,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: f = L([1,2,3,4], 4); f 1/(4^z) + 2/5^z + 3/6^z + 4/7^z - sage: g = L([1,3,5,7,9], 6, -1); g + sage: g = L([1,3,5,7,9], 6, constant=-1); g 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) - 1/(13^z) + O(1/(14^z)) TESTS:: @@ -1116,18 +1113,21 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No """ if valuation is None: valuation = 1 - if valuation <= 0: - raise ValueError("the valuation of a Dirichlet series must be positive") + elif valuation not in ZZ or valuation <= 0: + raise ValueError("the valuation must be a positive integer") if x is None: return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) BR = self.base_ring() - if constant is None: - constant = ZZ.zero() - elif isinstance(constant, (tuple, list)): + if isinstance(constant, (tuple, list)): constant, degree = constant - constant = BR(constant) + if isinstance(degree, (tuple, list)): + constant, degree = degree + if constant is None: + constant = BR(ZZ.zero()) + else: + constant = BR(constant) if x in BR: x = BR(x) @@ -1138,6 +1138,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No x = [] else: x = [x] + if isinstance(x, (tuple, list)): coeff_stream = Stream_exact(x, self._sparse, order=valuation, From f55c707a1f0086b5f115d4d4f7556e4bd5bd3d8b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 2 Sep 2021 10:56:19 +0200 Subject: [PATCH 135/355] fix doctests --- src/sage/rings/lazy_series.py | 83 +++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index ddf3a7ba063..662c2057858 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -312,9 +312,9 @@ def map_coefficients(self, func, ring=None): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: s = L(lambda n: n-1); s - 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + ... + 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + O(1/(8^z)) sage: s.map_coefficients(lambda c: c + 1) - 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) TESTS:: @@ -867,11 +867,11 @@ def _add_(self, other): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: s = L(lambda n: n); s - 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + ... + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) sage: t = L(constant=1); t - 1 + 1/(2^z) + 1/(3^z) + ... + 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) sage: s + t - 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + ... + 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + O(1/(8^z)) sage: r = L(constant=-1) sage: r + t @@ -879,7 +879,7 @@ def _add_(self, other): sage: r = L([1,2,3]) sage: r + t - 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + ... + 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) sage: r = L([1,2,3], constant=-1) sage: r + t @@ -1468,12 +1468,16 @@ def _div_(self, other): sage: P = M / N; P z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - Lazy Laurent series that are known to be exact can be divided:: + If the division of exact Lazy Laurent series yields a Laurent + polynomial, it is represented as an exact series:: + + sage: 1/z + z^-1 - M = z^2 + 2*z + 1 - N = z + 1 - O = M / N; O - z + 1 + sage: m = z^2 + 2*z + 1 + sage: n = z + 1 + sage: m / n + 1 + z An example over the ring of symmetric functions:: @@ -1482,6 +1486,7 @@ def _div_(self, other): sage: 1 / (1 - e[1]*z) e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) + """ if isinstance(other._coeff_stream, Stream_zero): raise ZeroDivisionError("cannot divide by 0") @@ -1494,23 +1499,30 @@ def _div_(self, other): if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact)): if not left._constant and not right._constant: + # # alternatively: + # pl = self.finite_part() + # pr = other.finite_part() + # try: + # ret = pl / pr + # ret = P._laurent_poly_ring(ret) + # except (TypeError, ValueError, NotImplementedError): + # # We cannot divide the polynomials, so the result must be a series + # pass + # return P(ret) R = P._laurent_poly_ring - # pl = left.polynomial_part(R) - # pr = right.polynomial_part(R) - pl = self.finite_part() - pr = other.finite_part() + pl = left._polynomial_part(R) + pr = right._polynomial_part(R) try: ret = pl / pr ret = P._laurent_poly_ring(ret) - return P(ret) - # ret = pl / pr - # ret = P._laurent_poly_ring(ret) - # initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - # return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - # valuation=ret.valuation(), constant=left._constant)) except (TypeError, ValueError, NotImplementedError): # We cannot divide the polynomials, so the result must be a series pass + else: + initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + order=ret.valuation(), + constant=left._constant)) return P.element_class(P, Stream_cauchy_mul(left, Stream_cauchy_invert(right))) @@ -1574,14 +1586,16 @@ def __pow__(self, n): if (isinstance(cs, Stream_exact) and not cs._constant and n in ZZ and (n > 0 or len(cs._initial_coefficients) == 1)): + # # alternatively: + # return P(self.finite_part() ** ZZ(n)) P = self.parent() - return P(self.finite_part() ** ZZ(n)) - # ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) - # val = ret.valuation() - # deg = ret.degree() + 1 - # initial_coefficients = [ret[i] for i in range(val, deg)] - # return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - # constant=cs._constant, degree=deg, valuation=val)) + ret = cs._polynomial_part(P._laurent_poly_ring) ** ZZ(n) + val = ret.valuation() + deg = ret.degree() + 1 + initial_coefficients = [ret[i] for i in range(val, deg)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + constant=cs._constant, + degree=deg, order=val)) return generic_power(self, n) @@ -2020,8 +2034,9 @@ def __call__(self, g): deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] coeff_stream = Stream_exact(initial_coefficients, - self._coeff_stream._is_sparse, constant=P.base_ring().zero(), - degree=deg, order=val) + self._coeff_stream._is_sparse, + constant=P.base_ring().zero(), + degree=deg, order=val) return P.element_class(P, coeff_stream) # Return the sum since g is not known to be finite or we do not get a Laurent polynomial @@ -2359,8 +2374,8 @@ def shift(self, n): degree = self._coeff_stream._degree + n valuation = self._coeff_stream._approximate_order + n coeff_stream = Stream_exact(init_coeff, self._coeff_stream._is_sparse, - constant=self._coeff_stream._constant, - order=valuation, degree=degree) + constant=self._coeff_stream._constant, + order=valuation, degree=degree) else: coeff_stream = Stream_shift(self._coeff_stream, n) P = self.parent() @@ -2432,7 +2447,7 @@ class LazyDirichletSeries(LazyModuleElement): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: f = L(constant=1)^2; f - 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: f.coefficient(100) == number_of_divisors(100) True @@ -2440,7 +2455,7 @@ class LazyDirichletSeries(LazyModuleElement): sage: g = loads(dumps(f)) sage: g - 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + ... + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: g == f True """ From 973b0798a933c2340b4e39246449116f5c4c1827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 4 Sep 2021 08:46:39 +0200 Subject: [PATCH 136/355] remove some whitespaces in combinat --- src/sage/combinat/blob_algebra.py | 53 +++++++-------- src/sage/combinat/permutation.py | 2 +- src/sage/combinat/rsk.py | 67 +++++++++---------- .../symmetric_group_representations.py | 2 +- src/sage/combinat/tiling.py | 2 +- 5 files changed, 62 insertions(+), 64 deletions(-) diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 6bd3dba1747..50e372db417 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -498,32 +498,32 @@ def _latex_term(self, diagram): sage: R. = ZZ[] sage: B2 = algebras.Blob(2, q, r, s) sage: latex(B2.an_element()) # indirect doctest - 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); - \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); - \end{tikzpicture} - + 3\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \draw[blue,very thick] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. node[midway,circle,fill,scale=0.6] {} (G--1); - \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); - \end{tikzpicture} - + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \draw[blue,very thick] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. node[midway,circle,fill,scale=0.6] {} (G-2); - \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 3\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[blue,very thick] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. node[midway,circle,fill,scale=0.6] {} (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \draw[blue,very thick] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. node[midway,circle,fill,scale=0.6] {} (G-2); + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); \end{tikzpicture} """ def edge_options(P): @@ -678,4 +678,3 @@ def product_on_basis(self, top, bot): return self.zero() diagram = self._indices.element_class(self._indices, ret_lists[0], ret_lists[1]) return self._from_dict({diagram: coeff}, remove_zeros=False) - diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 19c0f6a5382..72947e020a1 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -706,7 +706,7 @@ def size(self) -> Integer: return len(self) grade = size # for the category SetsWithGrading() - + def cycle_string(self, singletons=False) -> str: """ Return a string of the permutation in cycle notation. diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 9bc3f1d8720..9dfcd25d2a0 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -1888,14 +1888,14 @@ class RuleSuperRSK(RuleRSK): * The input (in terms of biwords) is no longer an arbitrary biword, but rather a restricted super biword (i.e., a pair of two lists `[a_1, a_2, \ldots, a_n]` and `[b_1, b_2, \ldots, b_n]` that - contains entries with even and odd parity and pairs with mixed + contains entries with even and odd parity and pairs with mixed parity entries do not repeat). * The output still consists of two tableaux `(P, Q)` of equal shapes, but rather than both of them being semistandard, now they are semistandard super tableaux. - * The main difference is in the way bumping works. Instead of having + * The main difference is in the way bumping works. Instead of having only row bumping super RSK uses `\epsilon`-insertion, a combination of classical RSK bumping along the rows and a dual RSK like bumping (i.e. when a number `k_i` is inserted into the `i`-th row of `P`, it @@ -1912,7 +1912,7 @@ class RuleSuperRSK(RuleRSK): [[[1, 3], [3']], [[1, 2], [3]]] sage: RSK([1, 3, "3p", "2p"], insertion='superRSK') [[[1, 3', 3], [2']], [[1', 1, 2'], [2]]] - sage: RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["1p", 1, "2p", 2, "3p", "3p", "3p", 3], insertion='superRSK') [[[1', 2, 3', 3], [1, 3'], [2'], [3']], [[1', 2, 3', 3], [2', 3'], [2], [3]]] sage: P = SemistandardSuperTableau([[1, '3p', 3], ['2p']]) @@ -1922,7 +1922,7 @@ class RuleSuperRSK(RuleRSK): We apply super RSK on Example 5.1 in [Muth2019]_:: - sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["3p", 1, 2, 3, "3p", "3p", "2p", "1p"], insertion='superRSK') sage: (P, Q) ([[1', 2', 3', 3], [1, 2, 3'], [3']], [[1', 2, 2, 3'], [2', 3, 3], [3']]) @@ -1935,7 +1935,7 @@ class RuleSuperRSK(RuleRSK): Example 6.1 in [Muth2019]_:: - sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["3p", 1, 2, 3, "3p", "3p", "2p", "1p"], insertion='superRSK') sage: ascii_art((P, Q)) ( 1' 2' 3' 3 1' 2 2 3' ) @@ -1944,7 +1944,7 @@ class RuleSuperRSK(RuleRSK): sage: RSK_inverse(P, Q, insertion=RSK.rules.superRSK) [[1', 2', 2, 2, 3', 3', 3, 3], [3', 1, 2, 3, 3', 3', 2', 1']] - sage: P,Q = RSK(["1p", 1, "2p", 2, "3p", "3p", "3p", 3], + sage: P,Q = RSK(["1p", 1, "2p", 2, "3p", "3p", "3p", 3], ....: [3, "2p", 3, 2, "3p", "3p", "1p", 2], insertion='superRSK') sage: ascii_art((P, Q)) ( 1' 2 2 3' 1' 2' 3' 3 ) @@ -1960,7 +1960,7 @@ class RuleSuperRSK(RuleRSK): sage: RSK_inverse(P, Q, insertion=RSK.rules.superRSK) [[1, 2, 2, 2], [2, 1, 2, 3]] - When applied to two tableaux with only even parity elements, reverse super + When applied to two tableaux with only even parity elements, reverse super RSK insertion behaves identically to the usual reversel RSK insertion:: sage: t1 = Tableau([[1, 2, 5], [3], [4]]) @@ -1985,7 +1985,7 @@ class RuleSuperRSK(RuleRSK): different types of inputs/outputs:: sage: from sage.combinat.shifted_primed_tableau import PrimedEntry - sage: RSK_inverse(SemistandardSuperTableau([]), + sage: RSK_inverse(SemistandardSuperTableau([]), ....: SemistandardSuperTableau([]), insertion=RSK.rules.superRSK) [[], []] sage: f = lambda p: RSK_inverse(*RSK(p, insertion=RSK.rules.superRSK), @@ -2002,8 +2002,8 @@ class RuleSuperRSK(RuleRSK): Checking that tableaux should be of same shape:: - sage: RSK_inverse(SemistandardSuperTableau([[1, 2, 3]]), - ....: SemistandardSuperTableau([[1, 2]]), + sage: RSK_inverse(SemistandardSuperTableau([[1, 2, 3]]), + ....: SemistandardSuperTableau([[1, 2]]), ....: insertion=RSK.rules.superRSK) Traceback (most recent call last): ... @@ -2014,8 +2014,8 @@ def to_pairs(self, obj1=None, obj2=None, check=True): Given a valid input for the super RSK algorithm, such as two `n`-tuples ``obj1`` `= [a_1, a_2, \ldots, a_n]` and ``obj2`` `= [b_1, b_2, \ldots, b_n]` forming a restricted - super biword (i.e., entries with even and odd parity and no - repetition of corresponding pairs with mixed parity entries) + super biword (i.e., entries with even and odd parity and no + repetition of corresponding pairs with mixed parity entries) return the array `[(a_1, b_1), (a_2, b_2), \ldots, (a_n, b_n)]`. INPUT: @@ -2059,7 +2059,7 @@ def to_pairs(self, obj1=None, obj2=None, check=True): raise ValueError("the two arrays must be the same length") mixed_parity = [] # Check it is a restricted superbiword: that is, - # the entries can have even or odd parity, but repetition of + # the entries can have even or odd parity, but repetition of # the pairs of corresponding entries of obj1 # and obj2 with mixed-parity is not allowed for t, b in zip(obj1, obj2): @@ -2239,8 +2239,8 @@ def forward_rule(self, obj1, obj2, check_standard=False, check=True): def insertion(self, j, r, epsilon=0): r""" Insert the letter ``j`` from the second row of the biword - into the row ``r`` using dual RSK insertion or classical - Schensted insertion depending on the value of ``epsilon``, + into the row ``r`` using dual RSK insertion or classical + Schensted insertion depending on the value of ``epsilon``, if there is bumping to be done. The row `r` is modified in place if bumping occurs. The bumped-out @@ -2289,15 +2289,15 @@ def _forward_format_output(self, p, q, check_standard): sage: from sage.combinat.rsk import RuleSuperRSK sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [['1p', 1, '2p']], [['1p', '1', '2p']], True)[0], + ....: [['1p', 1, '2p']], [['1p', '1', '2p']], True)[0], ....: StandardSuperTableau) True sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [[1, '2p', 3]], [[1, 2, 3]], False)[0], + ....: [[1, '2p', 3]], [[1, 2, 3]], False)[0], ....: SemistandardSuperTableau) True sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [[1, 1, 3]], [[1, 2, 3]], True)[0], + ....: [[1, 1, 3]], [[1, 2, 3]], True)[0], ....: SemistandardSuperTableau) True """ @@ -2401,7 +2401,7 @@ def backward_rule(self, p, q, output='array'): def reverse_insertion(self, x, row, epsilon=0): r""" Reverse bump the row ``row`` of the current insertion tableau - with the number ``x`` using dual RSK insertion or classical + with the number ``x`` using dual RSK insertion or classical Schensted insertion depending on the value of `epsilon`. The row ``row`` is modified in place. The bumped-out entry @@ -2442,7 +2442,7 @@ def reverse_insertion(self, x, row, epsilon=0): x, row[y_pos] = row[y_pos], x return x, y_pos - def _backward_format_output(self, lower_row, upper_row, output, + def _backward_format_output(self, lower_row, upper_row, output, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence @@ -2459,19 +2459,19 @@ def _backward_format_output(self, lower_row, upper_row, output, sage: from sage.combinat.rsk import RuleSuperRSK sage: from sage.combinat.shifted_primed_tableau import PrimedEntry - sage: RuleSuperRSK()._backward_format_output([PrimedEntry('1p'), - ....: PrimedEntry(1), PrimedEntry('3p'), PrimedEntry(9)], - ....: [PrimedEntry(1), PrimedEntry('2p'), PrimedEntry('3p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry('1p'), + ....: PrimedEntry(1), PrimedEntry('3p'), PrimedEntry(9)], + ....: [PrimedEntry(1), PrimedEntry('2p'), PrimedEntry('3p'), ....: PrimedEntry(4)], 'array', False) [[4, 3', 2', 1], [9, 3', 1, 1']] - sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), - ....: PrimedEntry('2p'), PrimedEntry('3p'), PrimedEntry(4)], - ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), + ....: PrimedEntry('2p'), PrimedEntry('3p'), PrimedEntry(4)], + ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), ....: PrimedEntry(2)], 'word', True) word: 4,3',2',1 - sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), - ....: PrimedEntry(2), PrimedEntry(3), PrimedEntry(4)], - ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), + ....: PrimedEntry(2), PrimedEntry(3), PrimedEntry(4)], + ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), ....: PrimedEntry(2)], 'word', True) word: 4321 """ @@ -3062,9 +3062,9 @@ def RSK(obj1=None, obj2=None, insertion=InsertionRules.RSK, check_standard=False - ``RSK.rules.Hecke`` (or ``'hecke'``) -- Hecke insertion (only guaranteed for generalized permutations whose top row is strictly increasing) (:class:`~sage.combinat.rsk.RuleHecke`) - - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion + - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion (only for strict biwords) (:class:`~sage.combinat.rsk.RuleDualRSK`) - - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only + - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only for strict cobiwords) (:class:`~sage.combinat.rsk.RuleCoRSK`) - ``RSK.rules.superRSK`` (or ``'super'``) -- Super RSK insertion (only for restricted super biwords) (:class:`~sage.combinat.rsk.RuleSuperRSK`) @@ -3221,9 +3221,9 @@ def RSK_inverse(p, q, output='array', insertion=InsertionRules.RSK): - ``RSK.rules.Hecke`` (or ``'hecke'``) -- Hecke insertion (only guaranteed for generalized permutations whose top row is strictly increasing) (:class:`~sage.combinat.rsk.RuleHecke`) - - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion + - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion (only for strict biwords) (:class:`~sage.combinat.rsk.RuleDualRSK`) - - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only + - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only for strict cobiwords) (:class:`~sage.combinat.rsk.RuleCoRSK`) - ``RSK.rules.superRSK`` (or ``'super'``) -- Super RSK insertion (only for restricted super biwords) (:class:`~sage.combinat.rsk.RuleSuperRSK`) @@ -3414,4 +3414,3 @@ def to_matrix(t, b): else: entries[pos] = 1 return matrix(entries, sparse=True) - diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index bce78a410a0..169d0f862ef 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -951,7 +951,7 @@ def representation_matrix(self, permutation): """ ret = self._representation_matrix_uncached(permutation) ret.set_immutable() - return ret + return ret def _representation_matrix_uncached(self, permutation): r""" diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 025adfe7d58..b34dad8f9ad 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -475,7 +475,7 @@ class Polyomino(SageObject): - ``coords`` -- iterable of integer coordinates in `\ZZ^d` - ``color`` -- string (default: ``'gray'``), color for display - - ``dimension`` -- integer (default: ``None``), dimension of the space, + - ``dimension`` -- integer (default: ``None``), dimension of the space, if ``None``, it is guessed from the ``coords`` if ``coords`` is non empty From 54cf11fa0f701f76523b1da5bf0e1434d9ab1723 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 12:40:40 +0200 Subject: [PATCH 137/355] Trac #29851: factory class --- .../characteristic_cohomology_class.py | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 68c865f834e..0457d2e6361 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -20,9 +20,10 @@ from .affine_connection import AffineConnection from .bundle_connection import BundleConnection from .levi_civita_connection import LeviCivitaConnection +from sage.rings.rational_field import QQ -class CharacteristicCohomologyClass(IndexedFreeModuleElement): +class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): r""" """ @@ -154,7 +155,7 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): r""" """ - Element = CharacteristicCohomologyClass + Element = CharacteristicCohomologyClassRingElement def __init__(self, base, vbundle): r""" @@ -250,7 +251,7 @@ def multiplicative_sequence(q): # Get the multiplicative sequence in the monomial basis: mon_pol = m._from_dict({p: prod(q[i] for i in p) - for k in range(len(q.degree())) + for k in range(q.degree() + 1) for p in Partitions(k)}) return Sym.e()(mon_pol) @@ -277,11 +278,29 @@ def additive_sequence(q, rk): # Express the additive sequence in the monomial basis, the 0th # order term must be treated separately; here comes ``rk`` into play: m_dict = {Partitions(0)([]): rk * q[0]} - m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree())}) + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree() + 1)}) mon_pol = m._from_dict(m_dict) return Sym.e()(mon_pol) +def CharacteristicCohomologyClass(*args, **kwargs): + r""" + + """ + pass + # name, latex_name = kwargs.get('name'), kwargs.get('latex_name') + # base_ring = kwargs.get('base_ring', QQ) + # class_type = kwargs.get('class_type') + # vbundle = args[0] + # input = args[1] + # R = CharacteristicCohomologyClassRing(base_ring, vbundle) + # w_vec = R._weighted_vectors + # if isinstance(input, Expression): + # + # + # return R(element, name=name, latex_name=latex_name) + + def fast_wedge_power(form, n): r""" Return the wedge product power of `form` using a square-and-wedge From ba71d70d8b94d8e6ffb9d59a5a9969b98d540ab7 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 13:00:29 +0200 Subject: [PATCH 138/355] Trac #29581: turn polynomial into dictionary --- .../characteristic_cohomology_class.py | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 0457d2e6361..a6a0beba7c5 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -287,18 +287,34 @@ def CharacteristicCohomologyClass(*args, **kwargs): r""" """ - pass - # name, latex_name = kwargs.get('name'), kwargs.get('latex_name') - # base_ring = kwargs.get('base_ring', QQ) - # class_type = kwargs.get('class_type') - # vbundle = args[0] - # input = args[1] - # R = CharacteristicCohomologyClassRing(base_ring, vbundle) - # w_vec = R._weighted_vectors - # if isinstance(input, Expression): - # - # - # return R(element, name=name, latex_name=latex_name) + from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') + base_ring = kwargs.get('base_ring', QQ) + class_type = kwargs.get('class_type') + vbundle = args[0] + input = args[1] + R = CharacteristicCohomologyClassRing(base_ring, vbundle) + if is_PolynomialRing(input.parent()): + from sage.misc.misc_c import prod + if class_type is None: + raise AttributeError(f'class_type must be stated since {input} ' + f'is a polynomial') + if class_type == 'additive': + sym = additive_sequence(input) + elif class_type == 'multiplicative': + sym = multiplicative_sequence(input) + + input = {} + zero = [0] * R.__ngens + w_vec = R._weighted_vectors + for p, c in sym: + vec = zero.copy() + for i in p: + vec[i] += 1 + key = w_vec(vec) + input[key] = c + + return R(input, name=name, latex_name=latex_name) def fast_wedge_power(form, n): From d0f14dc7caeb6fb7a225d73939af6f5a95e06ca7 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 16:12:26 +0200 Subject: [PATCH 139/355] Trac #29581: constructor class finished --- .../manifolds/diff_vector_bundle.rst | 2 +- .../characteristic_cohomology_class.py | 206 +++++++++++++++--- 2 files changed, 180 insertions(+), 28 deletions(-) diff --git a/src/doc/en/reference/manifolds/diff_vector_bundle.rst b/src/doc/en/reference/manifolds/diff_vector_bundle.rst index 5cfb22dae90..fdfdf39df61 100644 --- a/src/doc/en/reference/manifolds/diff_vector_bundle.rst +++ b/src/doc/en/reference/manifolds/diff_vector_bundle.rst @@ -8,4 +8,4 @@ Differentiable Vector Bundles sage/manifolds/differentiable/bundle_connection - sage/manifolds/differentiable/characteristic_class + sage/manifolds/differentiable/characteristic_cohomology_class diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index a6a0beba7c5..fed9a6e276d 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -15,7 +15,7 @@ from sage.combinat.free_module import IndexedFreeModuleElement from sage.misc.fast_methods import Singleton from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method +from sage.misc.cachefunc import cached_method, cached_function from sage.misc.abstract_method import abstract_method from .affine_connection import AffineConnection from .bundle_connection import BundleConnection @@ -150,6 +150,27 @@ def representative(self, nab=None): return next(iter(self._mixed_forms.values())) return self.get_form(nab) + def set_name(self, name=None, latex_name=None): + r""" + Set (or change) the text name and LaTeX name of the characteristic + cohomology class. + + INPUT: + + - ``name`` -- (string; default: ``None``) name given to the + characteristic cohomology class + - ``latex_name`` -- (string; default: ``None``) LaTeX symbol to denote + the characteristic cohomology class; if ``None`` while ``name`` is + provided, the LaTeX symbol is set to ``name`` + + """ + if name is not None: + self._name = name + if latex_name is None: + self._latex_name = self._name + if latex_name is not None: + self._latex_name = latex_name + class CharacteristicCohomologyClassRing(FiniteGCAlgebra): r""" @@ -204,7 +225,7 @@ def _element_constructor_(self, x, name=None, latex_name=None): if x in R: one_basis = self.one_basis() d = {one_basis: R(x)} - elif isinstance(x, CharacteristicCohomologyClass): + elif isinstance(x, CharacteristicCohomologyClassRingElement): d = x._monomial_coefficients # x is an element of the basis enumerated set; # This is a very ugly way of testing this @@ -233,10 +254,16 @@ def _repr_(self): # ALGORITHMS # ***************************************************************************** -def multiplicative_sequence(q): +def multiplicative_sequence(q, max_order=None): r""" Turn the polynomial ``q`` into its multiplicative sequence. + INPUT: + + - ``q`` -- polynomial to turn into its multiplicative sequence. + - ``max_order`` -- (default: ``None``) the highest order of the sequence; + if ``None``, the order of ``q`` is assumed. + OUTPUT: - A symmetric polynomial representing the multiplicative sequence. @@ -245,17 +272,20 @@ def multiplicative_sequence(q): from sage.combinat.partition import Partitions from sage.misc.misc_c import prod + if max_order is None: + max_order = q.degree() + R = q.parent().base_ring() Sym = SymmetricFunctions(R) m = Sym.m() # Get the multiplicative sequence in the monomial basis: mon_pol = m._from_dict({p: prod(q[i] for i in p) - for k in range(q.degree() + 1) + for k in range(max_order + 1) for p in Partitions(k)}) return Sym.e()(mon_pol) -def additive_sequence(q, rk): +def additive_sequence(q, rk, max_order=None): r""" Turn the polynomial ``q`` into its additive sequence. @@ -263,6 +293,8 @@ def additive_sequence(q, rk): - ``q`` -- polynomial to turn into its additive sequence. - ``rk`` -- rank of the underlying vector bundle + - ``max_order`` -- (default: ``None``) the highest order of the sequence; + if ``None``, the order of ``q`` is assumed. OUTPUT: @@ -271,50 +303,170 @@ def additive_sequence(q, rk): from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + if max_order is None: + max_order = q.degree() + R = q.parent().base_ring() Sym = SymmetricFunctions(R) m = Sym.m() - # Express the additive sequence in the monomial basis, the 0th + # Express the additive sequence in the monomial basis, the 0-th # order term must be treated separately; here comes ``rk`` into play: m_dict = {Partitions(0)([]): rk * q[0]} - m_dict.update({Partitions(k)([k]): q[k] for k in range(1, q.degree() + 1)}) + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, max_order + 1)}) mon_pol = m._from_dict(m_dict) return Sym.e()(mon_pol) - +@cached_function def CharacteristicCohomologyClass(*args, **kwargs): r""" + Construct a characteristic cohomology class. + + INPUT: + + - ``vbundle`` -- the vector bundle over which the characteristic + cohomology class shall be defined + - ``val`` -- input data; could be a string, polynomial, symbolic + expression or characteristic cohomology class + - ``base_ring`` -- (default: ``QQ``) base ring over which the + characteristic cohomology class ring shall be defined + - ``name`` -- (default: ``None``) string representation given to the + characteristic cohomology class; if ``None`` the default algebra + representation is used + - ``latex_name`` -- (default: ``None``) LaTeX name given to the + characteristic class; if ``None`` the value of ``name`` is used + - ``class_type`` -- (default: ``None``) class type of the characteristic + cohomology class; the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type + - ``'additive'`` -- returns a class of additive type + - ``'Pfaffian'`` -- returns a class of Pfaffian type + + This argument must be stated if ``val`` is a polynomial or symbolic + expression. """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.symbolic.expression import Expression + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') base_ring = kwargs.get('base_ring', QQ) class_type = kwargs.get('class_type') vbundle = args[0] - input = args[1] + val = args[1] # input value R = CharacteristicCohomologyClassRing(base_ring, vbundle) - if is_PolynomialRing(input.parent()): - from sage.misc.misc_c import prod + dim = vbundle._base_space._dim + + # predefined classes accessible via class names + if isinstance(val, str): + from sage.arith.misc import factorial, bernoulli + + P = PolynomialRing(base_ring, 'x') + x = P.gen() + if val == 'Chern': + if vbundle._field_type != 'complex': + raise ValueError(f'total Chern class not defined on {vbundle}') + class_type = 'multiplicative' + val = 1 + x + if val == 'Pontryagin': + if vbundle._field_type != 'real': + raise ValueError(f'total Pontryagin class not defined on {vbundle}') + class_type = 'multiplicative' + val = 1 + x + elif val == 'ChernChar': + if vbundle._field_type != 'complex': + raise ValueError(f'Chern character not defined on {vbundle}') + if name is None: + name = f'ch' + if latex_name is None: + latex_name = r'\mathrm{ch}' + class_type = 'additive' + coeff = [1 / factorial(k) for k in range(dim // 2 + 1)] # exp(x) + val = P(coeff) + elif val == 'Todd': + if vbundle._field_type != 'complex': + raise ValueError(f'Todd class not defined on {vbundle}') + if name is None: + name = f'Td({vbundle._name})' + if latex_name is None: + latex_name = r'\mathrm{Td}' + class_type = 'multiplicative' + val = 1 + x / 2 + for k in range(1, dim // 2 + 1): + val += (-1)**(k+1) / factorial(2*k) * bernoulli(2*k) * x**(2*k) + elif val == 'Hirzebruch': + if vbundle._field_type != 'real': + raise ValueError(f'Hirzebruch class not defined on {vbundle}') + if name is None: + name = f'L' + if latex_name is None: + latex_name = r'\mathrm{L}' + class_type = 'multiplicative' + coeff = [2**(2*k) * bernoulli(2*k) / factorial(2*k) + for k in range(dim // 4 + 1)] + val = P(coeff) + elif val == 'Euler': + if not vbundle._field_type != 'real' or not vbundle.has_orientation(): + raise ValueError(f'Euler class not defined on {vbundle}') + val = x + else: + ValueError(f'predefined class "{val}" unknown') + + # turn symbolic expression into a polynomial via Taylor expansion + if isinstance(val, Expression): + x = val.default_variable() + P = PolynomialRing(base_ring, x) + + if vbundle._field_type == 'real': + pow_range = dim // 4 + elif vbundle._field_type == 'complex': + pow_range = dim // 2 + else: + ValueError(f'field type of {vbundle} must be real or complex') + + val = P(val.taylor(x, 0, pow_range)) + + # turn polynomial into a characteristic cohomology class via sequences + if is_PolynomialRing(val.parent()): if class_type is None: - raise AttributeError(f'class_type must be stated since {input} ' - f'is a polynomial') + raise TypeError(f'class_type must be stated if {val} ' + f'is a polynomial') + max_order = R.ngens() + s = 0 # shift; important in case of Euler class generator + if R._algorithm is PontryaginEulerAlgorithm(): + s = 1 # skip Euler class + max_order -= 1 # ignore Euler class + + d = {} + w_vec = R._weighted_vectors + if class_type == 'additive': - sym = additive_sequence(input) + sym = additive_sequence(val, vbundle._rank, max_order=max_order) elif class_type == 'multiplicative': - sym = multiplicative_sequence(input) - - input = {} - zero = [0] * R.__ngens - w_vec = R._weighted_vectors + sym = multiplicative_sequence(val, max_order=max_order) + elif class_type == 'Pfaffian': + P = val.parent() + x = P.gen() + val = (val(x) + val(-x)) / 2 # project to odd functions + val = P([(-1)**k * val[2*k+1] for k in range(max_order + 1)]) + sym = multiplicative_sequence(val, max_order=max_order) + else: + AttributeError('unkown class type') + for p, c in sym: - vec = zero.copy() + vec = [0] * R.ngens() + if class_type == 'Pfaffian': + vec[0] = 1 # always multiply with e for i in p: - vec[i] += 1 + vec[i - 1 + s] += 1 key = w_vec(vec) - input[key] = c + d[key] = c + res = R._from_dict(d) + res.set_name(name=name, latex_name=latex_name) + return res - return R(input, name=name, latex_name=latex_name) + return R(val, name=name, latex_name=latex_name) def fast_wedge_power(form, n): @@ -418,7 +570,7 @@ def get_local(self, cmat): - a list containing the local characteristic Chern forms - .. ALGORITHM:: + ALGORITHM:: The algorithm is based on the Faddeev-LeVerrier algorithm for the characteristic polynomial. @@ -460,7 +612,7 @@ def get_local(self, cmat): - a list containing the local characteristic Pontryagin forms - .. ALGORITHM:: + ALGORITHM:: The algorithm is based on the Faddeev-LeVerrier algorithm for the characteristic polynomial. @@ -517,7 +669,7 @@ def get(self, nab): 'vector bundles') if rk % 2 != 0: raise ValueError('Euler forms are currently only supported for ' - 'vector bundles with odd rank') + 'vector bundles with even rank') res = dom.diff_form(rk) g = nab._metric for frame in dom._get_min_covering(vbundle.orientation()): @@ -552,7 +704,7 @@ def get_local(self, cmat): The result is the local Euler form if ``cmat`` is given w.r.t. an orthonormal oriented frame. - .. ALGORITHM:: + ALGORITHM:: The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for the Pfaffian. From 4b371bd075fc8c82328cffeff08c7cee91bfa9b5 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 16:56:35 +0200 Subject: [PATCH 140/355] Trac #29581: add AHat class + minor fixes --- .../differentiable/characteristic_cohomology_class.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index fed9a6e276d..6e5488c1897 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -406,9 +406,15 @@ def CharacteristicCohomologyClass(*args, **kwargs): coeff = [2**(2*k) * bernoulli(2*k) / factorial(2*k) for k in range(dim // 4 + 1)] val = P(coeff) + elif val == 'AHat': + class_type = 'multiplicative' + coeff = [- (2**(2*k) - 2) / 2**(2*k) * bernoulli(2*k) / factorial(2*k) + for k in range(dim // 4 + 1)] + val = P(coeff) elif val == 'Euler': - if not vbundle._field_type != 'real' or not vbundle.has_orientation(): + if vbundle._field_type != 'real' or not vbundle.has_orientation(): raise ValueError(f'Euler class not defined on {vbundle}') + class_type = 'Pfaffian' val = x else: ValueError(f'predefined class "{val}" unknown') @@ -448,7 +454,7 @@ def CharacteristicCohomologyClass(*args, **kwargs): elif class_type == 'Pfaffian': P = val.parent() x = P.gen() - val = (val(x) + val(-x)) / 2 # project to odd functions + val = (val(x) - val(-x)) / 2 # project to odd functions val = P([(-1)**k * val[2*k+1] for k in range(max_order + 1)]) sym = multiplicative_sequence(val, max_order=max_order) else: From e82168f67b13aec1f32208eef2a2bf17b7e6fc04 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 17:06:14 +0200 Subject: [PATCH 141/355] Trac #29581: minor improvements --- .../differentiable/characteristic_cohomology_class.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 6e5488c1897..ed307d12818 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -444,9 +444,6 @@ def CharacteristicCohomologyClass(*args, **kwargs): s = 1 # skip Euler class max_order -= 1 # ignore Euler class - d = {} - w_vec = R._weighted_vectors - if class_type == 'additive': sym = additive_sequence(val, vbundle._rank, max_order=max_order) elif class_type == 'multiplicative': @@ -460,6 +457,8 @@ def CharacteristicCohomologyClass(*args, **kwargs): else: AttributeError('unkown class type') + d = {} + w_vec = R._weighted_vectors for p, c in sym: vec = [0] * R.ngens() if class_type == 'Pfaffian': @@ -472,6 +471,7 @@ def CharacteristicCohomologyClass(*args, **kwargs): res.set_name(name=name, latex_name=latex_name) return res + # last resort: try coercion return R(val, name=name, latex_name=latex_name) From 9f53f25b684540bf08e1d64d8a31b9420ebcce25 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 17:11:56 +0200 Subject: [PATCH 142/355] Trac #29581: adapt names --- .../characteristic_cohomology_class.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index ed307d12818..5baae591109 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -378,7 +378,7 @@ def CharacteristicCohomologyClass(*args, **kwargs): if vbundle._field_type != 'complex': raise ValueError(f'Chern character not defined on {vbundle}') if name is None: - name = f'ch' + name = 'ch' if latex_name is None: latex_name = r'\mathrm{ch}' class_type = 'additive' @@ -388,7 +388,7 @@ def CharacteristicCohomologyClass(*args, **kwargs): if vbundle._field_type != 'complex': raise ValueError(f'Todd class not defined on {vbundle}') if name is None: - name = f'Td({vbundle._name})' + name = 'Td' if latex_name is None: latex_name = r'\mathrm{Td}' class_type = 'multiplicative' @@ -399,14 +399,20 @@ def CharacteristicCohomologyClass(*args, **kwargs): if vbundle._field_type != 'real': raise ValueError(f'Hirzebruch class not defined on {vbundle}') if name is None: - name = f'L' + name = 'L' if latex_name is None: - latex_name = r'\mathrm{L}' + latex_name = 'L' class_type = 'multiplicative' coeff = [2**(2*k) * bernoulli(2*k) / factorial(2*k) for k in range(dim // 4 + 1)] val = P(coeff) elif val == 'AHat': + if vbundle._field_type != 'real': + raise ValueError(f'AHat class not defined on {vbundle}') + if name is None: + name = 'A^' + if latex_name is None: + latex_name = r'\hat{A}' class_type = 'multiplicative' coeff = [- (2**(2*k) - 2) / 2**(2*k) * bernoulli(2*k) / factorial(2*k) for k in range(dim // 4 + 1)] From 86b4d28a2aceb68e36b6fed8ca4ee1d8dcbc754c Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 21:17:34 +0200 Subject: [PATCH 143/355] Trac #29581: add coercion and further improvements --- .../characteristic_cohomology_class.py | 36 +++++-- .../differentiable/de_rham_cohomology.py | 24 ++++- .../manifolds/differentiable/vector_bundle.py | 94 +++++++------------ 3 files changed, 84 insertions(+), 70 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 5baae591109..e442f7eb6e5 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -46,11 +46,11 @@ def _repr_(self): """ if self._name is None: - name = super()._repr_() + name = f'({super()._repr_()})' else: name = self._name vbundle = self.parent()._vbundle - name = f'({name})({vbundle._name})' + name = f'{name}({vbundle._name})' return f'Characteristic cohomology class {name} of the {vbundle}' def _latex_(self): @@ -58,12 +58,11 @@ def _latex_(self): """ if self._latex_name is None: - latex = super()._latex_() + latex = r'\left(' + super()._latex_() + r'\right)' else: latex = self._latex_name vbundle = self.parent()._vbundle - latex = r'\left(' + latex + r'\right)\right(' - latex += vbundle._latex_name + r'\right)' + latex += latex + r'\left(' + vbundle._latex_name + r'\right)' return latex def get_form(self, nab): @@ -101,11 +100,11 @@ def get_form(self, nab): if self._name is None: name = f'({super()._repr_()})' else: - name = f'({self._name})' + name = self._name if self._latex_name is None: latex_name = r'\left(' + super()._latex_() + r'\right)' else: - latex_name = r'\left(' + self._latex_name + r'\right)' + latex_name = self._latex_name # appendix append_name = f'({vbundle._name}, {nab._name})' append_latex_name = r'\left(' + vbundle._latex_name @@ -326,8 +325,19 @@ def CharacteristicCohomologyClass(*args, **kwargs): - ``vbundle`` -- the vector bundle over which the characteristic cohomology class shall be defined - - ``val`` -- input data; could be a string, polynomial, symbolic - expression or characteristic cohomology class + - ``val`` -- the input data corresponding to the characteristic class + using the Chern-Weil homomorphism; this argument can be either a + symbolic expression, a polynomial or one of the following predefined + classes: + + - ``'Chern'`` -- total Chern class, + - ``'ChernChar'`` -- Chern character, + - ``'Todd'`` -- Todd class, + - ``'Pontryagin'`` -- total Pontryagin class, + - ``'Hirzebruch'`` -- Hirzebruch class, + - ``'AHat'`` -- `\hat{A}` class, + - ``'Euler'`` -- Euler class. + - ``base_ring`` -- (default: ``QQ``) base ring over which the characteristic cohomology class ring shall be defined - ``name`` -- (default: ``None``) string representation given to the @@ -367,11 +377,15 @@ def CharacteristicCohomologyClass(*args, **kwargs): if val == 'Chern': if vbundle._field_type != 'complex': raise ValueError(f'total Chern class not defined on {vbundle}') + if name is None: + name = 'c' class_type = 'multiplicative' val = 1 + x if val == 'Pontryagin': if vbundle._field_type != 'real': raise ValueError(f'total Pontryagin class not defined on {vbundle}') + if name is None: + name = 'p' class_type = 'multiplicative' val = 1 + x elif val == 'ChernChar': @@ -420,6 +434,8 @@ def CharacteristicCohomologyClass(*args, **kwargs): elif val == 'Euler': if vbundle._field_type != 'real' or not vbundle.has_orientation(): raise ValueError(f'Euler class not defined on {vbundle}') + if name is None: + name = 'e' class_type = 'Pfaffian' val = x else: @@ -635,7 +651,7 @@ def get_local(self, cmat): rk = len(cmat) dim = dom._dim ran = min(rk // 2, dim // 4) - if ran < 2: + if ran < 1: return [] # nothing to compute fac = -1 / (2 * pi) ** 2 res = [] diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index 3f6cc7aa9c0..a29dbedd574 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -51,6 +51,8 @@ from sage.structure.parent import Parent from sage.structure.element import AlgebraElement from sage.categories.algebras import Algebras +from .characteristic_cohomology_class import (CharacteristicCohomologyClassRing, + CharacteristicCohomologyClassRingElement) class DeRhamCohomologyClass(AlgebraElement): r""" @@ -412,13 +414,33 @@ def _element_constructor_(self, x): differentiable manifold M must be a closed form """ - if x not in self._module: + if isinstance(x, CharacteristicCohomologyClassRingElement): + x = x.representative() + elif x not in self._module: raise TypeError(f"{x} must be an element of {self._module}") x = self._module(x) if x.derivative() != 0: raise ValueError(f"{x} must be a closed form") return self.element_class(self, x) + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: C = M.de_rham_complex() + sage: H = C.cohomology() + sage: H.has_coerce_map_from(QQ) + True + + """ + if isinstance(other, CharacteristicCohomologyClassRing): + return other._vbundle._base_space == self._manifold + return super()._coerce_map_from_(other) + def _repr_(self): r""" Return a string representation of the object. diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 709ff479196..ba9d362509b 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -195,45 +195,42 @@ def characteristic_cohomology_class_ring(self, base=QQ): return CharacteristicCohomologyClassRing(base, self) - def characteristic_cohomology_class(self, func, **kwargs): + def characteristic_cohomology_class(self, *args, **kwargs): r""" - Return a characteristic class of the given type with respect to the - given function. + Return a characteristic cohomology class associated with the input + data. INPUT: - - ``func`` -- the function corresponding to the characteristic class - using the Chern-Weil homomorphism; this argument can be either one of - the predefined classes, in the following specified by - (field type, class type, name, LaTeX name, function): - - - ``'Chern'`` -- (complex, multiplicative, ``c``, `c`, `1+x`), - - ``'ChernChar'`` -- (complex, additive, ``ch``, `\mathrm{ch}`, - `\exp(x)`), - - ``'Todd'`` -- (complex, additive, ``Td``, `\mathrm{Td}`, - `\frac{x}{1-\exp(-x)}`), - - ``'Pontryagin'`` -- (real, multiplicative, ``p``, `p`, `1+x`), - - ``'Hirzebruch'`` -- (real, multiplicative, ``L``, `L`, - `\frac{\sqrt{x}}{\tanh(\sqrt{x})}`), - - ``'AHat'`` -- (real, multiplicative, ``A^``, `\hat{A}`, - `\frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}`), - - ``'Euler'`` -- (real, Pfaffian, ``e``, `e`, `x`), - - or a symbolic expression. If ``func`` is one of the predefined classes, - the following arguments are obsolete. - - - ``class_type`` -- (default: ``'multiplicative'``) the type of the - characteristic class; possible values are: - - - ``'multiplicative'`` -- returns a class of multiplicative type, - using the determinant - - ``'additive'`` -- returns a class of additive type, using the trace - - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the - Pfaffian - - - ``name`` -- string representation given to the characteristic class + - ``val`` -- the input data associated with the characteristic class + using the Chern-Weil homomorphism; this argument can be either a + symbolic expression, a polynomial or one of the following predefined + classes: + + - ``'Chern'`` -- total Chern class, + - ``'ChernChar'`` -- Chern character, + - ``'Todd'`` -- Todd class, + - ``'Pontryagin'`` -- total Pontryagin class, + - ``'Hirzebruch'`` -- Hirzebruch class, + - ``'AHat'`` -- `\hat{A}` class, + - ``'Euler'`` -- Euler class. + + - ``base_ring`` -- (default: ``QQ``) base ring over which the + characteristic cohomology class ring shall be defined + - ``name`` -- (default: ``None``) string representation given to the + characteristic cohomology class; if ``None`` the default algebra + representation is used - ``latex_name`` -- (default: ``None``) LaTeX name given to the - characteristic class + characteristic class; if ``None`` the value of ``name`` is used + - ``class_type`` -- (default: ``None``) class type of the characteristic + cohomology class; the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type + - ``'additive'`` -- returns a class of additive type + - ``'Pfaffian'`` -- returns a class of Pfaffian type + + This argument must be stated if ``val`` is a polynomial or symbolic + expression. EXAMPLES: @@ -266,11 +263,8 @@ def characteristic_cohomology_class(self, func, **kwargs): sage: TM = M.tangent_bundle(); TM Tangent bundle TM over the 4-dimensional Lorentzian manifold M sage: p = TM.characteristic_cohomology_class('Pontryagin'); p - Characteristic class p of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 4-dimensional Lorentzian - manifold M - sage: p.function() - x + 1 + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 4-dimensional Lorentzian manifold M sage: p_form = p.get_form(nab); p_form.display_expansion() p(TM, nabla_g) = 1 @@ -280,27 +274,9 @@ def characteristic_cohomology_class(self, func, **kwargs): :class:`~sage.manifolds.differentiable.characteristic_class.CharacteristicClass`. """ - if self._field_type == 'neither_real_nor_complex': - raise ValueError("the vector bundle must be real or complex") - from .characteristic_class import CharacteristicClass, _get_predefined_class - # Is func a predefined class? - if isinstance(func, str): - func_str = func - # Get predefined class: - (field_type, class_type, name, - latex_name, func) = _get_predefined_class(func_str) - # The fields must be equal: - if field_type != self._field_type: - raise ValueError("base field must be {} ".format(field_type) + - "for class '{}'".format(func_str)) - else: - # Get arguments: - class_type = kwargs.pop('class_type', 'multiplicative') - name = kwargs.pop('name', None) - latex_name = kwargs.pop('latex_name', None) + from .characteristic_cohomology_class import CharacteristicCohomologyClass - return CharacteristicClass(self, func, class_type=class_type, - name=name, latex_name=latex_name) + return CharacteristicCohomologyClass(self, *args, **kwargs) characteristic_class = deprecated_function_alias(29581, characteristic_cohomology_class) From f81b25d80d4b0b9c692b25af037f1fe7623e96e8 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 21:21:16 +0200 Subject: [PATCH 144/355] Trac #39581: add example for coercion --- .../manifolds/differentiable/de_rham_cohomology.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index a29dbedd574..d511f44fd5d 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -430,12 +430,23 @@ def _coerce_map_from_(self, other): TESTS:: sage: M = Manifold(2, 'M') - sage: X. = M.chart() sage: C = M.de_rham_complex() sage: H = C.cohomology() sage: H.has_coerce_map_from(QQ) True + :: + + sage: M = Manifold(4, 'M') + sage: C = M.de_rham_complex() + sage: H = C.cohomology() + sage: TM = M.tangent_bundle() + sage: C = TM.characteristic_cohomology_class_ring(); C + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + sage: H.has_coerce_map_from(C) + True + """ if isinstance(other, CharacteristicCohomologyClassRing): return other._vbundle._base_space == self._manifold From 69dd5301343ea310bbdec34b65585a837c18be1b Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 21:23:42 +0200 Subject: [PATCH 145/355] Trac #39581: improve doc --- .../manifolds/differentiable/characteristic_cohomology_class.py | 2 +- src/sage/manifolds/differentiable/vector_bundle.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index e442f7eb6e5..f339067c521 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -342,7 +342,7 @@ def CharacteristicCohomologyClass(*args, **kwargs): characteristic cohomology class ring shall be defined - ``name`` -- (default: ``None``) string representation given to the characteristic cohomology class; if ``None`` the default algebra - representation is used + representation or predefined name is used - ``latex_name`` -- (default: ``None``) LaTeX name given to the characteristic class; if ``None`` the value of ``name`` is used - ``class_type`` -- (default: ``None``) class type of the characteristic diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index ba9d362509b..e0a2f4ee440 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -219,7 +219,7 @@ def characteristic_cohomology_class(self, *args, **kwargs): characteristic cohomology class ring shall be defined - ``name`` -- (default: ``None``) string representation given to the characteristic cohomology class; if ``None`` the default algebra - representation is used + representation or predefined name is used - ``latex_name`` -- (default: ``None``) LaTeX name given to the characteristic class; if ``None`` the value of ``name`` is used - ``class_type`` -- (default: ``None``) class type of the characteristic From 00203e394d5afd7b61802a39dcf6cde13f73efb7 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 5 Sep 2021 21:28:07 +0200 Subject: [PATCH 146/355] Trac #29581: use cup-product for mul_symbol --- .../differentiable/characteristic_cohomology_class.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index f339067c521..6d0a51be774 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -213,7 +213,8 @@ def __init__(self, base, vbundle): names = tuple(names) # hashable degrees = tuple(degrees) # hashable super().__init__(base=base, names=names, degrees=degrees, - max_degree=dim) + max_degree=dim, mul_symbol='⌣', + mul_latex_symbol=r'\smile') def _element_constructor_(self, x, name=None, latex_name=None): r""" From 7555772e7b26039de4796997cd6f812a287ba49e Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 7 Sep 2021 19:38:20 +0200 Subject: [PATCH 147/355] Trac #29581: copy doc from old file + add some doc for CharacteristicCohomologyRing --- .../characteristic_cohomology_class.py | 355 ++++++++++++++++++ 1 file changed, 355 insertions(+) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 6d0a51be774..98bd53f103e 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1,5 +1,272 @@ r""" Characteristic cohomology classes + +A *characteristic class* `\kappa` is a natural transformation that +associates to each vector bundle `E \to M` a cohomology class +`\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M` +from another topological manifold `N`, the *naturality condition* is +satisfied: + +.. MATH:: + + f^*\kappa(E) = \kappa(f^* E) \in H^*(N;R) + +The cohomology class `\kappa(E)` is called *characteristic cohomology class*. +Roughly speaking, characteristic cohomology classes measure the non-triviality +of vector bundles. + +One way to obtain and compute characteristic classes in the de Rham cohomology +with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* +using the curvature of a differentiable vector bundle. + +For that let `\nabla` be a connection on `E`, `e` a local frame on +`E` and `\Omega` be the corresponding curvature matrix +(see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). + +Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant +polynomial, the object + +.. MATH:: + + \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +is well-defined, independent of the choice of `\nabla` (the proof can be +found in [Roe1988]_ pp. 31) and fulfills the naturality condition. +This is the foundation of the Chern-Weil theory and therefore the following +definitions. + +.. NOTE:: + + This documentation is rich of examples, but sparse in explanations. Please + consult the references for more details. + +AUTHORS: + +- Michael Jung (2021) : initial version + +REFERENCES: + +- [Mil1974]_ +- [Roe1988]_ + +Contents +-------- + +We consider the following three types of classes: + +- :ref:`additive` +- :ref:`multiplicative` +- :ref:`Pfaffian` + +.. _additive: + +Additive Classes +---------------- + +In the **complex** case, let `f` be a holomorphic function around zero. Then +we call + +.. MATH:: + + \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *additive characteristic class associated to* `f` of the complex vector +bundle `E`. + +Important and predefined additive classes are: + +- *Chern Character* with `f(x) = \exp(x)` + +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=0`. Then we call + +.. MATH:: + + \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2} + \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *additive characteristic class associated to* `g` of the **real** vector +bundle `E`. + +EXAMPLES: + +Consider the **Chern character** on some 2-dimensional spacetime:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + +Let us define the connection `\nabla^E` in terms of an electro-magnetic +potential `A(t)`:: + + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: nab.set_immutable() + +The Chern character is then given by:: + + sage: ch = E.characteristic_cohomology_class('ChernChar'); ch + Characteristic cohomology class ch(E) of the Differentiable complex vector + bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian + manifold M + +The corresponding characteristic form w.r.t. the bundle connection can be +obtained via :meth:`get_form`. + + sage: ch_form = ch.get_form(nab); ch_form.display_expansion() + ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx + +.. _multiplicative: + +Multiplicative Classes +---------------------- + +In the **complex** case, let `f` be a holomorphic function around zero. +Then we call + +.. MATH:: + + \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative characteristic class associated to* `f` of the complex +vector bundle `E`. + +Important and predefined multiplicative classes on complex vector bundles are: + +- *Chern class* with `f(x) = 1+x` +- *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` + +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=1`. Then we call + +.. MATH:: + + \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) + \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative characteristic class associated to* `g` on the **real** +vector bundle `E`. + +Important and predefined multiplicative classes on real vector bundles are: + +- *Pontryagin class* with `g(x) = 1+x` +- `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}` +- *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}` + +EXAMPLES: + +We consider the **Chern class** of the tautological line bundle `\gamma^1` over +`\CC\mathbf{P}^1`:: + + sage: M = Manifold(2, 'CP^1', start_index=1) + sage: U = M.open_subset('U') + sage: c_cart. = U.chart() # homogeneous coordinates in real terms + sage: c_comp. = U.chart(r'z:z zbar:\bar{z}') # complexification + sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y)) + sage: comp_to_cart = cart_to_comp.inverse() + sage: E = M.vector_bundle(1, 'gamma^1', field='complex') + sage: e = E.local_frame('e', domain=U) + +To apply the Chern-Weil approach, we need a bundle connection in terms of a +connection one form. To achieve this, we take the connection induced from the +hermitian metric on the trivial bundle +`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e` +corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared +is given by `1+|z|^2`:: + + sage: nab = E.bundle_connection('nabla') + sage: omega = U.one_form(name='omega') + sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar) + sage: nab[e, 1, 1] = omega + sage: nab.set_immutable() + +Now, the Chern class can be constructed:: + + sage: c = E.characteristic_cohomology_class('Chern'); c + Characteristic cohomology class c(gamma^1) of the Differentiable complex + vector bundle gamma^1 -> CP^1 of rank 1 over the base space 2-dimensional + differentiable manifold CP^1 + sage: c_form = c.get_form(nab) + sage: c_form.display_expansion(c_comp.frame(), chart=c_comp) + c(gamma^1, nabla) = 1 + 1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz∧dzbar + +Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null +set, it is enough to integrate the top form over the domain `U`:: + + sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), + ....: y, -infinity, infinity) + 1 + +The result shows that `c_1(\gamma^1)` generates the second integer +cohomology of `\CC\mathbf{P}^1`. + +.. _Pfaffian: + +Pfaffian Classes +---------------- + +Usually, there is no such thing as "Pfaffian classes" in literature. However, +using the matrix' Pfaffian and inspired by the aforementioned definitions, +such classes can be defined as follows. + +Let `E` be a real vector bundle of rank `2n` and `f` an odd real function +being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which +certainly will be true if `\nabla` is metric and `e` is orthonormal. Then +we call + +.. MATH:: + + \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right] + \in H^{2n*}(M,\RR) + +the *Pfaffian class associated to f*. + +The most important Pfaffian class is the *Euler class* which is simply given by +`f(x)=x`. + +EXAMPLES: + +We consider the **Euler class** of `S^2`:: + + sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: TM = M.tangent_bundle() + sage: e_class = TM.characteristic_cohomology_class('Euler'); e_class + Characteristic cohomology class e(TS^2) of the Tangent bundle TS^2 over the + 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3 + +To compute a particular representative of the Euler class, we need to determine +a connection, which is in this case given by the standard metric:: + + sage: g = M.metric('g') # standard metric on S2 + sage: nab = g.connection() + sage: nab.set_immutable() + +Now the representative of the Euler class with respect to the connection +`\nabla_g` induced by the standard metric can be computed:: + + sage: e_class_form = e_class.get_form(nab) + sage: e_class_form.display_expansion() + e(TS^2, nabla_g) = 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + +Let us check whether this form represents the Euler class correctly:: + + sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), + ....: y, -infinity, infinity) + 2 + +As we can see, the integral coincides with the Euler characteristic of `S^2` so +that our form actually represents the Euler class appropriately. + """ #****************************************************************************** @@ -173,7 +440,95 @@ def set_name(self, name=None, latex_name=None): class CharacteristicCohomologyClassRing(FiniteGCAlgebra): r""" + Characteristic cohomology class ring. + + Let `E \to M` be a real or complex vector bundle of rank `k` and `R` be a + torsion-free subring of `\CC`. + + Let `BG` be the classifying space of the group `G`. As for vector bundles, + we consider + + - `G = O(k)` if `E` is real, + - `G = SO(k)` if `E` is real and oriented, + - `G = U(k)` if `E` is complex. + + The cohomology ring `H^*(BG; R)` can be explicitly expressed for the + aforementioned cases: + + .. MATH:: + + H^*(BG; R) \cong \begin{cases} + R[c_1, \ldots c_k] & \text{if } G = U(k), \\ + R[p_1, \ldots p_{\lfloor \frac{k}{2}\rfloor}] & \text{if } G = O(k), \\ + R[p_1, \ldots p_k, e] \big/ (p_k^2-e) & \text{if } G = SO(2k), \\ + R[p_1, \ldots p_k, e] & \text{if } G = O(2k+1). \\ + \end{cases} + + The Chern-Weil homomorphism relates the generators in the de Rham cohomology + as follows. For the Chern classes, we have + + .. MATH:: + + \left[ \det\left( 1 + \frac{t \Omega}{2 \pi i} \right) = 1 + + \sum^k_{n=1} c_n(E) t^n, + + for the Pontryagin classes we have + + .. MATH:: + + \left[ \det\left( 1 - \frac{t \Omega}{2 \pi} \right) = 1 + \sum^{ + \lfloor\frac{k}{2} \rfloor}_{n=1} p_n(E) t^n, + + and for the Euler class we obtain + + .. MATH:: + + \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) = e(E). + + Consequently, the cohomology `H^*(BG; R)` can be considered being a + subring of `H_\mathrm{dR}(M, \CC)`. + + INPUT: + - ``base`` -- base ring + - ``vbundle`` -- vector bundle + + EXAMPLES: + + Characteristic cohomology class ring over the tangent bundle of an + 8-dimensional manifold:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring(); CR + Algebra of characteristic cohomology classes of the Tangent bundle TM + over the 8-dimensional differentiable manifold M + sage: CR.gens() + [Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M, + Characteristic cohomology class (p_2)(TM) of the Tangent bundle TM + over the 8-dimensional differentiable manifold M] + + The default base ring is `\QQ`:: + + sage: CR.base_ring() + Rational Field + + Characteristic cohomology class ring over a complex vector bundle:: + + sage: M = Manifold(4, 'M') + sage: E = M.vector_bundle(2, 'E', field='complex') + sage: CR_E = E.characteristic_cohomology_class_ring(); CR_E + Algebra of characteristic cohomology classes of the Differentiable + complex vector bundle E -> M of rank 2 over the base space + 4-dimensional differentiable manifold M + sage: CR_E.gens() + [Characteristic cohomology class (c_1)(E) of the Differentiable complex + vector bundle E -> M of rank 2 over the base space 4-dimensional + differentiable manifold M, + Characteristic cohomology class (c_2)(E) of the Differentiable + complex vector bundle E -> M of rank 2 over the base space + 4-dimensional differentiable manifold M] """ Element = CharacteristicCohomologyClassRingElement From 5f542e15b88799d5e37df351d32a6389e237e913 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 7 Sep 2021 19:47:11 +0200 Subject: [PATCH 148/355] Trac #29581: improve doc CharacteristicCohomologyClassRing --- .../characteristic_cohomology_class.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 98bd53f103e..e1f7dfcd9c5 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -120,7 +120,7 @@ manifold M The corresponding characteristic form w.r.t. the bundle connection can be -obtained via :meth:`get_form`. +obtained via :meth:`get_form`:: sage: ch_form = ch.get_form(nab); ch_form.display_expansion() ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx @@ -461,32 +461,34 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): R[c_1, \ldots c_k] & \text{if } G = U(k), \\ R[p_1, \ldots p_{\lfloor \frac{k}{2}\rfloor}] & \text{if } G = O(k), \\ R[p_1, \ldots p_k, e] \big/ (p_k^2-e) & \text{if } G = SO(2k), \\ - R[p_1, \ldots p_k, e] & \text{if } G = O(2k+1). \\ + R[p_1, \ldots p_k, e] & \text{if } G = SO(2k+1). \\ \end{cases} The Chern-Weil homomorphism relates the generators in the de Rham cohomology - as follows. For the Chern classes, we have + as follows. If `\Omega` is a curvature form matrix on `E`, for the Chern + classes + we get .. MATH:: - \left[ \det\left( 1 + \frac{t \Omega}{2 \pi i} \right) = 1 + + \left[ \det\left( 1 + \frac{t \Omega}{2 \pi i} \right) \right] = 1 + \sum^k_{n=1} c_n(E) t^n, for the Pontryagin classes we have .. MATH:: - \left[ \det\left( 1 - \frac{t \Omega}{2 \pi} \right) = 1 + \sum^{ - \lfloor\frac{k}{2} \rfloor}_{n=1} p_n(E) t^n, + \left[ \det\left( 1 - \frac{t \Omega}{2 \pi} \right) \right] = 1 + + \sum^{\lfloor\frac{k}{2} \rfloor}_{n=1} p_n(E) t^n, and for the Euler class we obtain .. MATH:: - \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) = e(E). + \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) \right] = e(E). - Consequently, the cohomology `H^*(BG; R)` can be considered being a - subring of `H_\mathrm{dR}(M, \CC)`. + Consequently, the cohomology ring `H^*(BG; R)` can be considered being a + subring of `H^*_\mathrm{dR}(M, \CC)`. INPUT: From 0ca6eb9fac729f9cfe68f61a5a41bf8e3d1f6504 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 8 Sep 2021 14:20:09 +0200 Subject: [PATCH 149/355] Trac #29581: add doc to sequences --- .../characteristic_cohomology_class.py | 116 ++++++++++++++---- 1 file changed, 95 insertions(+), 21 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index e1f7dfcd9c5..cd14de47586 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -487,8 +487,10 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) \right] = e(E). - Consequently, the cohomology ring `H^*(BG; R)` can be considered being a - subring of `H^*_\mathrm{dR}(M, \CC)`. + Consequently, the cohomology ring `H^*(BG; R)` is mapped (not + necessarily injectively) to a subring of `H^*_\mathrm{dR}(M, \CC)` via + the Chern-Weil homomorphism. This implementation attempts to represent this + subring. INPUT: @@ -536,7 +538,14 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): def __init__(self, base, vbundle): r""" + Construct a characteristic cohomology ring. + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: TestSuite(CR).run() """ self._vbundle = vbundle self._domain = vbundle._base_space @@ -576,6 +585,10 @@ def __init__(self, base, vbundle): def _element_constructor_(self, x, name=None, latex_name=None): r""" Convert ``x`` into ``self``. + + TESTS:: + + """ R = self.base_ring() @@ -601,7 +614,19 @@ def _element_constructor_(self, x, name=None, latex_name=None): def _repr_(self): r""" - + String representation of the object. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: CR._repr_() + 'Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 8-dimensional differentiable manifold M' + sage: CR # indirect doctest + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 8-dimensional differentiable manifold M """ vbundle = self._vbundle repr = f'Algebra of characteristic cohomology classes of the {vbundle}' @@ -611,26 +636,51 @@ def _repr_(self): # ALGORITHMS # ***************************************************************************** -def multiplicative_sequence(q, max_order=None): +def multiplicative_sequence(q, n=None): r""" Turn the polynomial ``q`` into its multiplicative sequence. + Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The + *multiplicative sequence of* `q` is then given by the polynomials `K_j` + + .. MATH:: + + \sum_{j=0}^n K_j(\sigma_1, \ldots, \sigma_j) z^j = + \prod_{i=1}^{n} q(z \,x_i), + + where `\sigma_i` is the `i`-th elementary symmetric polynomial in the + indeterminates `x_i`. + INPUT: - ``q`` -- polynomial to turn into its multiplicative sequence. - - ``max_order`` -- (default: ``None``) the highest order of the sequence; + - ``n`` -- (default: ``None``) the highest order `n` of the sequence; if ``None``, the order of ``q`` is assumed. OUTPUT: - A symmetric polynomial representing the multiplicative sequence. + + EXAMPLES:: + + sage: P. = PolynomialRing(QQ) + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import multiplicative_sequence + sage: f = 1 + x - x^2 + sage: sym = multiplicative_sequence(f); sym + e[] + e[1] - e[1, 1] + 3*e[2] + + The maximal order of the result can be stated with ``n``:: + + sage: sym_5 = multiplicative_sequence(f, n=5); sym_5 + e[] + e[1] - e[1, 1] + 3*e[2] - e[2, 1] + e[2, 2] + 4*e[3] - 3*e[3, 1] + + e[3, 2] + 7*e[4] - 4*e[4, 1] + 11*e[5] """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions from sage.misc.misc_c import prod - if max_order is None: - max_order = q.degree() + if n is None: + n = q.degree() R = q.parent().base_ring() Sym = SymmetricFunctions(R) @@ -638,30 +688,54 @@ def multiplicative_sequence(q, max_order=None): # Get the multiplicative sequence in the monomial basis: mon_pol = m._from_dict({p: prod(q[i] for i in p) - for k in range(max_order + 1) + for k in range(n + 1) for p in Partitions(k)}) return Sym.e()(mon_pol) -def additive_sequence(q, rk, max_order=None): +def additive_sequence(q, k, n=None): r""" Turn the polynomial ``q`` into its additive sequence. + Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The + *additive sequence of* `q` is then given by the polynomials `Q_j` + + .. MATH:: + + \sum_{j=0}^n Q_j(\sigma_1, \ldots, \sigma_j) z^j = + \sum_{i=1}^{k} q(z \,x_i), + + where `\sigma_i` is the `i`-th elementary symmetric polynomial in the + indeterminates `x_i`. + INPUT: - ``q`` -- polynomial to turn into its additive sequence. - - ``rk`` -- rank of the underlying vector bundle - - ``max_order`` -- (default: ``None``) the highest order of the sequence; + - ``k`` -- maximal index `k` of the sum + - ``n`` -- (default: ``None``) the highest order of the sequence `n`; if ``None``, the order of ``q`` is assumed. OUTPUT: - A symmetric polynomial representing the additive sequence. + + EXAMPLES:: + + sage: P. = PolynomialRing(QQ) + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import additive_sequence + sage: f = 1 + x - x^2 + sage: sym = additive_sequence(f, 2); sym + 2*e[] + e[1] - e[1, 1] + 2*e[2] + + The maximal order of the result can be stated with ``n``:: + + sage: sym_1 = additive_sequence(f, 2, 1); sym_1 + 2*e[] + e[1] """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions - if max_order is None: - max_order = q.degree() + if n is None: + n = q.degree() R = q.parent().base_ring() Sym = SymmetricFunctions(R) @@ -669,8 +743,8 @@ def additive_sequence(q, rk, max_order=None): # Express the additive sequence in the monomial basis, the 0-th # order term must be treated separately; here comes ``rk`` into play: - m_dict = {Partitions(0)([]): rk * q[0]} - m_dict.update({Partitions(k)([k]): q[k] for k in range(1, max_order + 1)}) + m_dict = {Partitions(0)([]): k * q[0]} + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, n + 1)}) mon_pol = m._from_dict(m_dict) return Sym.e()(mon_pol) @@ -818,22 +892,22 @@ def CharacteristicCohomologyClass(*args, **kwargs): if class_type is None: raise TypeError(f'class_type must be stated if {val} ' f'is a polynomial') - max_order = R.ngens() + n = R.ngens() s = 0 # shift; important in case of Euler class generator if R._algorithm is PontryaginEulerAlgorithm(): s = 1 # skip Euler class - max_order -= 1 # ignore Euler class + n -= 1 # ignore Euler class if class_type == 'additive': - sym = additive_sequence(val, vbundle._rank, max_order=max_order) + sym = additive_sequence(val, vbundle._rank, n) elif class_type == 'multiplicative': - sym = multiplicative_sequence(val, max_order=max_order) + sym = multiplicative_sequence(val, n) elif class_type == 'Pfaffian': P = val.parent() x = P.gen() val = (val(x) - val(-x)) / 2 # project to odd functions - val = P([(-1)**k * val[2*k+1] for k in range(max_order + 1)]) - sym = multiplicative_sequence(val, max_order=max_order) + val = P([(-1)**k * val[2*k+1] for k in range(n + 1)]) + sym = multiplicative_sequence(val, n) else: AttributeError('unkown class type') From e7169f81d27242663c168350b203c2d8d51861ef Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 8 Sep 2021 14:46:37 +0200 Subject: [PATCH 150/355] Trac #29581: doc of fast_wedge_power --- .../characteristic_cohomology_class.py | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index cd14de47586..021c6c5ab97 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -756,7 +756,9 @@ def CharacteristicCohomologyClass(*args, **kwargs): INPUT: - ``vbundle`` -- the vector bundle over which the characteristic - cohomology class shall be defined + cohomology class shall be defined; this argument is skipped when invoked + directly from the vector bundle (see + :meth:`sage.manifolds.differentiable.vector_bundle.characteristic_cohomology_class`) - ``val`` -- the input data corresponding to the characteristic class using the Chern-Weil homomorphism; this argument can be either a symbolic expression, a polynomial or one of the following predefined @@ -787,6 +789,33 @@ def CharacteristicCohomologyClass(*args, **kwargs): This argument must be stated if ``val`` is a polynomial or symbolic expression. + EXAMPLES: + + Total Pontryagin class of an 8-dimensional manifold:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over the + 8-dimensional differentiable manifold M + + Define a multiplicative class (see :func:`multiplicative_sequence`):: + + sage: P. = PolynomialRing(QQ) + sage: f = 1 + x - x^2 + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 + p_1 - p_1^2 + 3*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + + Pass a symbolic expression, whose Taylor expansion at zero will be used:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: x = var('x') + sage: f = cos(x) + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 - 1/2*p_1^2 + p_2)(TM) of the Tangent + bundle TM over the 8-dimensional differentiable manifold M """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -933,6 +962,26 @@ def fast_wedge_power(form, n): r""" Return the wedge product power of `form` using a square-and-wedge algorithm. + + INPUT: + + - ``form`` -- a differential form + - ``n`` -- a non-negative integer + + EXAMPLES:: + + sage: M = Manifold(4, 'M') + sage: X. = M.chart() + sage: omega = M.diff_form(2, name='omega') + sage: omega[0,1] = t*y^2 + 2*x + sage: omega[0,3] = z - 2*y + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import fast_wedge_power + sage: fast_wedge_power(omega, 0) + Scalar field 1 on the 4-dimensional differentiable manifold M + sage: fast_wedge_power(omega, 1) + 4-form omega on the 4-dimensional differentiable manifold M + sage: fast_wedge_power(omega, 2) + 4-form omega∧omega on the 4-dimensional differentiable manifold M """ if n == 0: return form._domain._one_scalar_field @@ -940,7 +989,6 @@ def fast_wedge_power(form, n): raise ValueError("'n' must be non-negative") val = form while not (n & 1): - print(n) val = val.wedge(val) n >>= 1 @@ -959,6 +1007,8 @@ def fast_wedge_power(form, n): class Algorithm_generic(SageObject): r""" Algorithm class to compute the characteristic forms of the generators. + + This is an abstract class and only meant for developers. """ @cached_method @@ -971,6 +1021,9 @@ def get(self, nab): - a list containing the generator's global characteristic forms + ALGORITHM: + + """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() From 114b483325526810c504935048e87b1e813985df Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 9 Sep 2021 14:17:11 +0200 Subject: [PATCH 151/355] Trac #29581: add more docstring --- .../characteristic_cohomology_class.py | 208 +++++++++++++++--- 1 file changed, 182 insertions(+), 26 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 021c6c5ab97..c8beb749d7d 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -32,8 +32,7 @@ is well-defined, independent of the choice of `\nabla` (the proof can be found in [Roe1988]_ pp. 31) and fulfills the naturality condition. -This is the foundation of the Chern-Weil theory and therefore the following -definitions. +This is the foundation of the Chern-Weil theory and the following definitions. .. NOTE:: @@ -292,12 +291,19 @@ class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): r""" + Characteristic cohomology class. """ - def __init__(self, parent, x, name=None, latex_name=None): r""" + Construct a characteristic cohomology class. + + TESTS:: + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: TestSuite(p).run() """ self._name = name if latex_name is None: @@ -310,7 +316,30 @@ def __init__(self, parent, x, name=None, latex_name=None): def _repr_(self): r""" + String representation of the object. + + TESTS:: + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p._repr_() + 'Characteristic cohomology class p(TM) of the Tangent bundle TM + over the 8-dimensional differentiable manifold M' + sage: p # indirect doctest + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M + + :: + + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative') + sage: k._repr_() + 'Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M' + sage: k # indirect doctest + Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M """ if self._name is None: name = f'({super()._repr_()})' @@ -322,19 +351,77 @@ def _repr_(self): def _latex_(self): r""" + LaTeX representation of the object. + + TESTS:: + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p._latex_() + 'p\\left(TM\\right)' + sage: latex(p) # indirect doctest + p\left(TM\right) + + :: + + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative') + sage: k._latex_() + '\\left(1 + p_1^{2} - 2p_2\\right)\\left(TM\\right)' + sage: latex(k) + \left(1 + p_1^{2} - 2p_2\right)\left(TM\right) """ if self._latex_name is None: latex = r'\left(' + super()._latex_() + r'\right)' else: latex = self._latex_name vbundle = self.parent()._vbundle - latex += latex + r'\left(' + vbundle._latex_name + r'\right)' + latex += r'\left(' + vbundle._latex_name + r'\right)' return latex def get_form(self, nab): r""" + Return the characteristic form of ``self``. + + INPUT: + + - ``nab`` -- get the characteristic form w.r.t. to the + connection ``nab`` + OUTPUT: + + - an instance of `sage.manifolds.differentiable.mixed_form.MixedForm` + + EXAMPLES: + + Trivial characteristic form on Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: one = TM.characteristic_cohomology_class_ring().one() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: one.get_form(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Pontryagin form on the 4-sphere:: + + sage: M = manifolds.Sphere(4) + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TS^4) of the Tangent bundle TS^4 + over the 4-sphere S^4 of radius 1 smoothly embedded in the + 5-dimensional Euclidean space E^5 + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: p_form = p.get_form(nab); p_form + Mixed differential form p(TS^4, nabla_g) on the 4-sphere S^4 of + radius 1 smoothly embedded in the 5-dimensional Euclidean space E^5 + sage: p_form.display_expansion() + p(TS^4, nabla_g) = 1 """ if nab not in self._mixed_forms: dom = nab._domain @@ -407,8 +494,49 @@ def representative(self, nab=None): - ``nab`` -- (default: ``None``) if stated, return the representative w.r.t. to the connection ``nab``; otherwise an arbitrary already - computed representative will be chosen + computed representative will be chosen. + + OUTPUT: + + - an instance of `sage.manifolds.differentiable.mixed_form.MixedForm` + + EXAMPLES: + + Define the 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: one = TM.characteristic_cohomology_class_ring().one() + No characteristic form has been computed so far, thus we get an error:: + + sage: one.representative() + Traceback (most recent call last): + ... + AttributeError: cannot pick a representative + + Get a characteristic form:: + + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: one.get_form(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Now, the result is cached and `representative` returns a form:: + + sage: one.representative() + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Alternatively, the option ``nab`` can be used to return the + characteristic form w.r.t. a fixed connection:: + + sage: one.representative(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + .. SEEALSO:: + + :meth:`CharacteristicCohomologyClassRingElement.get_form` """ if nab is None: if not self._mixed_forms: @@ -419,7 +547,7 @@ def representative(self, nab=None): def set_name(self, name=None, latex_name=None): r""" Set (or change) the text name and LaTeX name of the characteristic - cohomology class. + class. INPUT: @@ -429,6 +557,21 @@ def set_name(self, name=None, latex_name=None): the characteristic cohomology class; if ``None`` while ``name`` is provided, the LaTeX symbol is set to ``name`` + EXAMPLES:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, + ....: class_type='multiplicative'); k + Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + sage: k.set_name(name='k', latex_name=r'\kappa') + sage: k + Characteristic cohomology class k(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M + sage: latex(k) + \kappa\left(TM\right) """ if name is not None: self._name = name @@ -464,10 +607,9 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): R[p_1, \ldots p_k, e] & \text{if } G = SO(2k+1). \\ \end{cases} - The Chern-Weil homomorphism relates the generators in the de Rham cohomology - as follows. If `\Omega` is a curvature form matrix on `E`, for the Chern - classes - we get + The Chern-Weil homomorphism relates the generators in the de Rham + cohomology as follows. If `\Omega` is a curvature form matrix on `E`, for + the Chern classes we get .. MATH:: @@ -533,6 +675,18 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): Characteristic cohomology class (c_2)(E) of the Differentiable complex vector bundle E -> M of rank 2 over the base space 4-dimensional differentiable manifold M] + + Characteristic cohomology class ring over an oriented manifold:: + + sage: S2 = manifolds.Sphere(2, coordinates='stereographic') + sage: TS2 = S2.tangent_bundle() + sage: S2.has_orientation() + True + sage: CR = TS2.characteristic_cohomology_class_ring() + sage: CR.gens() + [Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 + over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean + space E^3] """ Element = CharacteristicCohomologyClassRingElement @@ -588,7 +742,13 @@ def _element_constructor_(self, x, name=None, latex_name=None): TESTS:: - + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: CR(p, name='pontr') + Characteristic cohomology class pontr(TM) of the Tangent bundle + TM over the 8-dimensional differentiable manifold M """ R = self.base_ring() @@ -753,6 +913,8 @@ def CharacteristicCohomologyClass(*args, **kwargs): r""" Construct a characteristic cohomology class. + The result is cached. + INPUT: - ``vbundle`` -- the vector bundle over which the characteristic @@ -775,8 +937,8 @@ def CharacteristicCohomologyClass(*args, **kwargs): - ``base_ring`` -- (default: ``QQ``) base ring over which the characteristic cohomology class ring shall be defined - ``name`` -- (default: ``None``) string representation given to the - characteristic cohomology class; if ``None`` the default algebra - representation or predefined name is used + characteristic class; if ``None`` the default algebra representation or + predefined name is used - ``latex_name`` -- (default: ``None``) LaTeX name given to the characteristic class; if ``None`` the value of ``name`` is used - ``class_type`` -- (default: ``None``) class type of the characteristic @@ -979,7 +1141,7 @@ def fast_wedge_power(form, n): sage: fast_wedge_power(omega, 0) Scalar field 1 on the 4-dimensional differentiable manifold M sage: fast_wedge_power(omega, 1) - 4-form omega on the 4-dimensional differentiable manifold M + 2-form omega on the 4-dimensional differentiable manifold M sage: fast_wedge_power(omega, 2) 4-form omega∧omega on the 4-dimensional differentiable manifold M """ @@ -1006,24 +1168,20 @@ def fast_wedge_power(form, n): class Algorithm_generic(SageObject): r""" - Algorithm class to compute the characteristic forms of the generators. - - This is an abstract class and only meant for developers. + Abstract algorithm class to compute the characteristic forms of the + generators. """ - @cached_method def get(self, nab): r""" Return the global characteristic forms of the generators w.r.t. a given connection. + The result is cached. + OUTPUT: - a list containing the generator's global characteristic forms - - ALGORITHM: - - """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() @@ -1055,7 +1213,6 @@ def get_local(self, cmat): OUTPUT: - a list containing the generator's local characteristic forms - """ pass @@ -1064,6 +1221,8 @@ def get_gen_pow(self, nab, i, n): r""" Return the `n`-th power of the `i`-th generator's characteristic form w.r.t ``nab``. + + The result is cached. """ if n == 0: return nab._domain._one_scalar_field # no computation necessary @@ -1074,7 +1233,6 @@ class ChernAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Chern forms. """ - def get_local(self, cmat): r""" Return the local Chern forms w.r.t. a given curvature matrix. @@ -1116,7 +1274,6 @@ class PontryaginAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Pontryagin forms. """ - def get_local(self, cmat): r""" Return the local Pontryagin forms w.r.t. a given curvature matrix. @@ -1159,7 +1316,6 @@ class EulerAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Euler forms. """ - @cached_method def get(self, nab): r""" From bafd78dcbb8e5b385051d64cc0a68a2e14908ad6 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 9 Sep 2021 14:48:49 +0200 Subject: [PATCH 152/355] Trac #29581: remove old file + add more doc --- .../differentiable/characteristic_class.py | 962 ------------------ .../characteristic_cohomology_class.py | 44 +- 2 files changed, 37 insertions(+), 969 deletions(-) delete mode 100644 src/sage/manifolds/differentiable/characteristic_class.py diff --git a/src/sage/manifolds/differentiable/characteristic_class.py b/src/sage/manifolds/differentiable/characteristic_class.py deleted file mode 100644 index 547ca44260d..00000000000 --- a/src/sage/manifolds/differentiable/characteristic_class.py +++ /dev/null @@ -1,962 +0,0 @@ -r""" -Characteristic Classes - -A *characteristic class* `\kappa` is a natural transformation that -associates to each vector bundle `E \to M` a cohomology class -`\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M` -from another topological manifold `N`, the *naturality condition* is -satisfied: - -.. MATH:: - - f^*\kappa(E) = \kappa(f^* E) \in H^*(N;R) - -Roughly speaking, characteristic classes measure the non-triviality of -vector bundles. - -One way to obtain and compute characteristic classes in the de Rham cohomology -with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* -using the curvature of a differentiable vector bundle. - -For that let `\nabla` be a connection on `E`, `e` a local frame on -`E` and `\Omega` be the corresponding curvature matrix -(see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). - -Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant -polynomial, the object - -.. MATH:: - - \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -is well-defined, independent of the choice of `\nabla` (the proof can be -found in [Roe1988]_ pp. 31) and fulfills the naturality condition. -This is the foundation of the Chern-Weil theory and therefore the following -definitions. - -.. NOTE:: - - This documentation is rich of examples, but sparse in explanations. Please - consult the references for more details. - -AUTHORS: - -- Michael Jung (2019) : initial version - -REFERENCES: - -- [Mil1974]_ -- [Roe1988]_ - -Contents --------- - -We consider the following three types of classes: - -- :ref:`additive` -- :ref:`multiplicative` -- :ref:`Pfaffian` - -.. _additive: - -Additive Classes ----------------- - -In the **complex** case, let `f` be a holomorphic function around zero. Then -we call - -.. MATH:: - - \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right) - \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -the *additive characteristic class associated to* `f` of the complex vector -bundle `E`. - -Important and predefined additive classes are: - -- *Chern Character* with `f(x) = \exp(x)` - -In the **real** case, let `g` be a holomorphic function around zero with -`g(0)=0`. Then we call - -.. MATH:: - - \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2} - \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC) - -the *additive characteristic class associated to* `g` of the **real** vector -bundle `E`. - -EXAMPLES: - -Consider the **Chern character** on some 2-dimensional spacetime:: - - sage: M = Manifold(2, 'M', structure='Lorentzian') - sage: X. = M.chart() - sage: E = M.vector_bundle(1, 'E', field='complex'); E - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M - sage: e = E.local_frame('e') - -Let us define the connection `\nabla^E` in terms of an electro-magnetic -potential `A(t)`:: - - sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') - sage: omega = M.one_form(name='omega') - sage: A = function('A') - sage: nab.set_connection_form(0, 0)[1] = I*A(t) - sage: nab[0, 0].display() - connection (0,0) of bundle connection nabla^E w.r.t. Local frame - (E|_M, (e_0)) = I*A(t) dx - sage: nab.set_immutable() - -The Chern character is then given by:: - - sage: ch = E.characteristic_class('ChernChar'); ch - Characteristic class ch of additive type associated to e^x on the - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M - -The corresponding characteristic form w.r.t. the bundle connection can be -obtained via :meth:`get_form`. - - sage: ch_form = ch.get_form(nab); ch_form.display_expansion() - ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx - -.. _multiplicative: - -Multiplicative Classes ----------------------- - -In the **complex** case, let `f` be a holomorphic function around zero. -Then we call - -.. MATH:: - - \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right) - \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -the *multiplicative characteristic class associated to* `f` of the complex -vector bundle `E`. - -Important and predefined multiplicative classes on complex vector bundles are: - -- *Chern class* with `f(x) = 1+x` -- *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` - -In the **real** case, let `g` be a holomorphic function around zero with -`g(0)=1`. Then we call - -.. MATH:: - - \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) - \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) - -the *multiplicative characteristic class associated to* `g` on the **real** -vector bundle `E`. - -Important and predefined multiplicative classes on real vector bundles are: - -- *Pontryagin class* with `g(x) = 1+x` -- `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}` -- *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}` - -EXAMPLES: - -We consider the **Chern class** of the tautological line bundle `\gamma^1` over -`\CC\mathbf{P}^1`:: - - sage: M = Manifold(2, 'CP^1', start_index=1) - sage: U = M.open_subset('U') - sage: c_cart. = U.chart() # homogeneous coordinates in real terms - sage: c_comp. = U.chart(r'z:z zbar:\bar{z}') # complexification - sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y)) - sage: comp_to_cart = cart_to_comp.inverse() - sage: E = M.vector_bundle(1, 'gamma^1', field='complex') - sage: e = E.local_frame('e', domain=U) - -To apply the Chern-Weil approach, we need a bundle connection in terms of a -connection one form. To achieve this, we take the connection induced from the -hermitian metric on the trivial bundle -`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e` -corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared -is given by `1+|z|^2`:: - - sage: nab = E.bundle_connection('nabla') - sage: omega = U.one_form(name='omega') - sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar) - sage: nab[e, 1, 1] = omega - sage: nab.set_immutable() - -Now, the Chern class can be constructed:: - - sage: c = E.characteristic_class('Chern'); c - Characteristic class c of multiplicative type associated to x + 1 on the - Differentiable complex vector bundle gamma^1 -> CP^1 of rank 1 over the - base space 2-dimensional differentiable manifold CP^1 - sage: c_form = c.get_form(nab) - sage: c_form.display_expansion(c_comp.frame(), chart=c_comp) - c(gamma^1, nabla) = 1 + 1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz∧dzbar - -Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null -set, it is enough to integrate the top form over the domain `U`:: - - sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), - ....: y, -infinity, infinity) - 1 - -The result shows that `c_1(\gamma^1)` generates the second integer -cohomology of `\CC\mathbf{P}^1`. - -.. _Pfaffian: - -Pfaffian Classes ----------------- - -Usually, there is no such thing as "Pfaffian classes" in literature. However, -using the matrix' Pfaffian and inspired by the aforementioned definitions, -such classes can be defined as follows. - -Let `E` be a real vector bundle of rank `2n` and `f` an odd real function -being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which -certainly will be true if `\nabla` is metric and `e` is orthonormal. Then -we call - -.. MATH:: - - \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right] - \in H^{2n*}(M,\RR) - -the *Pfaffian class associated to f*. - -The most important Pfaffian class is the *Euler class* which is simply given by -`f(x)=x`. - -EXAMPLES: - -We consider the **Euler class** of `S^2`:: - - sage: M = Manifold(2, name='S2', latex_name=r'S^2', start_index=1) - sage: U = M.open_subset('U') ; V = M.open_subset('V') - sage: M.declare_union(U,V) # M is the union of U and V - sage: c_xy. = U.chart() ; c_uv. = V.chart() - sage: xy_to_uv = c_xy.transition_map(c_uv, - ....: (x/(x^2+y^2), y/(x^2+y^2)), - ....: intersection_name='W', - ....: restrictions1= x^2+y^2!=0, - ....: restrictions2= u^2+v^2!=0) - sage: uv_to_xy = xy_to_uv.inverse() - sage: eU = c_xy.frame() ; eV = c_uv.frame() - sage: TM = M.tangent_bundle() - sage: e_class = TM.characteristic_class('Euler'); e_class - Characteristic class e of Pfaffian type associated to x on the Tangent - bundle TS2 over the 2-dimensional differentiable manifold S2 - -To compute a particular representative of the Euler class, we need to determine -a connection:: - - sage: g = M.metric('g') # standard metric on S2 - sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2 - sage: g[eV,1,1], g[eV,2,2] = 4/(1+u^2+v^2)^2, 4/(1+u^2+v^2)^2 - sage: nab = g.connection() - -In case of the Euler class, skew-symmetric curvature matrices are needed -for the Pfaffian. For this, we need to define the curvature matrices by -hand:: - - sage: cmatrix_U = [[nab.curvature_form(i,j,eU) for j in TM.irange()] - ....: for i in TM.irange()] - sage: cmatrix_V = [[nab.curvature_form(i,j,eV) for j in TM.irange()] - ....: for i in TM.irange()] - -Fortunately, both curvature matrices are already skew-symmetric:: - - sage: for i in range(TM.rank()): - ....: for j in range(TM.rank()): - ....: print(cmatrix_U[i][j].display()) - curvature (1,1) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 0 - curvature (1,2) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx∧dy - curvature (2,1) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = -4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx∧dy - curvature (2,2) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 0 - sage: for i in range(TM.rank()): - ....: for j in range(TM.rank()): - ....: print(cmatrix_V[i][j].display()) - curvature (1,1) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 0 - curvature (1,2) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du∧dv - curvature (2,1) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du∧dv - curvature (2,2) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 0 - sage: nab.set_immutable() # make nab immutable - -Now the representative of the Euler class with respect to the connection -`\nabla_g` induced by the standard metric can be computed:: - - sage: cmatrices = {eU: cmatrix_U, eV: cmatrix_V} - sage: e_class_form = e_class.get_form(nab, cmatrices) - sage: e_class_form.display_expansion() - e(TS2, nabla_g) = 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy - -Let us check whether this form represents the Euler class correctly:: - - sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), - ....: y, -infinity, infinity) - 2 - -As we can see, the integral coincides with the Euler characteristic of `S^2` so -that our form actually represents the Euler class appropriately. - -""" - -#****************************************************************************** -# Copyright (C) 2019 Michael Jung -# -# 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. -# https://www.gnu.org/licenses/ -#****************************************************************************** - -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method -from sage.structure.sage_object import SageObject -from sage.symbolic.ring import SR -from sage.rings.rational_field import QQ - -################################################################################ -## Separate functions - -def _get_predefined_class(arg): - r""" - Return the signature of the predefined class given by the string ``arg``. - - The signature is given by a tuple following the syntax - (base field, class type, name, LaTeX name, function). - - Modify this method to add new predefined characteristic classes. - - TESTS:: - - sage: from sage.manifolds.differentiable.characteristic_class import _get_predefined_class - sage: _get_predefined_class('Chern') - ('complex', 'multiplicative', 'c', 'c', x + 1) - sage: _get_predefined_class('Pontryagin') - ('real', 'multiplicative', 'p', 'p', x + 1) - sage: _get_predefined_class('Euler') - ('real', 'Pfaffian', 'e', 'e', x) - - """ - if not isinstance(arg, str): - raise TypeError("argument 'arg' must be string") - # Define variable: - x = SR.symbol('x') - # Define dictionary. The syntax is as follows: - # (field_type, class_type, name, latex_name, func) - if arg == 'ChernChar': - return ('complex', 'additive', 'ch', r'\mathrm{ch}', x.exp()) - elif arg == 'Todd': - return ('complex', 'additive', 'Td', r'\mathrm{Td}', - x / (1 - (-x).exp())) - elif arg == 'Chern': - return ('complex', 'multiplicative', 'c', 'c', 1 + x) - elif arg == 'Pontryagin': - return ('real', 'multiplicative', 'p', 'p', 1 + x) - elif arg == 'AHat': - return ('real', 'multiplicative', 'A^', r'\hat{A}', - x.sqrt() / (2 * (x.sqrt() / 2).sinh())) - elif arg == 'Hirzebruch': - return ('real', 'multiplicative', 'L', 'L', - x.sqrt() / x.sqrt().tanh()) - elif arg == 'Euler': - return ('real', 'Pfaffian', 'e', 'e', x) - else: - raise ValueError("the characteristic class '{}' is ".format(arg) + - "not predefined yet.") - -################################################################################ -## Classes - -class CharacteristicClass(UniqueRepresentation, SageObject): - r""" - An instance of this class represents a characteristic class on some - differentiable vector bundle over the field `\RR` or `\CC`. - - INPUT: - - - vbundle -- vector bundle on which the characteristic class should be - defined - - func -- symbolic expression representing the function to which ``self`` - should be associated to - - class_type -- (default: ``'multiplicative'``) class type of the - characteristic class; at this stage, the following options are possible: - - - ``'multiplicative'`` -- returns a class of multiplicative type, - using the determinant - - ``'additive'`` -- returns a class of additive type, using the trace - - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the - Pfaffian - - - ``name`` -- string representation given to the characteristic class - - ``latex_name`` -- (default: ``None``) LaTeX name given to the - characteristic class - - EXAMPLES: - - Get characteristic classes using predefined ones:: - - sage: M = Manifold(4, 'M') - sage: TM = M.tangent_bundle() - sage: TM.characteristic_class('Pontryagin') - Characteristic class p of multiplicative type associated to x + 1 on the - Tangent bundle TM over the 4-dimensional differentiable manifold M - sage: TM.characteristic_class('Hirzebruch') - Characteristic class L of multiplicative type associated to - sqrt(x)/tanh(sqrt(x)) on the Tangent bundle TM over the 4-dimensional - differentiable manifold M - sage: TM.characteristic_class('AHat') - Characteristic class A^ of multiplicative type associated to - 1/2*sqrt(x)/sinh(1/2*sqrt(x)) on the Tangent bundle TM over the - 4-dimensional differentiable manifold M - - The vector bundle's base field and definition domain of the characteristic - class must fit together, otherwise an error message occurs:: - - sage: TM.characteristic_class('Chern') - Traceback (most recent call last): - ... - ValueError: base field must be complex for class 'Chern' - - If your favourite class is not predefined yet, the associated function can - be put manually:: - - sage: cl = TM.characteristic_class(1+x^2, name='cl'); cl - Characteristic class cl of multiplicative type associated to x^2 + 1 on - the Tangent bundle TM over the 4-dimensional differentiable manifold M - - """ - def __init__(self, vbundle, func, class_type='multiplicative', name=None, - latex_name=None): - r""" - Construct a characteristic class. - - TESTS:: - - sage: M = Manifold(3, 'M') - sage: TM = M.tangent_bundle() - sage: from sage.manifolds.differentiable.characteristic_class import CharacteristicClass - sage: c = CharacteristicClass(TM, 1+x, name='c'); c - Characteristic class c of multiplicative type associated to x + 1 on - the Tangent bundle TM over the 3-dimensional differentiable - manifold M - sage: TestSuite(c).run() - - """ - if vbundle._field_type == 'neither_real_nor_complex': - raise ValueError("the vector bundle must either be real or complex") - if class_type not in ['additive', 'multiplicative', 'Pfaffian']: - raise ValueError("the argument 'class_type' must either be " - "'additive', 'multiplicative' or 'Pfaffian'") - if class_type == 'Pfaffian': - if vbundle._field_type != 'real' or vbundle._rank % 2 != 0: - raise ValueError("Pfaffian classes can only be defined for real" - " vector bundles of even rank") - self._name = name - if latex_name is None: - self._latex_name = name - else: - self._latex_name = latex_name - self._func = func - self._class_type = class_type - self._vbundle = vbundle - self._base_space = vbundle._base_space - self._rank = vbundle._rank - self._coeff_list = self._get_coeff_list() - self._init_derived() - - def _get_coeff_list(self, distinct_real=True): - r""" - Return the list of coefficients of the Taylor expansion at zero of the - function. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: E = M.vector_bundle(1, 'E', field='complex') - sage: c = E.characteristic_class(1+x) - sage: c._get_coeff_list() - [1, 1] - - """ - pow_range = self._base_space._dim // 2 - def_var = self._func.default_variable() - # Use a complex variable without affecting the old one: - with SR.temp_var(domain='complex') as new_var: - if self._vbundle._field_type == 'real' and distinct_real: - if self._class_type == 'additive': - func = self._func.subs({def_var: new_var ** 2}) / 2 - elif self._class_type == 'multiplicative': - # This could case problems in the real domain, where sqrt(x^2) - # is simplified to |x|. However, the variable must be complex - # anyway. - func = self._func.subs({def_var : new_var**2}).sqrt() - elif self._class_type == 'Pfaffian': - # There are no canonical Pfaffian classes, however, consider the - # projection onto the odd part of the function to keep the - # matrices skew: - func = (self._func.subs({def_var: new_var}) - - self._func.subs({def_var: -new_var})) / 2 - else: - func = self._func.subs({def_var: new_var}) - - if self._vbundle._field_type == 'real' and not distinct_real: - pow_range = pow_range // 2 - - return func.taylor(new_var, 0, pow_range).coefficients(sparse=False) - - def _init_derived(self): - r""" - Initialize the derived quantities. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._init_derived() - - """ - self._mixed_forms = {} # dict. of mixed forms corresponding this - # characteristic class - # (key: bundle connection) - - def _del_derived(self): - r""" - Delete the derived quantities. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._del_derived() - - """ - self._mixed_forms.clear() - - def _repr_(self): - r""" - String representation of the object. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x, name='c') - sage: c # indirect doctest - Characteristic class c of multiplicative type associated to x + 1 on - the Tangent bundle TM over the 2-dimensional differentiable - manifold M - sage: repr(c) # indirect doctest - 'Characteristic class c of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 2-dimensional differentiable - manifold M' - sage: c._repr_() - 'Characteristic class c of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 2-dimensional differentiable - manifold M' - - """ - desc = "Characteristic class " - if self._name is not None: - desc += self._name + " " - desc += "of {} type ".format(self._class_type) - desc += "associated to {} on the {}".format(self._func, self._vbundle) - return desc - - def _latex_(self): - r""" - LaTeX representation of the object. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', - ....: name='ch', latex_name=r'\mathrm{ch}') - sage: ch._latex_() - '\\mathrm{ch}(TM)' - - """ - return self._latex_name + "(" + self._vbundle._latex_name + ")" - - def class_type(self): - r""" - Return the class type of ``self``. - - EXAMPLES:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', - ....: name='ch', latex_name=r'\mathrm{ch}') - sage: ch.class_type() - 'additive' - - """ - return self._class_type - - def function(self): - r""" - Return the function corresponding to this characteristic class. - - EXAMPLES:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: e_class = TM.characteristic_class('Euler') - sage: e_class.function() - x - sage: AHat = TM.characteristic_class('AHat') - sage: AHat.function() - 1/2*sqrt(x)/sinh(1/2*sqrt(x)) - sage: c = TM.characteristic_class(1+x, name='c') - sage: c.function() - x + 1 - - """ - return self._func - - @cached_method - def sequence(self, ring=QQ): - r""" - Return the multiplicative/additive sequence (depending on the class - type of ``self``) of ``self.function`` in terms of elementary symmetric - functions `e_i`. - - If `f(x)` is the function with respect to ``self`` then its - multiplicative sequence is given by - - .. MATH:: - - \Pi_{i = 1}^n f(x_i) = \sum^n_{i=0} c_i \, e_i(x_1, \ldots, x_n) - - whereas its additive sequence is given by - - .. MATH:: - - \sum_{i = 1}^n f(x_i) = \sum^n_{i=0} c_i \, e_i(x_1, \ldots, x_n). - - Here, `e_i` denotes the `i`-th elementary symmetric function. - - INPUT: - - - ``ring`` -- (default: ``QQ``) the base ring of the symmetric - function ring; in most cases, one can assume ``QQ`` which is - supposed to work faster, if it doesn't work, try ``SR`` instead. - - OUTPUT: - - - a symmetric function in the elementary symmetric basis represented - by an instance of - :class:`~sage.combinat.sf.elementary.SymmetricFunctionAlgebra_elementary` - - EXAMPLES: - - Consider the multiplicative sequence of the `\hat{A}` class:: - - sage: M = Manifold(8, 'M') - sage: A = M.tangent_bundle().characteristic_class('AHat') - sage: A.sequence() - e[] - 1/24*e[1] + 7/5760*e[1, 1] - 1/1440*e[2] - - This is an element of the symmetric functions over the rational field:: - - sage: A.sequence().parent() - Symmetric Functions over Rational Field in the elementary basis - - To get the sequence as an element of usual polynomial ring, we can do - the following:: - - sage: P = PolynomialRing(QQ, 'e', 3) - sage: poly = P(sum(c * prod(P.gens()[i] for i in p) - ....: for p, c in A.sequence())) - sage: poly - 7/5760*e1^2 - 1/24*e1 - 1/1440*e2 + 1 - - Get an additive sequence:: - - sage: E = M.vector_bundle(2, 'E', field='complex') - sage: ch = E.characteristic_class('ChernChar') - sage: ch.sequence() - 2*e[] + e[1] + 1/2*e[1, 1] + 1/6*e[1, 1, 1] + 1/24*e[1, 1, 1, 1] - - e[2] - 1/2*e[2, 1] - 1/6*e[2, 1, 1] + 1/12*e[2, 2] + 1/2*e[3] - + 1/6*e[3, 1] - 1/6*e[4] - - .. SEEALSO:: - - See :class:`~sage.combinat.sf.elementary.SymmetricFunctionAlgebra_elementary` - for detailed information about elementary symmetric functions. - - """ - if self._class_type == 'Pfaffian': - return NotImplementedError('this functionality is not supported ' - 'for characteristic classes of ' - 'Pfaffian type') - - from sage.combinat.sf.sf import SymmetricFunctions - from sage.misc.misc_c import prod - - Sym = SymmetricFunctions(ring) - - coeff = self._get_coeff_list(distinct_real=False) - from sage.combinat.partition import Partitions - m = Sym.m() - if self._class_type == 'multiplicative': - # Get the multiplicative sequence in the monomial basis: - mon_pol = m._from_dict({p: prod(ring(coeff[i]) for i in p) - for k in range(len(coeff)) - for p in Partitions(k)}) - elif self._class_type == 'additive': - # Express the additive sequence in the monomial basis, the 0th - # order term must be treated separately: - - m_dict = {Partitions(0)([]): self._vbundle._rank * ring(coeff[0])} - m_dict.update({Partitions(k)([k]): ring(coeff[k]) for k in range(1, len(coeff))}) - mon_pol = m._from_dict(m_dict) - # Convert to elementary symmetric polynomials: - return Sym.e()(mon_pol) - - def get_form(self, connection, cmatrices=None): - r""" - Return the form representing ``self`` with respect to the given - connection ``connection``. - - INPUT: - - - ``connection`` -- connection to which the form should be associated to; - this can be either a bundle connection as an instance of - :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` - or, in case of the tensor bundle, an affine connection as an instance - of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` - - ``cmatrices`` -- (default: ``None``) a dictionary of curvature - matrices with local frames as keys and curvature matrices as items; if - ``None``, Sage tries to get the curvature matrices from the connection - - OUTPUT: - - - mixed form as an instance of - :class:`~sage.manifolds.differentiable.mixed_form.MixedForm` - representing the total characteristic class - - .. NOTE:: - - Be aware that depending on the characteristic class and complexity - of the manifold, computation times may vary a lot. In addition, if - not done before, the curvature form is computed from the connection, - here. If this behaviour is not wanted and the curvature form is - already known, please use the argument ``cmatrices``. - - EXAMPLES: - - Again, consider the Chern character on some 2-dimensional spacetime:: - - sage: M = Manifold(2, 'M', structure='Lorentzian') - sage: X. = M.chart() - sage: E = M.vector_bundle(1, 'E', field='complex'); E - Differentiable complex vector bundle E -> M of rank 1 over the base - space 2-dimensional Lorentzian manifold M - sage: e = E.local_frame('e') - - And again, we define the connection `\nabla^E` in terms of an - electro-magnetic potential `A(t)`:: - - sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') - sage: omega = M.one_form(name='omega') - sage: A = function('A') - sage: nab.set_connection_form(0, 0)[1] = I*A(t) - sage: nab.set_immutable() - sage: nab[0, 0].display() - connection (0,0) of bundle connection nabla^E w.r.t. Local frame - (E|_M, (e_0)) = I*A(t) dx - - .. NOTE:: - - The characteristic form is strongly linked to the connection - which is why we must make the connection unchangeable, - i.e. immutable, with the command - :meth:`sage.manifolds.differentiable.bundle_connection.BundleConnection.set_immutable` - before we can use :meth:`get_form`. - - The Chern character is then given by:: - - sage: ch = E.characteristic_class('ChernChar'); ch - Characteristic class ch of additive type associated to e^x on the - Differentiable complex vector bundle E -> M of rank 1 over the base - space 2-dimensional Lorentzian manifold M - - Inserting the connection, the result is a mixed differential form with - a priori non-zero components in even degrees:: - - sage: ch_form = ch.get_form(nab); ch_form - Mixed differential form ch(E, nabla^E) on the 2-dimensional - Lorentzian manifold M - sage: ch_form.display() - ch(E, nabla^E) = ch_0(E, nabla^E) + zero + ch_1(E, nabla^E) - sage: ch_form.display_expansion() - ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx - - Due to long computation times, the form is saved:: - - sage: ch_form is ch.get_form(nab) - True - - """ - from .bundle_connection import BundleConnection - from .affine_connection import AffineConnection - if not isinstance(connection, (AffineConnection, BundleConnection)): - raise TypeError("argument must be an affine connection on the " - "manifold or bundle connection on the vector " - "bundle") - if connection not in self._mixed_forms: - base_space = self._base_space - if cmatrices is None: - if self._class_type == 'Pfaffian': - raise NotImplementedError( - "At this stage, Pfaffian forms cannot be derived from " - "(metric) connections. Please use the argument " - "'cmatrices' to insert a dictionary of skew-symmetric " - "curvature matrices by hand, instead.") - cmatrices = {} - for frame in base_space._get_min_covering(connection._coefficients): - cmatrix = [[connection.curvature_form(i, j, frame) - for j in self._vbundle.irange()] - for i in self._vbundle.irange()] - cmatrices[frame] = cmatrix - # Prepare mixed form: - name, latex_name = self._name, self._latex_name - if name is not None and connection._name is not None: - name += "(" + self._vbundle._name + ", " + connection._name + ")" - if latex_name is not None and connection._latex_name is not None: - latex_name += "(" + self._vbundle._latex_name + ", " + \ - connection._latex_name + ")" - res = base_space.mixed_form(name=name, latex_name=latex_name) - # BEGIN computation: - from sage.matrix.matrix_space import MatrixSpace - for frame, cmatrix in cmatrices.items(): - # Define matrix space: - dom = frame._domain - alg = dom.mixed_form_algebra() - mspace = MatrixSpace(alg, self._rank) - # Insert "normalized" curvature matrix into polynomial: - cmatrix = mspace(cmatrix) # convert curvature matrix - ncmatrix = self._normalize_matrix(cmatrix) - rmatrix = self._insert_in_polynomial(ncmatrix) - # Compute classes: - if self._class_type == 'additive': - rst = rmatrix.trace() # mixed form - elif self._class_type == 'multiplicative': - rst = rmatrix.det() # mixed form - elif self._class_type == 'Pfaffian': - rst = rmatrix.pfaffian() # mixed form - # Set restriction: - res.set_restriction(rst) - # END of computation - # - # Preparation to name each homogeneous component; only even (or in - # the real case, by four divisible) degrees are non-zero: - if self._class_type == 'Pfaffian': - deg_dist = self._rank - elif self._vbundle._field_type == 'real': - deg_dist = 4 - elif self._vbundle._field_type == 'complex': - deg_dist = 2 - else: - # You never know... - deg_dist = 1 - # Now, define the name for each form: - for k in res.irange(): - if k % deg_dist != 0 or (self._class_type == 'Pfaffian' and - k == 0): - res[k] = 0 # this form is zero anyway - else: - # String representation: - if self._name is not None: - name = self._name + "_" + str(k // deg_dist) + \ - "(" + self._vbundle._name - if connection._name is not None: - name += ", " + connection._name - name += ")" - # LaTeX name: - if self._latex_name is not None: - latex_name = self._latex_name + \ - r"_{" + str(k // deg_dist) + r"}" + \ - r"(" + self._vbundle._latex_name - if connection._latex_name is not None: - latex_name += r", " + connection._latex_name - latex_name += r")" - # Set name: - res[k].set_name(name=name, latex_name=latex_name) - # Add the result to the dictionary: - self._mixed_forms[connection] = res - - return self._mixed_forms[connection] - - def _insert_in_polynomial(self, cmatrix): - r""" - Return the matrix after inserting `cmatrix` into the polynomial given by - the taylor expansion of `self._func`. - - TESTS:: - - sage: M = Manifold(4, 'M') - sage: c = M.tangent_bundle().characteristic_class('Pontryagin') - sage: c._insert_in_polynomial(x) - 1/2*x^2 + 1 - - """ - mspace = cmatrix.parent() - # Compute matrix powers: - power_list = [mspace.one()] - for pow in range(len(self._coeff_list) - 1): - power_list.append(cmatrix * power_list[pow]) - # Put things together: - rmatrix = sum(self._coeff_list[k] * power_list[k] - for k in range(len(self._coeff_list))) - - return rmatrix - - def _normalize_matrix(self, cmatrix): - r""" - Return the curvature matrix "normalized" with `i/(2 \pi)` or `1/(2 \pi)` - respectively. - - INPUT: - - - ``cmatrix`` -- curvature matrix - - OUTPUT: - - - ``I/(2*pi)*cmatrix`` - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._normalize_matrix(x) - -1/2*I*x/pi - - """ - from sage.symbolic.constants import pi - fac = 1 / (2 * pi) - if self._class_type != 'Pfaffian': - from sage.libs.pynac.pynac import I - fac = fac / I - return fac * cmatrix diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index c8beb749d7d..0f0cd10b8ff 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -2,7 +2,7 @@ Characteristic cohomology classes A *characteristic class* `\kappa` is a natural transformation that -associates to each vector bundle `E \to M` a cohomology class +associates with each vector bundle `E \to M` a cohomology class `\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M` from another topological manifold `N`, the *naturality condition* is satisfied: @@ -41,7 +41,8 @@ AUTHORS: -- Michael Jung (2021) : initial version +- Michael Jung (2019) : initial version +- Michael Jung (2021) : new algorithm; complete refactoring REFERENCES: @@ -293,6 +294,35 @@ class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): r""" Characteristic cohomology class. + Let `E \to M` be a real/complex vector bundle of rank `k`. A characteristic + cohomology class of `E` is generated by either + + - Chern classes if `E` is complex, + - Pontryagin classes if `E` is real, + - Pontryagin classes and the Euler class if `E` is real and orientable, + + via the Chern-Weil homomorphism. + + For details about the ring structure, see + :class:`CharacteristicCohomologyClassRing`. + + To construct a characteristic cohomology class, please use + :func:`CharacteristicCohomologyClass`. + + EXAMPLES:: + + sage: M = Manifold(12, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: p1, p2, p3 = CR.gens() + sage: p1*p2+p3 + Characteristic cohomology class (p_1⌣p_2 + p_3)(TM) of the Tangent + bundle TM over the 12-dimensional differentiable manifold M + sage: A = TM.characteristic_cohomology_class('AHat'); A + Characteristic cohomology class A^(TM) of the Tangent bundle TM over + the 12-dimensional differentiable manifold M + sage: A == 1 - p1/24 + (7*p1^2-4*p2)/5760 + (44*p1*p2-31*p1^3-16*p3)/967680 + True """ def __init__(self, parent, x, name=None, latex_name=None): r""" @@ -1208,7 +1238,7 @@ def get(self, nab): def get_local(self, cmat): r""" Abstract method to get the local forms of the generators w.r.t. a given - curvature matrix ``cmat``. + curvature form matrix ``cmat``. OUTPUT: @@ -1235,7 +1265,7 @@ class ChernAlgorithm(Singleton, Algorithm_generic): """ def get_local(self, cmat): r""" - Return the local Chern forms w.r.t. a given curvature matrix. + Return the local Chern forms w.r.t. a given curvature form matrix. OUTPUT: @@ -1276,7 +1306,7 @@ class PontryaginAlgorithm(Singleton, Algorithm_generic): """ def get_local(self, cmat): r""" - Return the local Pontryagin forms w.r.t. a given curvature matrix. + Return the local Pontryagin forms w.r.t. a given curvature form matrix. OUTPUT: @@ -1358,7 +1388,7 @@ def get(self, nab): def get_local(self, cmat): r""" - Return the normalized Pfaffian w.r.t. a given curvature matrix. + Return the normalized Pfaffian w.r.t. a given curvature form matrix. The normalization is given by the factor `\left(\frac{1}{2 \pi}\right)^{\frac{k}{2}}`, where `k` is the @@ -1420,7 +1450,7 @@ def get(self, nab): def get_local(self, cmat): r""" Return the local Euler and Pontryagin forms w.r.t. a given curvature - matrix. + form matrix. OUTPUT: From 265f918b8045a6b93142130f9fa4147fc7bd1f4c Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 9 Sep 2021 16:24:16 +0200 Subject: [PATCH 153/355] Trac #29581: fix sign mistake --- .../differentiable/characteristic_cohomology_class.py | 4 ++-- src/sage/manifolds/differentiable/de_rham_cohomology.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 0f0cd10b8ff..bce8f79c26e 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1325,7 +1325,7 @@ def get_local(self, cmat): ran = min(rk // 2, dim // 4) if ran < 1: return [] # nothing to compute - fac = -1 / (2 * pi) ** 2 + fac = 1 / (2 * pi) ** 2 res = [] m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) @@ -1335,7 +1335,7 @@ def get_local(self, cmat): res.append(fac * c) for i in range(rk): m[i][i] += c - fac *= -1 / (2 * pi) ** 2 + fac *= 1 / (2 * pi) ** 2 m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] res.append(-fac * sum(m[i][i] for i in range(rk)) / (2 * ran)) diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index d511f44fd5d..403f9f37f00 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -449,6 +449,7 @@ def _coerce_map_from_(self, other): """ if isinstance(other, CharacteristicCohomologyClassRing): + # TODO: we need to be careful if manifolds have boundary! return other._vbundle._base_space == self._manifold return super()._coerce_map_from_(other) From a3555e13332e0879adae188179120f4311462c6e Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 9 Sep 2021 17:49:31 +0200 Subject: [PATCH 154/355] Trac #29581: more docstring --- .../characteristic_cohomology_class.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index bce8f79c26e..8b48baafaac 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1262,6 +1262,42 @@ def get_gen_pow(self, nab, i, n): class ChernAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Chern forms. + + EXAMPLES: + + Define a complex line bundle over a 2-dimensional manifold:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm + sage: algorithm = ChernAlgorithm() + sage: algorithm.get(nab) + [2-form on the 2-dimensional Lorentzian manifold M] + sage: algorithm.get(nab)[0].display() + 1/2*d(A)/dt/pi dt∧dx + + Check some equalities:: + + sage: cmat = [[nab.curvature_form(0, 0, e)]] + sage: algorithm.get(nab)[0] == algorithm.get_local(cmat)[0] # bundle trivial + True + sage: algorithm.get_gen_pow(nab, 0, 1) == algorithm.get(nab)[0] + True """ def get_local(self, cmat): r""" From 0c385882f58f1e2a0f1ec30823a88feaefd3d124 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 10 Sep 2021 12:05:34 +1000 Subject: [PATCH 155/355] Adding more description to the backward=True example. --- src/sage/graphs/generic_graph.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 75485617d13..6d98c543f5f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -20748,7 +20748,8 @@ def graphviz_string(self, **options): } We test the same graph and ``'dir'`` edge options but with - ``backward=True``:: + ``backward=True``, which reverses the natural direction + each edge wants to be pointing for the layout:: sage: def edge_options(data): ....: u,v,label = data From c3dc88c9d9974339b58f9a983fbd8a53904d9188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Aug 2021 09:52:58 +0200 Subject: [PATCH 156/355] use argparse in sage-runtests --- src/bin/sage-runtests | 172 ++++++++++++++++++------------------ src/sage/doctest/control.py | 2 +- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 16d3295b922..cd08cc8eb32 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -1,11 +1,12 @@ #!/usr/bin/env sage-python -import optparse +import argparse import os import sys # Note: the DOT_SAGE and SAGE_STARTUP_FILE environment variables have already been set by sage-env -DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'),'.sage')) +DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), + '.sage')) SAGE_ROOT = os.environ.get('SAGE_ROOT') # Override to not pick up user configuration, see Trac #20270 @@ -27,36 +28,26 @@ def _get_optional_defaults(): if __name__ == "__main__": - parser = optparse.OptionParser() - - def optional_argument(option, opt_str, value, parser, typ, default_arg): - assert value is None - try: - next_arg = typ(parser.rargs[0]) - except Exception: - next_arg = default_arg - else: - parser.rargs.pop(0) - setattr(parser.values, option.dest, next_arg) - - parser.add_option("-p", "--nthreads", dest="nthreads", default=1, action="callback", - callback=optional_argument, callback_args=(int, 0), nargs=0, - metavar="N", help="tests in parallel using N threads with 0 interpreted as max(2, min(8, cpu_count()))") - parser.add_option("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") - parser.add_option("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") - parser.add_option("--logfile", metavar="FILE", help="log all output to FILE") - - parser.add_option("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") - parser.add_option("-s", "--short", dest="target_walltime", default=None, action="callback", - callback=optional_argument, callback_args=(int, 300), nargs=0, - metavar="SECONDS", help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") - parser.add_option("--warn-long", dest="warn_long", default=None, action="callback", - callback=optional_argument, callback_args=(float, 1.0), nargs=0, - metavar="SECONDS", help="warn if tests take more time than SECONDS") + parser = argparse.ArgumentParser(usage="sage -t [options] filenames") + parser.add_argument("-p", "--nthreads", dest="nthreads", + type=int, nargs='?', const=0, default=1, metavar="N", + help="tests in parallel using N threads with 0 interpreted as max(2, min(8, cpu_count()))") + parser.add_argument("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") + what = parser.add_mutually_exclusive_group() + what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") + parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") + + parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") + parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', + default=None, const=300, metavar="SECONDS", + help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") + parser.add_argument("--warn-long", dest="warn_long", nargs='?', + default=None, const=1.0, metavar="SECONDS", + help="warn if tests take more time than SECONDS") # By default, include all tests marked 'dochtml' -- see # https://trac.sagemath.org/ticket/25345 and # https://trac.sagemath.org/ticket/26110: - parser.add_option("--optional", metavar="PKGS", default=_get_optional_defaults(), + parser.add_argument("--optional", metavar="PKGS", default=_get_optional_defaults(), help='only run tests including one of the "# optional" tags listed in PKGS; ' 'if "sage" is listed, will also run the standard doctests; ' 'if "dochtml" is listed, will also run the tests relying on the HTML documentation; ' @@ -64,75 +55,86 @@ if __name__ == "__main__": 'if "external" is listed, will also run tests for available external software; ' 'if "build" is listed, will also run tests specific to Sage\'s build/packaging system; ' 'if set to "all", then all tests will be run') - parser.add_option("--randorder", type=int, metavar="SEED", help="randomize order of tests") - parser.add_option("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed for fuzzing doctests") - parser.add_option("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") - parser.add_option("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") - parser.add_option("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") - - parser.add_option("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file") - parser.add_option("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception") - parser.add_option("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)") - parser.add_option("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths") - parser.add_option("--verbose", action="store_true", default=False, help="print debugging output during the test") - parser.add_option("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised") - parser.add_option("--only-errors", action="store_true", default=False, help="only output failures, not test successes") - - parser.add_option("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") - parser.add_option("--valgrind", "--memcheck", action="store_true", default=False, - help="run doctests using Valgrind's memcheck tool. The log " - "files are named sage-memcheck.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--massif", action="store_true", default=False, - help="run doctests using Valgrind's massif tool. The log " - "files are named sage-massif.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--cachegrind", action="store_true", default=False, - help="run doctests using Valgrind's cachegrind tool. The log " - "files are named sage-cachegrind.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--omega", action="store_true", default=False, - help="run doctests using Valgrind's omega tool. The log " - "files are named sage-omega.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - - parser.add_option("-f", "--failed", action="store_true", default=False, + parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") + parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed for fuzzing doctests") + parser.add_argument("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") + parser.add_argument("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") + parser.add_argument("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") + + parser.add_argument("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file") + parser.add_argument("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception") + parser.add_argument("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)") + parser.add_argument("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths") + parser.add_argument("--verbose", action="store_true", default=False, help="print debugging output during the test") + parser.add_argument("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised") + parser.add_argument("--only-errors", action="store_true", default=False, help="only output failures, not test successes") + + parser.add_argument("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") + parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, + help="run doctests using Valgrind's memcheck tool. The log " + "files are named sage-memcheck.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--massif", action="store_true", default=False, + help="run doctests using Valgrind's massif tool. The log " + "files are named sage-massif.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--cachegrind", action="store_true", default=False, + help="run doctests using Valgrind's cachegrind tool. The log " + "files are named sage-cachegrind.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--omega", action="store_true", default=False, + help="run doctests using Valgrind's omega tool. The log " + "files are named sage-omega.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + + parser.add_argument("-f", "--failed", action="store_true", default=False, help="doctest only those files that failed in the previous run") - parser.add_option("-n", "--new", action="store_true", default=False, + what.add_argument("-n", "--new", action="store_true", default=False, help="doctest only those files that have been changed in the repository and not yet been committed") - parser.add_option("--show-skipped", "--show_skipped", action="store_true", default=False, + parser.add_argument("--show-skipped", "--show_skipped", action="store_true", default=False, help="print a summary at the end of each file of optional tests that were skipped") - parser.add_option("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), - help="path to a json dictionary for the latest run storing a timing for each file") + parser.add_argument("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), + help="path to a json dictionary for the latest run storing a timing for each file") - def gc_option(option, opt_str, value, parser): - gcopts = dict(DEFAULT=0, ALWAYS=1, NEVER=-1) - try: - arg = gcopts[value.upper()] - except KeyError: - parser.error("unknown value {0}={1}".format(opt_str, value)) - setattr(parser.values, option.dest, arg) + class GCAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + gcopts = dict(DEFAULT=0, ALWAYS=1, NEVER=-1) + new_value = gcopts[values] + setattr(namespace, self.dest, new_value) - parser.add_option("--gc", type="string", action="callback", callback=gc_option, - help="control garbarge collection " - "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") + parser.add_argument("--gc", + choices=["DEFAULT", "ALWAYS", "NEVER"], + default=0, + action=GCAction, + help="control garbarge collection " + "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") # The --serial option is only really for internal use, better not # document it. - parser.add_option("--serial", action="store_true", default=False, help=optparse.SUPPRESS_HELP) + parser.add_argument("--serial", action="store_true", default=False, help=argparse.SUPPRESS) - parser.set_usage("sage -t [options] filenames") + parser.add_argument("filenames", help="file names", nargs='*') - options, args = parser.parse_args() + # custom treatment to separate properly + # one or several file names at the end + new_arguments = [] + flag = False + for arg in sys.argv: + if arg.split('.')[-1] in ['py', 'rst', 'sage'] and not flag: + flag = True + new_arguments.append('--') + new_arguments.append(arg) - if not args and not (options.all or options.new): - parser.print_help() + args = parser.parse_args(new_arguments[1:]) + + if not args.filenames and not (args.all or args.new): + print('either use --new or --all or some filenames') sys.exit(2) # Limit the number of threads to 2 to save system resources. # See Trac #23713, #23892, #30351 - if sys.platform == 'darwin': + if sys.platform == 'darwin': os.environ["OMP_NUM_THREADS"] = "1" else: os.environ["OMP_NUM_THREADS"] = "2" @@ -140,21 +142,19 @@ if __name__ == "__main__": os.environ["SAGE_NUM_THREADS"] = "2" from sage.doctest.control import DocTestController - DC = DocTestController(options, args) + DC = DocTestController(args, args.filenames) err = DC.run() try: exit_code_pytest = 0 import pytest pytest_options = ["--import-mode", "importlib"] - if options.verbose: + if args.verbose: pytest_options.append("-v") exit_code_pytest = pytest.main(pytest_options + args) except ModuleNotFoundError: print("Pytest is not installed, skip checking tests that rely on it.") - - if err == 0: sys.exit(exit_code_pytest) else: diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index afb0d6cbcf1..2df8b0b22ca 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -383,7 +383,7 @@ def __init__(self, options, args): self.files = args if options.logfile: try: - self.logfile = open(options.logfile, 'a') + self.logfile = options.logfile except IOError: print("Unable to open logfile {!r}\nProceeding without logging.".format(options.logfile)) self.logfile = None From dd18675b44c31d387d96caff5646046af9fdde4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 11 Sep 2021 13:18:57 +0200 Subject: [PATCH 157/355] fix --- src/bin/sage-runtests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index cd08cc8eb32..1e4d3520bc4 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -121,7 +121,7 @@ if __name__ == "__main__": new_arguments = [] flag = False for arg in sys.argv: - if arg.split('.')[-1] in ['py', 'rst', 'sage'] and not flag: + if arg.split('.')[-1] in ['py', 'pyx', 'pxi', 'pxd', 'rst', 'sage'] and not flag: flag = True new_arguments.append('--') new_arguments.append(arg) From 939cfd9d21342527dc0442f653dc50791ce73ad8 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sat, 11 Sep 2021 22:11:57 +0200 Subject: [PATCH 158/355] Trac #29581: more doc EulerAlgorithm --- src/doc/en/reference/references/index.rst | 4 + .../characteristic_cohomology_class.py | 175 +++++++++++++++++- 2 files changed, 173 insertions(+), 6 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index c022be01e1e..9f68fa63cbf 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1280,6 +1280,10 @@ REFERENCES: Coinvariants Quasi-Symétriques*, Electronic Journal of Combinatorics Vol 12(1) (2005) N16. +.. [Che1944] \S. Chern, *A simple intrinsic proof of the Gauss-Bonnet formula + for closed Riemannian manifolds*, Ann. of Math. (2) 45 (1944), + 747–752. + .. [CQ2019] \A. Cassella and C. Quadrelli. *Right-angled Artin groups and enhanced Koszul properties*. Preprint, :arxiv:`1907.03824`, (2019). diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 8b48baafaac..ee158b8d3bf 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -421,7 +421,8 @@ def get_form(self, nab): OUTPUT: - - an instance of `sage.manifolds.differentiable.mixed_form.MixedForm` + - an instance of + :class:`sage.manifolds.differentiable.mixed_form.MixedForm` EXAMPLES: @@ -528,7 +529,8 @@ def representative(self, nab=None): OUTPUT: - - an instance of `sage.manifolds.differentiable.mixed_form.MixedForm` + - an instance of + :class:`sage.manifolds.differentiable.mixed_form.MixedForm` EXAMPLES: @@ -1211,7 +1213,13 @@ def get(self, nab): OUTPUT: - - a list containing the generator's global characteristic forms + - a list containing the generator's global characteristic forms as + instances of + :class:`sage.manifolds.differentiable.diff_form.DiffForm` + + EXAMPLES: + + sage: """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() @@ -1243,6 +1251,10 @@ def get_local(self, cmat): OUTPUT: - a list containing the generator's local characteristic forms + + ALGORITHM: + + The inherited class determines the algorithm. """ pass @@ -1305,12 +1317,41 @@ def get_local(self, cmat): OUTPUT: - - a list containing the local characteristic Chern forms + - a list containing the local characteristic Chern forms as + instances of + :class:`sage.manifolds.differentiable.diff_form.DiffForm` ALGORITHM:: The algorithm is based on the Faddeev-LeVerrier algorithm for the characteristic polynomial. + + EXAMPLES: + + Define a complex line bundle over a 2-dimensional manifold:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base + space 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: cmat = [[nab.curvature_form(i, j, e) for j in E.irange()] + ....: for i in E.irange()] + + Import the algorithm and apply ``cmat`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm + sage: algorithm = ChernAlgorithm() + sage: algorithm.get_local(cmat) + [2-form on the 2-dimensional Lorentzian manifold M] """ from sage.symbolic.constants import pi from sage.libs.pynac.pynac import I @@ -1381,6 +1422,57 @@ def get_local(self, cmat): class EulerAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Euler forms. + + EXAMPLES: + + Consider the 2-dimensional Euclidean space:: + + sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: algorithm.get(nab) + [2-form on the 2-sphere S^2 of radius 1 smoothly embedded in the + Euclidean space E^3] + sage: algorithm.get(nab)[0].display() + 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + + Get the local (normalized) Pfaffian w.r.t. spherical coordinates:: + + sage: spher.<ϑ,ϕ> = M.spherical_coordinates() + sage: cmat = [[nab.curvature_form(i, j, spher.frame()) + ....: for j in TM.irange()] + ....: for i in TM.irange()] + sage: [euler_spher] = algorithm.get_local(cmat) + sage: euler_spher.display() + + + Get the local (normalized) Pfaffian w.r.t. stereographic coordinates:: + + sage: stereoN = M.stereographic_coordinates() + sage: cmat = [[nab.curvature_form(i, j, stereoN.frame()) + ....: for j in TM.irange()] + ....: for i in TM.irange()] + sage: [euler_stereo] = algorithm.get_local(cmat) + + sage: euler_stereo.display() + 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + + In general, the result of :meth:`get_local` does not yield the Euler form:: + + sage: W = spher.domain().intersection(stereoN.domain()) + sage: euler_stereo.restrict(W) == euler_spher.restrict(W) # should be False + False + + :: + + """ @cached_method def get(self, nab): @@ -1388,10 +1480,59 @@ def get(self, nab): Return the global characteristic forms of the generators w.r.t. a given connection. + INPUT: + + - a metric connection `\nabla` + OUTPUT: - a list containing the global characteristic Euler form + ALGORITHM: + + Assume that `\nabla` is compatible with the metric `g`, and let + `(s_1, \ldots, s_n)` be any oriented frame. Denote by + `G_s = (g(s_i, s_j))_{ij}` the metric tensor and let + `\Omega_s` be the curvature form matrix of `\nabla` w.r.t. `s`. + Then, we get: + + .. MATH:: + + \left(G_s \cdot \Omega_s \right)_{ij} = g\!\left(R(.,.)s_i, s_j\right), + + where `R` is the Riemannian curvature tensor w.r.t. `\nabla`. + + The characteristic Euler form is now obtained by the expression + + .. MATH:: + + \frac{1}{\sqrt{\left|\det(G_s)\right|}} \ + \mathrm{Pf}\!\left(G_s \cdot \frac{\Omega_s}{2 \pi}\right). + + EXAMPLES: + + Consider the 2-sphere:: + + sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: algorithm.get(nab) + [2-form on the 2-sphere S^2 of radius 1 smoothly embedded in the + Euclidean space E^3] + sage: algorithm.get(nab)[0].display() + 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + + REFERENCES: + + - [Che1944]_ + - [Baer2020]_ """ if not isinstance(nab, LeviCivitaConnection): raise TypeError('Euler forms are currently only supported for ' @@ -1436,13 +1577,35 @@ def get_local(self, cmat): .. NOTE:: - The result is the local Euler form if ``cmat`` is given w.r.t. an - orthonormal oriented frame. + In general, the output does *not* represent the local + characteristic Euler form. The result is only guaranteed to be the + local Euler form if ``cmat`` is given w.r.t. an orthonormal + oriented frame. See :meth:`get` for details. ALGORITHM:: The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for the Pfaffian. + + EXAMPLES: + + Consider the 2-sphere:: + + sage: M.<ϑ,ϕ> = manifolds.Sphere(2) # use spherical coordinates + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select a frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm and apply ``cmat`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: [euler] = algorithm.get_local(cmat) + sage: euler.display() + """ from sage.symbolic.constants import pi From e8d8393314a45980c25d110734a57ac4bda64191 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sat, 11 Sep 2021 22:47:10 +0200 Subject: [PATCH 159/355] Trac #29581: correct doc for EulerAlgorithm --- .../characteristic_cohomology_class.py | 53 +++++-------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index ee158b8d3bf..c04c73baff2 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1427,7 +1427,7 @@ class EulerAlgorithm(Singleton, Algorithm_generic): Consider the 2-dimensional Euclidean space:: - sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: M = manifolds.EuclideanSpace(2) sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() @@ -1438,41 +1438,9 @@ class EulerAlgorithm(Singleton, Algorithm_generic): sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm sage: algorithm = EulerAlgorithm() sage: algorithm.get(nab) - [2-form on the 2-sphere S^2 of radius 1 smoothly embedded in the - Euclidean space E^3] + [2-form on the Euclidean plane E^2] sage: algorithm.get(nab)[0].display() - 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy - - Get the local (normalized) Pfaffian w.r.t. spherical coordinates:: - - sage: spher.<ϑ,ϕ> = M.spherical_coordinates() - sage: cmat = [[nab.curvature_form(i, j, spher.frame()) - ....: for j in TM.irange()] - ....: for i in TM.irange()] - sage: [euler_spher] = algorithm.get_local(cmat) - sage: euler_spher.display() - - - Get the local (normalized) Pfaffian w.r.t. stereographic coordinates:: - - sage: stereoN = M.stereographic_coordinates() - sage: cmat = [[nab.curvature_form(i, j, stereoN.frame()) - ....: for j in TM.irange()] - ....: for i in TM.irange()] - sage: [euler_stereo] = algorithm.get_local(cmat) - - sage: euler_stereo.display() - 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy - - In general, the result of :meth:`get_local` does not yield the Euler form:: - - sage: W = spher.domain().intersection(stereoN.domain()) - sage: euler_stereo.restrict(W) == euler_spher.restrict(W) # should be False - False - - :: - - + 0 """ @cached_method def get(self, nab): @@ -1595,17 +1563,24 @@ def get_local(self, cmat): sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() - sage: e = M.frames()[0] # select a frame + sage: e = M.frames()[0] # select a frame (opposite orientation!) sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] ....: for i in TM.irange()] - Import the algorithm and apply ``cmat`` to it:: + We need some preprocessing because the frame is not orthonormal:: + + sage: gcmat = [[sum(g[[e, i, j]] * nab.curvature_form(j, k, e) + ....: for j in TM.irange()) + ....: for k in TM.irange()] for i in TM.irange()] + + Now, ``gcmat`` is guaranteed to be skew-symmetric and can be applied + to :meth:`get_local`. Then, the result must be normalized:: sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm sage: algorithm = EulerAlgorithm() - sage: [euler] = algorithm.get_local(cmat) + sage: euler = -algorithm.get_local(gcmat)[0] / sqrt(g.det(frame=e)) sage: euler.display() - + 1/2*sin(ϑ)/pi dϑ∧dϕ """ from sage.symbolic.constants import pi From d057ee2d3263e4aca9f4a26a763364a616ed2a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 12 Sep 2021 09:27:14 +0200 Subject: [PATCH 160/355] another try for argparse of runtests --- src/bin/sage-runtests | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 1e4d3520bc4..20a77c65817 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -36,7 +36,7 @@ if __name__ == "__main__": what = parser.add_mutually_exclusive_group() what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") - + parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', default=None, const=300, metavar="SECONDS", @@ -119,14 +119,17 @@ if __name__ == "__main__": # custom treatment to separate properly # one or several file names at the end new_arguments = [] - flag = False - for arg in sys.argv: - if arg.split('.')[-1] in ['py', 'pyx', 'pxi', 'pxd', 'rst', 'sage'] and not flag: - flag = True + need_filenames = True + in_filenames = False + for arg in sys.argv[1:]: + if arg in ['-n', '--new', '-a', '--all']: + need_filenames = False + elif need_filenames and not in_filenames and os.path.exists(arg): + in_filenames = True new_arguments.append('--') new_arguments.append(arg) - args = parser.parse_args(new_arguments[1:]) + args = parser.parse_args(new_arguments) if not args.filenames and not (args.all or args.new): print('either use --new or --all or some filenames') From 15b37cacc178272923528ea816ced3fdf2a49d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 12 Sep 2021 11:56:21 +0200 Subject: [PATCH 161/355] modify global_height for projective points --- .../schemes/projective/projective_point.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index 8e669bb5170..838e782af67 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -41,6 +41,7 @@ from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ from sage.arith.all import gcd, lcm +from sage.misc.misc_c import prod from copy import copy from sage.schemes.generic.morphism import (SchemeMorphism, @@ -658,7 +659,7 @@ def dehomogenize(self,n): def global_height(self, prec=None): r""" - Returns the absolute logarithmic height of the point. + Return the absolute logarithmic height of the point. INPUT: @@ -674,14 +675,14 @@ def global_height(self, prec=None): sage: P. = ProjectiveSpace(QQ,2) sage: Q = P.point([4, 4, 1/30]) sage: Q.global_height() - 4.78749174278205 + log(120) :: sage: P. = ProjectiveSpace(ZZ,2) sage: Q = P([4, 1, 30]) sage: Q.global_height() - 3.40119738166216 + log(30) :: @@ -706,6 +707,8 @@ def global_height(self, prec=None): sage: Q.global_height() 1.38629436111989 """ + if prec is None: + prec = 53 K = self.codomain().base_ring() if K in _NumberFields or is_NumberFieldOrder(K): P = self @@ -714,7 +717,21 @@ def global_height(self, prec=None): P = self._number_field_from_algebraics() except TypeError: raise TypeError("must be defined over an algebraic field") - return max([P[i].global_height(prec=prec) for i in range(self.codomain().ambient_space().dimension_relative()+1)]) + else: + K = P.codomain().base_ring() + # first get rid of the denominators + denom = lcm([xi.denominator() for xi in P]) + x = [xi * denom for xi in P] + d = K.degree() + if d == 1: + height = max(abs(xi) for xi in x) / gcd(x) + return height.log() + + finite = ~sum(K.ideal(xi) for xi in x).norm() + infinite = prod(max(abs(xi.complex_embedding(prec, i)) + for xi in x) for i in range(d)) + height = (finite * infinite)**(~d) + return height.log() def local_height(self, v, prec=None): r""" From 974c3cc866d51d884de7b666335a8c5d36517666 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 12 Sep 2021 12:23:06 +0200 Subject: [PATCH 162/355] Trac #29851: finish doc so far --- .../characteristic_cohomology_class.py | 192 +++++++++++++++++- 1 file changed, 187 insertions(+), 5 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index c04c73baff2..c2245e50dcf 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1202,6 +1202,19 @@ class Algorithm_generic(SageObject): r""" Abstract algorithm class to compute the characteristic forms of the generators. + + EXAMPLES:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import Algorithm_generic + sage: algorithm = Algorithm_generic() + sage: algorithm.get + Cached version of + sage: algorithm.get_local + Traceback (most recent call last): + ... + NotImplementedError: + sage: algorithm.get_gen_pow + Cached version of """ @cached_method def get(self, nab): @@ -1217,9 +1230,22 @@ def get(self, nab): instances of :class:`sage.manifolds.differentiable.diff_form.DiffForm` - EXAMPLES: + EXAMPLES:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() - sage: + :: + + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p_form = p.get_form(nab); p_form + Mixed differential form p(TE^4, nabla_g) on the 4-dimensional + Euclidean space E^4 + sage: p_form.display_expansion() + p(TE^4, nabla_g) = 1 """ if isinstance(nab, AffineConnection): vbundle = nab._domain.tangent_bundle() @@ -1255,6 +1281,26 @@ def get_local(self, cmat): ALGORITHM: The inherited class determines the algorithm. + + EXAMPLES:: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get_local(cmat) + sage: p1.display() + 0 """ pass @@ -1265,6 +1311,23 @@ def get_gen_pow(self, nab, i, n): w.r.t ``nab``. The result is cached. + + EXAMPLES:: + + sage: M = manifolds.EuclideanSpace(8) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + :: + + sage: A = TM.characteristic_cohomology_class('AHat') + sage: A_form = A.get_form(nab); A_form + Mixed differential form A^(TE^8, nabla_g) on the 8-dimensional + Euclidean space E^8 + sage: A_form.display_expansion() + A^(TE^8, nabla_g) = 1 """ if n == 0: return nab._domain._one_scalar_field # no computation necessary @@ -1380,6 +1443,23 @@ def get_local(self, cmat): class PontryaginAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Pontryagin forms. + + EXAMPLES: + + 5-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(5) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get(nab) + sage: p1.display() + 0 """ def get_local(self, cmat): r""" @@ -1393,6 +1473,26 @@ def get_local(self, cmat): The algorithm is based on the Faddeev-LeVerrier algorithm for the characteristic polynomial. + + EXAMPLES: + + 5-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(5) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get_local(cmat) + sage: p1.display() + 0 """ from sage.symbolic.constants import pi @@ -1428,7 +1528,6 @@ class EulerAlgorithm(Singleton, Algorithm_generic): Consider the 2-dimensional Euclidean space:: sage: M = manifolds.EuclideanSpace(2) - sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() sage: nab.set_immutable() @@ -1482,7 +1581,6 @@ def get(self, nab): Consider the 2-sphere:: sage: M. = manifolds.Sphere(2, coordinates='stereographic') - sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() sage: nab.set_immutable() @@ -1563,7 +1661,7 @@ def get_local(self, cmat): sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() - sage: e = M.frames()[0] # select a frame (opposite orientation!) + sage: e = M.frames()[0] # select frame (opposite orientation!) sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] ....: for i in TM.irange()] @@ -1605,6 +1703,25 @@ def get_local(self, cmat): class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): r""" Algorithm class to generate Euler and Pontryagin forms. + + EXAMPLES: + + 6-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(6) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e, p1 = algorithm.get(nab) + sage: e.display() + 0 + sage: p1.display() + 0 """ @cached_method @@ -1618,6 +1735,22 @@ def get(self, nab): - a list containing the global Euler form in the first entry, and the global Pontryagin forms in the remaining entries. + EXAMPLES: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: algorithm.get(nab) + [4-form on the 4-dimensional Euclidean space E^4, + 4-form on the 4-dimensional Euclidean space E^4] """ return EulerAlgorithm().get(nab) + PontryaginAlgorithm().get(nab) @@ -1626,11 +1759,39 @@ def get_local(self, cmat): Return the local Euler and Pontryagin forms w.r.t. a given curvature form matrix. + .. NOTE:: + + Similar as for :class:`EulerAlgorithm`, the first entry only + represents the Euler form if the curvature form matrix is chosen + w.r.t. an orthonormal oriented frame. See + :meth:`EulerAlgorithm.get_local` for details. + OUTPUT: - a list containing the local Euler form in the first entry, and the local Pontryagin forms in the remaining entries. + EXAMPLES: + + 6-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(6) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select the standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e, p1 = algorithm.get_local(cmat) + sage: e.display() + 0 + sage: p1.display() + 0 """ res = EulerAlgorithm().get_local(cmat) # first entry is Euler class res += PontryaginAlgorithm().get_local(cmat) # rest Pontryagin @@ -1640,6 +1801,27 @@ def get_local(self, cmat): def get_gen_pow(self, nab, i, n): r""" Return the `n`-th power of the `i`-th generator w.r.t ``nab``. + + The result is cached. + + EXAMPLES: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(8) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e = algorithm.get_gen_pow(nab, 0, 1) # Euler + sage: p1_pow2 = algorithm.get_gen_pow(nab, 1, 2) # 1st Pontryagin + sage: p1_pow2 == e + True """ if n == 0: return nab._domain._one_scalar_field # no computation necessary From 5830550c072e7ba16215dfe80e3985cee9e7d320 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 12 Sep 2021 21:59:51 +0200 Subject: [PATCH 163/355] Trac #29581: fix :: mistake and add Singleton example --- .../differentiable/characteristic_cohomology_class.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index c2245e50dcf..a3382c791c8 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1282,7 +1282,7 @@ def get_local(self, cmat): The inherited class determines the algorithm. - EXAMPLES:: + EXAMPLES: 4-dimensional Euclidean space:: @@ -1301,6 +1301,12 @@ def get_local(self, cmat): sage: [p1] = algorithm.get_local(cmat) sage: p1.display() 0 + + A concrete implementation is given by a + :class:`sage.misc.fast_methods.Singleton`:: + + sage: algorithm is PontryaginAlgorithm() + True """ pass From c9227e36c8aff0e7b693d3c9e959e12f9464d550 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 13 Sep 2021 14:45:47 +1000 Subject: [PATCH 164/355] Full doctest coverage and last bits from move. --- src/sage/rings/function_field/maps.py | 2 +- src/sage/rings/lazy_series_ring.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index 702c4768745..4db242f7673 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -1777,7 +1777,7 @@ def __init__(self, field, place, name=None, prec=None, gen_name=None): self._gen_name = gen_name if prec == infinity: - from sage.rings.lazy_laurent_series_ring import LazyLaurentSeriesRing + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing codomain = LazyLaurentSeriesRing(k, name) self._precision = infinity else: # prec < infinity: diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index aeb5d156874..2cf7db18930 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1047,9 +1047,19 @@ def _coerce_map_from_(self, S): return False def _coerce_map_from_base_ring(self): - """ + r""" Return a coercion map from the base ring of ``self``. + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=2) + 2/2^z + sage: phi(2, valuation=2, constant=4) + 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) """ # Return a DefaultConvertMap_unique; this can pass additional # arguments to _element_constructor_, unlike the map returned From 9a73cad1f5c1504b62c1890b28cc12c753cf9b23 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 13 Sep 2021 14:26:48 +0200 Subject: [PATCH 165/355] Trac #29581: correct ideal in doc + add long time tags for 30s or more --- .../characteristic_cohomology_class.py | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index a3382c791c8..cfc4fa55f9c 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -635,7 +635,7 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): H^*(BG; R) \cong \begin{cases} R[c_1, \ldots c_k] & \text{if } G = U(k), \\ R[p_1, \ldots p_{\lfloor \frac{k}{2}\rfloor}] & \text{if } G = O(k), \\ - R[p_1, \ldots p_k, e] \big/ (p_k^2-e) & \text{if } G = SO(2k), \\ + R[p_1, \ldots p_k, e] \big/ (p_k-e^2) & \text{if } G = SO(2k), \\ R[p_1, \ldots p_k, e] & \text{if } G = SO(2k+1). \\ \end{cases} @@ -666,6 +666,13 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): the Chern-Weil homomorphism. This implementation attempts to represent this subring. + .. NOTE:: + + Some generators might have torsion in `H^*(BG; R)` giving a zero + element in the de Rham cohomology. Those generators are still + considered in the implementation. Generators whose degree exceed the + dimension of the base space, however, are ignored. + INPUT: - ``base`` -- base ring @@ -1329,10 +1336,10 @@ def get_gen_pow(self, nab, i, n): :: sage: A = TM.characteristic_cohomology_class('AHat') - sage: A_form = A.get_form(nab); A_form + sage: A_form = A.get_form(nab); A_form # long time Mixed differential form A^(TE^8, nabla_g) on the 8-dimensional Euclidean space E^8 - sage: A_form.display_expansion() + sage: A_form.display_expansion() # long time A^(TE^8, nabla_g) = 1 """ if n == 0: @@ -1723,10 +1730,10 @@ class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm sage: algorithm = PontryaginEulerAlgorithm() - sage: e, p1 = algorithm.get(nab) - sage: e.display() + sage: e_form, p1_form = algorithm.get(nab) # long time + sage: e_form.display() # long time 0 - sage: p1.display() + sage: p1_form.display() # long time 0 """ @@ -1787,16 +1794,16 @@ def get_local(self, cmat): sage: nab = g.connection() sage: e = M.frames()[0] # select the standard frame sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] - ....: for i in TM.irange()] + ....: for i in TM.irange()] # long time Import the algorithm:: sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm sage: algorithm = PontryaginEulerAlgorithm() - sage: e, p1 = algorithm.get_local(cmat) - sage: e.display() + sage: e, p1 = algorithm.get_local(cmat) # long time + sage: e.display() # long time 0 - sage: p1.display() + sage: p1.display() # long time 0 """ res = EulerAlgorithm().get_local(cmat) # first entry is Euler class @@ -1814,7 +1821,7 @@ def get_gen_pow(self, nab, i, n): 4-dimensional Euclidean space:: - sage: M = manifolds.EuclideanSpace(8) + sage: M = manifolds.EuclideanSpace(4) sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() @@ -1825,9 +1832,11 @@ def get_gen_pow(self, nab, i, n): sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm sage: algorithm = PontryaginEulerAlgorithm() sage: e = algorithm.get_gen_pow(nab, 0, 1) # Euler - sage: p1_pow2 = algorithm.get_gen_pow(nab, 1, 2) # 1st Pontryagin - sage: p1_pow2 == e - True + sage: e.display() + 0 + sage: p1_pow2 = algorithm.get_gen_pow(nab, 1, 2) # 1st Pontryagin squared + sage: p1_pow2 + 8-form zero on the 4-dimensional Euclidean space E^4 """ if n == 0: return nab._domain._one_scalar_field # no computation necessary From 4c1bc44977bbf506a415c9635bf884ae0519e229 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 13 Sep 2021 19:14:13 +0200 Subject: [PATCH 166/355] Trac #29581: remove f-string without placeholder --- .../manifolds/differentiable/characteristic_cohomology_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index cfc4fa55f9c..0459b64732a 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -767,7 +767,7 @@ def __init__(self, base, vbundle): f'field type {vbundle._field_type}') if not names or not degrees: - raise ValueError(f'cannot find any generators') + raise ValueError('cannot find any generators') names = tuple(names) # hashable degrees = tuple(degrees) # hashable From a3d08b4497b143a938e285e18f0fa4f64325a2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 22 Mar 2021 22:23:07 +0100 Subject: [PATCH 167/355] 31161: Add qhull distro info --- build/pkgs/qhull/distros/arch.txt | 1 + build/pkgs/qhull/distros/cygwin.txt | 1 + build/pkgs/qhull/distros/debian.txt | 1 + build/pkgs/qhull/distros/fedora.txt | 1 + build/pkgs/qhull/distros/freebsd.txt | 1 + build/pkgs/qhull/distros/gentoo.txt | 1 + build/pkgs/qhull/distros/nix.txt | 1 + build/pkgs/qhull/distros/void.txt | 1 + 8 files changed, 8 insertions(+) create mode 100644 build/pkgs/qhull/distros/arch.txt create mode 100644 build/pkgs/qhull/distros/cygwin.txt create mode 100644 build/pkgs/qhull/distros/debian.txt create mode 100644 build/pkgs/qhull/distros/fedora.txt create mode 100644 build/pkgs/qhull/distros/freebsd.txt create mode 100644 build/pkgs/qhull/distros/gentoo.txt create mode 100644 build/pkgs/qhull/distros/nix.txt create mode 100644 build/pkgs/qhull/distros/void.txt diff --git a/build/pkgs/qhull/distros/arch.txt b/build/pkgs/qhull/distros/arch.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/arch.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/cygwin.txt b/build/pkgs/qhull/distros/cygwin.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/cygwin.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/debian.txt b/build/pkgs/qhull/distros/debian.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/debian.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/fedora.txt b/build/pkgs/qhull/distros/fedora.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/fedora.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/freebsd.txt b/build/pkgs/qhull/distros/freebsd.txt new file mode 100644 index 00000000000..1f24ee3c6e7 --- /dev/null +++ b/build/pkgs/qhull/distros/freebsd.txt @@ -0,0 +1 @@ +math/qhull diff --git a/build/pkgs/qhull/distros/gentoo.txt b/build/pkgs/qhull/distros/gentoo.txt new file mode 100644 index 00000000000..a7c7a4e1261 --- /dev/null +++ b/build/pkgs/qhull/distros/gentoo.txt @@ -0,0 +1 @@ +media-libs/qhull diff --git a/build/pkgs/qhull/distros/nix.txt b/build/pkgs/qhull/distros/nix.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/nix.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/void.txt b/build/pkgs/qhull/distros/void.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/void.txt @@ -0,0 +1 @@ +qhull From 8e99f5ed7634c3a262d544712de8849fb8c70f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 22 Mar 2021 22:23:56 +0100 Subject: [PATCH 168/355] 31161: Upgrade: qhull 2020-src-8.0.2 --- build/pkgs/qhull/SPKG.rst | 2 ++ build/pkgs/qhull/checksums.ini | 7 +++-- build/pkgs/qhull/package-version.txt | 2 +- build/pkgs/qhull/patches/Makefile.patch | 40 ------------------------- 4 files changed, 7 insertions(+), 44 deletions(-) delete mode 100644 build/pkgs/qhull/patches/Makefile.patch diff --git a/build/pkgs/qhull/SPKG.rst b/build/pkgs/qhull/SPKG.rst index 285c1ef1a1b..069a6808b21 100644 --- a/build/pkgs/qhull/SPKG.rst +++ b/build/pkgs/qhull/SPKG.rst @@ -33,6 +33,8 @@ http://pythonhosted.org/pyhull/). Upstream Contact ---------------- +http://www.qhull.org/html + C. Bradford Barber bradb@shore.net or qhull@qhull.org Dependencies diff --git a/build/pkgs/qhull/checksums.ini b/build/pkgs/qhull/checksums.ini index e8d02d0cf6e..65635055fa6 100644 --- a/build/pkgs/qhull/checksums.ini +++ b/build/pkgs/qhull/checksums.ini @@ -1,4 +1,5 @@ tarball=qhull-VERSION.tgz -sha1=8188765b9f9f004e38e9906fd2a68e81119f05fb -md5=e6270733a826a6a7c32b796e005ec3dc -cksum=2560098443 +sha1=2dbc240919560ac008a92363984754a70677b353 +md5=295f7332269a38279478f555cc185296 +cksum=3092762704 +upstream_url=http://www.qhull.org/download/qhull-VERSION.tgz diff --git a/build/pkgs/qhull/package-version.txt b/build/pkgs/qhull/package-version.txt index f3d5a78f033..26328103545 100644 --- a/build/pkgs/qhull/package-version.txt +++ b/build/pkgs/qhull/package-version.txt @@ -1 +1 @@ -2015-src-7.2.0.p1 +2020-src-8.0.2 diff --git a/build/pkgs/qhull/patches/Makefile.patch b/build/pkgs/qhull/patches/Makefile.patch deleted file mode 100644 index c4255d319c9..00000000000 --- a/build/pkgs/qhull/patches/Makefile.patch +++ /dev/null @@ -1,40 +0,0 @@ -* fix dependencies between target (otherwise compilation fails with "make -j3") - ---- a/Makefile -+++ b/Makefile -@@ -200,7 +200,7 @@ cleanall: clean - doc: - $(PRINTMAN) $(TXTFILES) $(DOCFILES) - --install: -+install: bin/qconvex bin/qdelaunay bin/qhalf bin/qhull bin/qvoronoi bin/rbox - mkdir -p $(BINDIR) - mkdir -p $(DOCDIR) - mkdir -p $(INCDIR)/libqhull -@@ -240,7 +240,7 @@ printc: - printf: - $(PRINTC) $(FILES) - --qtest: -+qtest: bin/testqset bin/rbox - @echo ============================================ - @echo == make qtest ============================== - @echo ============================================ -@@ -262,7 +262,7 @@ qtest: - @echo ============================================ - -bin/rbox D4 | bin/qhull Tv - --test: qtest -+test: qtest bin/qconvex bin/qdelaunay bin/qhalf bin/qhull bin/qvoronoi bin/rbox - @echo ============================================ - @echo == make test =============================== - @echo ============================================ -@@ -319,7 +319,7 @@ testall: test - -eg/q_egtest - -eg/q_test - --qconvex-prompt: -+qconvex-prompt: bin/qconvex bin/rbox - bin/qconvex - @echo - @echo ============================================ From 64f613a30ca4f2997e1f889f65138afc5a277c3e Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 19 Jul 2021 13:35:24 +0100 Subject: [PATCH 169/355] added basic spkg-configure.m4 --- build/pkgs/qhull/spkg-configure.m4 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 build/pkgs/qhull/spkg-configure.m4 diff --git a/build/pkgs/qhull/spkg-configure.m4 b/build/pkgs/qhull/spkg-configure.m4 new file mode 100644 index 00000000000..b403ee09f6e --- /dev/null +++ b/build/pkgs/qhull/spkg-configure.m4 @@ -0,0 +1,25 @@ +SAGE_SPKG_CONFIGURE([qhull], [ + m4_pushdef([SAGE_QHULL_MINVER],["8.0.2"]) + AC_PATH_PROG([QHULL], [qhull]) + AS_IF([test x$QHULL = x], [ + AC_MSG_NOTICE([qhull not found. Installing qhull]) + sage_spkg_install_qhull=yes + ], [ + AC_MSG_CHECKING([is qhull's version good enough? ]) + qhull_ver=`$QHULL -V | cut -d' ' -f2 2>> config.log` + AX_COMPARE_VERSION([$qhull_ver], [ge], [$SAGE_QHULL_MINVER], [ + AC_MSG_RESULT([yes.]) + AC_MSG_CHECKING([is qhull_r library and headers installed? ]) + AC_CHECK_HEADER([libqhull_r/libqhull_r.h], [ + AC_SEARCH_LIBS([qh_distplane], [qhull_r], [ + AC_MSG_RESULT([yes. Use system's qhull]) + ], [ + AC_MSG_RESULT([no. Install qhull]) + sage_spkg_install_qhull=yes]) dnl SEARCH_LIBS + ], [ + AC_MSG_RESULT([no. Install qhull]) + sage_spkg_install_qhull=yes]) dnl CHECK_HEADER + ]) dnl COMPARE_VERSION + ]) dnl IF + m4_popdef([SAGE_QHULL_MINVER]) +]) From 09399677aba12df5cadd9e10c80ec70b7cf37481 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 10 Sep 2021 12:47:15 +0100 Subject: [PATCH 170/355] correct distros info --- build/pkgs/qhull/distros/debian.txt | 1 + build/pkgs/qhull/distros/fedora.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/build/pkgs/qhull/distros/debian.txt b/build/pkgs/qhull/distros/debian.txt index 95d316779cf..969ed092ec0 100644 --- a/build/pkgs/qhull/distros/debian.txt +++ b/build/pkgs/qhull/distros/debian.txt @@ -1 +1,2 @@ qhull +libqhull-dev diff --git a/build/pkgs/qhull/distros/fedora.txt b/build/pkgs/qhull/distros/fedora.txt index 95d316779cf..f9702ea0653 100644 --- a/build/pkgs/qhull/distros/fedora.txt +++ b/build/pkgs/qhull/distros/fedora.txt @@ -1 +1,2 @@ qhull +qhull-devel From 04e40ffba2f944c8369cc48f3b5aeef6fc409bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 14 Sep 2021 18:14:02 +0200 Subject: [PATCH 171/355] fine tuning short and warn-long options --- src/bin/sage-runtests | 4 ++-- src/sage/doctest/control.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 20a77c65817..674837e5c9b 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -39,10 +39,10 @@ if __name__ == "__main__": parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', - default=None, const=300, metavar="SECONDS", + type=int, default=-1, const=300, metavar="SECONDS", help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") parser.add_argument("--warn-long", dest="warn_long", nargs='?', - default=None, const=1.0, metavar="SECONDS", + type=float, default=-1.0, const=1.0, metavar="SECONDS", help="warn if tests take more time than SECONDS") # By default, include all tests marked 'dochtml' -- see # https://trac.sagemath.org/ticket/25345 and diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 2df8b0b22ca..5bee00bd992 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -99,7 +99,7 @@ def __init__(self, **kwds): self.all = False self.logfile = None self.long = False - self.warn_long = None + self.warn_long = -1.0 self.randorder = None self.random_seed = 0 self.global_iterations = 1 # sage-runtests default is 0 @@ -120,7 +120,7 @@ def __init__(self, **kwds): self.failed = False self.new = False self.show_skipped = False - self.target_walltime = None + self.target_walltime = -1 # sage-runtests contains more optional tags. Technically, adding # auto_optional_tags here is redundant, since that is added @@ -450,7 +450,8 @@ def _init_warn_long(self): sage: DC.options.warn_long # existing command-line options are not changed 5.00000000000000 """ - if self.options.warn_long is not None: # Specified on the command line + # default is -1.0 + if self.options.warn_long > 0: # Specified on the command line return try: self.options.warn_long = 60.0 * self.second_on_modern_computer() From 936b3b64c67e656c2cf528aba70be6638a27d19c Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Tue, 14 Sep 2021 14:46:45 -0400 Subject: [PATCH 172/355] fix docbuild errors --- src/sage/modular/quasimodform/element.py | 11 ++++++----- src/sage/modular/quasimodform/ring.py | 8 +++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index bf0b2af7f95..bcda57bd6cc 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -340,15 +340,16 @@ def is_modular_form(self): def to_polynomial(self, names='E2, E4, E6'): r""" - Return a polynomial `P(E_2, E_4, E_6)` corresponding to the given form - where `E_2`, `E_4` and `E_6` are the generators of the quasimodular - form ring given by :meth:`~sage.modular.quasiform.ring.QuasiModularForms.gens`. + Return a multivariate polynomial `P(E_2, E_4, E_6)` corresponding to the + given form where `E_2`, `E_4` and `E_6` are the generators of the + quasimodular form ring given by + :meth:`~sage.modular.quasiform.ring.QuasiModularForms.gens`. INPUT: - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names - (strings), or a comma separated string. Correspond to the names of the - variables; + (strings), or a comma separated string. Correspond to the names of the + variables; OUTPUT: A multivariate polynomial in the variables ``names`` diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 5736d7cf3d0..8845d090765 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -494,15 +494,17 @@ def polygen(self): def polynomial_ring(self, names='E2, E4, E6'): r""" Return a multivariate polynomial ring isomorphic to the given graded - quasimodular forms ring. In the case of the full modular group, this + quasimodular forms ring. + + In the case of the full modular group, this ring is `R[E_2, E_4, E_6]` where `E_2`, `E_4` and `E_6` have degrees 2, 4 and 6 respectively. INPUT: - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names - (strings), or a comma separated string. Correspond to the names of the - variables; + (strings), or a comma separated string. Correspond to the names of the + variables. OUTPUT: A multivariate polynomial ring in the variables ``names`` From 7e7e98312ec9d4f3e43b83f3a39d38a4e6f7c8af Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 14 Sep 2021 23:25:29 +0100 Subject: [PATCH 173/355] correct package name on debian --- build/pkgs/qhull/distros/debian.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/build/pkgs/qhull/distros/debian.txt b/build/pkgs/qhull/distros/debian.txt index 969ed092ec0..c4e91af6528 100644 --- a/build/pkgs/qhull/distros/debian.txt +++ b/build/pkgs/qhull/distros/debian.txt @@ -1,2 +1 @@ -qhull libqhull-dev From e073d08f6005e28b0b9ec3799b1d0b1a05691dfc Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 14 Sep 2021 23:25:54 +0100 Subject: [PATCH 174/355] replace tabs by spaces, adjust spacing --- build/pkgs/qhull/spkg-configure.m4 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/build/pkgs/qhull/spkg-configure.m4 b/build/pkgs/qhull/spkg-configure.m4 index b403ee09f6e..6eaf6461ec8 100644 --- a/build/pkgs/qhull/spkg-configure.m4 +++ b/build/pkgs/qhull/spkg-configure.m4 @@ -4,22 +4,23 @@ SAGE_SPKG_CONFIGURE([qhull], [ AS_IF([test x$QHULL = x], [ AC_MSG_NOTICE([qhull not found. Installing qhull]) sage_spkg_install_qhull=yes - ], [ + ], [ AC_MSG_CHECKING([is qhull's version good enough? ]) qhull_ver=`$QHULL -V | cut -d' ' -f2 2>> config.log` AX_COMPARE_VERSION([$qhull_ver], [ge], [$SAGE_QHULL_MINVER], [ AC_MSG_RESULT([yes.]) AC_MSG_CHECKING([is qhull_r library and headers installed? ]) AC_CHECK_HEADER([libqhull_r/libqhull_r.h], [ - AC_SEARCH_LIBS([qh_distplane], [qhull_r], [ - AC_MSG_RESULT([yes. Use system's qhull]) - ], [ + AC_SEARCH_LIBS([qh_distplane], [qhull_r], [ + AC_MSG_RESULT([yes. Use system's qhull]) + ], [ AC_MSG_RESULT([no. Install qhull]) sage_spkg_install_qhull=yes]) dnl SEARCH_LIBS - ], [ - AC_MSG_RESULT([no. Install qhull]) - sage_spkg_install_qhull=yes]) dnl CHECK_HEADER - ]) dnl COMPARE_VERSION + ], [ + AC_MSG_RESULT([no. Install qhull]) + sage_spkg_install_qhull=yes + ]) dnl CHECK_HEADER + ]) dnl COMPARE_VERSION ]) dnl IF m4_popdef([SAGE_QHULL_MINVER]) ]) From dc418dd70237e1b61ce54cee57a2ebb3e614a8e6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 14 Sep 2021 22:01:37 -0700 Subject: [PATCH 175/355] build/pkgs/pybind11/patches: Add fix for linuxmint-17, ubuntu-trusty --- build/pkgs/pybind11/patches/3270.patch | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 build/pkgs/pybind11/patches/3270.patch diff --git a/build/pkgs/pybind11/patches/3270.patch b/build/pkgs/pybind11/patches/3270.patch new file mode 100644 index 00000000000..4404661ca81 --- /dev/null +++ b/build/pkgs/pybind11/patches/3270.patch @@ -0,0 +1,23 @@ +From 8920453affdcaad3e4a3a02d39181f5b5bf67fb7 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Tue, 14 Sep 2021 21:57:58 -0700 +Subject: [PATCH] include/pybind11/numpy.h: gcc 4.8.4 does not have + is_trivially_copyable + +--- + include/pybind11/numpy.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h +index 7313897fe1..34b7536d38 100644 +--- a/include/pybind11/numpy.h ++++ b/include/pybind11/numpy.h +@@ -319,7 +319,7 @@ template using remove_all_extents_t = typename array_info::type; + + template using is_pod_struct = all_of< + std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type +-#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) ++#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) + // libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5) + // don't implement is_trivially_copyable, so approximate it + std::is_trivially_destructible, From d0e1e95ea2212f095e51c5963573f675595668fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 14 Sep 2021 22:40:24 -0700 Subject: [PATCH 176/355] build/pkgs/pybind11/package-version.txt: Adjust patch for layout of the sdist --- build/pkgs/pybind11/package-version.txt | 2 +- build/pkgs/pybind11/patches/3270.patch | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build/pkgs/pybind11/package-version.txt b/build/pkgs/pybind11/package-version.txt index 860487ca19c..da323e3f838 100644 --- a/build/pkgs/pybind11/package-version.txt +++ b/build/pkgs/pybind11/package-version.txt @@ -1 +1 @@ -2.7.1 +2.7.1.p0 diff --git a/build/pkgs/pybind11/patches/3270.patch b/build/pkgs/pybind11/patches/3270.patch index 4404661ca81..e434eda6834 100644 --- a/build/pkgs/pybind11/patches/3270.patch +++ b/build/pkgs/pybind11/patches/3270.patch @@ -4,14 +4,16 @@ Date: Tue, 14 Sep 2021 21:57:58 -0700 Subject: [PATCH] include/pybind11/numpy.h: gcc 4.8.4 does not have is_trivially_copyable +Manually edited -- the sdist has a layout different from the git repo. + --- include/pybind11/numpy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 7313897fe1..34b7536d38 100644 ---- a/include/pybind11/numpy.h -+++ b/include/pybind11/numpy.h +--- a/pybind11/include/pybind11/numpy.h ++++ b/pybind11/include/pybind11/numpy.h @@ -319,7 +319,7 @@ template using remove_all_extents_t = typename array_info::type; template using is_pod_struct = all_of< From 84471a3d11c198c23fd59ced9815069181bb5f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 15 Sep 2021 09:01:06 +0200 Subject: [PATCH 177/355] fix for --short --- src/sage/doctest/forker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index c7859acd302..4772c4ed017 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -627,7 +627,7 @@ def _run(self, test, compileflags, out): # Skip this test if we exceeded our --short budget of walltime for # this doctest - if self.options.target_walltime is not None and self.total_walltime >= self.options.target_walltime: + if self.options.target_walltime != -1 and self.total_walltime >= self.options.target_walltime: walltime_skips += 1 self.optionflags |= doctest.SKIP @@ -1753,7 +1753,7 @@ def parallel_dispatch(self): # If we think that we can not finish running all tests until # target_endtime, we skip individual tests. (Only enabled with # --short.) - if opt.target_walltime is None: + if opt.target_walltime == -1: target_endtime = None else: target_endtime = time.time() + opt.target_walltime From 964bf649e5436fc3a8ff78ae8c21dcba3ae18c27 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 20:56:32 -0700 Subject: [PATCH 178/355] git grep -l 'TypeError: .*() takes' | xargs sed -i.bak 's/TypeError: \(.*\)() takes/TypeError: ...\1() takes/' --- src/sage/arith/misc.py | 2 +- src/sage/combinat/combinat.py | 8 ++++---- src/sage/game_theory/normal_form_game.py | 2 +- src/sage/geometry/polyhedron/base.py | 4 ++-- src/sage/graphs/generators/distance_regular.pyx | 2 +- src/sage/interfaces/scilab.py | 2 +- src/sage/misc/explain_pickle.py | 8 ++++---- src/sage/misc/randstate.pyx | 2 +- src/sage/modular/cusps_nf.py | 2 +- src/sage/plot/colors.py | 4 ++-- src/sage/plot/graphics.py | 4 ++-- src/sage/rings/complex_interval.pyx | 2 +- src/sage/rings/complex_mpfr.pyx | 2 +- src/sage/rings/rational.pyx | 2 +- src/sage/symbolic/expression.pyx | 4 ++-- 15 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 83f3a957d17..438fac63053 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -1699,7 +1699,7 @@ def gcd(a, b=None, **kwargs): sage: gcd(3, 6, 2) Traceback (most recent call last): ... - TypeError: gcd() takes ... + TypeError: ...gcd() takes ... sage: gcd([3, 6, 2]) 1 diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 1b63e315221..a5b4c94f14d 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -1508,19 +1508,19 @@ def __init__(self, parent, *args, **kwds): sage: CombinatorialElement(ZZ) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (1 given) + TypeError: ...__init__() takes exactly 2 arguments (1 given) sage: CombinatorialElement(ZZ, 1, 2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) sage: CombinatorialElement(ZZ, 1, list=2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) sage: CombinatorialElement(ZZ, a=1, b=2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) """ # There should be one "list" argument, which can be given as # positional or keyword argument (in the latter case, the name diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index 0ca60758b69..b9e7f031b54 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -744,7 +744,7 @@ def __init__(self, generator=None): sage: error = NormalFormGame(p1, p2) Traceback (most recent call last): ... - TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given + TypeError: ...__init__() takes from 1 to 2 positional arguments but 3 were given When initiating, argument passed must be a list or nothing:: diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 040e09f7df8..08fc4bfe32d 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -215,12 +215,12 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') Traceback (most recent call last): ... - TypeError: _init_Hrepresentation() takes 3 positional arguments but 9 were given + TypeError: ..._init_Hrepresentation() takes 3 positional arguments but 9 were given sage: p = Polyhedron_field(parent, Vrep, 'nonsense', # py2 ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') Traceback (most recent call last): ... - TypeError: _init_Hrepresentation() takes exactly 3 arguments (9 given) + TypeError: ..._init_Hrepresentation() takes exactly 3 arguments (9 given) The empty polyhedron is detected when the Vrepresentation is given with generator; see :trac:`29899`:: diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 91ab0818722..38c356d8863 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -2512,7 +2512,7 @@ def near_polygon_graph(family, params): sage: near_polygon_graph((0, 12)) Traceback (most recent call last): ... - TypeError: near_polygon_graph() takes exactly 2 positional arguments (1 given) + TypeError: ...near_polygon_graph() takes exactly 2 positional arguments (1 given) sage: near_polygon_graph(0, 12) Cycle graph: Graph on 12 vertices sage: near_polygon_graph(*is_near_polygon([8, 7, 6, 5, 1, 2, 3, 8])) diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index ace7bb33ccd..610f64f8d81 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -132,7 +132,7 @@ sage: M = scilab(x) # optional - scilab Traceback (most recent call last): ... - TypeError: _interface_init_() takes exactly one argument (0 given) + TypeError: ..._interface_init_() takes exactly one argument (0 given) sage: M = scilab(matrix(3,range(9))); M # optional - scilab 0. 1. 2. 3. 4. 5. diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index d28ff94ce65..448e641191c 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -2826,11 +2826,11 @@ def append(self): sage: v.append(7) # py2 Traceback (most recent call last): ... - TypeError: append() takes exactly 1 argument (2 given) + TypeError: ...append() takes exactly 1 argument (2 given) sage: v.append(7) # py3 Traceback (most recent call last): ... - TypeError: append() takes 1 positional argument but 2 were given + TypeError: ...append() takes 1 positional argument but 2 were given We can still append by directly using the list method:: @@ -2851,11 +2851,11 @@ def extend(self): sage: v.extend([3,1,4,1,5,9]) # py2 Traceback (most recent call last): ... - TypeError: extend() takes exactly 1 argument (2 given) + TypeError: ...extend() takes exactly 1 argument (2 given) sage: v.extend([3,1,4,1,5,9]) # py3 Traceback (most recent call last): ... - TypeError: extend() takes 1 positional argument but 2 were given + TypeError: ...extend() takes 1 positional argument but 2 were given We can still extend by directly using the list method:: diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index 8b422fe6d9c..f5c282bdb65 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -486,7 +486,7 @@ cdef class randstate: sage: seed(1,2) # indirect doctest Traceback (most recent call last): ... - TypeError: __init__() takes at most 1 positional argument (2 given) + TypeError: ...__init__() takes at most 1 positional argument (2 given) AUTHOR: diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index c575fc1bc09..acfa7a5ebb7 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -257,7 +257,7 @@ def __call__(self, x): sage: c = kCusps(a,2) Traceback (most recent call last): ... - TypeError: __call__() takes 2 positional arguments but 3 were given + TypeError: ...__call__() takes 2 positional arguments but 3 were given :: diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index 7d0b083b0cc..ca387975949 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -1235,7 +1235,7 @@ def float_to_html(r, g, b): sage: float_to_html((0.2, 0.6, 0.8)) # py2 Traceback (most recent call last): ... - TypeError: float_to_html() takes exactly 3 arguments (1 given) + TypeError: ...float_to_html() takes exactly 3 arguments (1 given) sage: float_to_html((0.2, 0.6, 0.8)) # py3 Traceback (most recent call last): @@ -1281,7 +1281,7 @@ def float_to_integer(r, g, b): sage: float_to_integer((0.2, 0.6, 0.8)) # py2 Traceback (most recent call last): ... - TypeError: float_to_integer() takes exactly 3 arguments (1 given) + TypeError: ...float_to_integer() takes exactly 3 arguments (1 given) sage: float_to_integer((0.2, 0.6, 0.8)) # py3 Traceback (most recent call last): diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 94a5d21942d..dfe79c7b6f9 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1252,12 +1252,12 @@ def plot(self): sage: S.plot(1) # py2 Traceback (most recent call last): ... - TypeError: plot() takes exactly 1 argument (2 given) + TypeError: ...plot() takes exactly 1 argument (2 given) sage: S.plot(1) # py3 Traceback (most recent call last): ... - TypeError: plot() takes 1 positional argument but 2 were given + TypeError: ...plot() takes 1 positional argument but 2 were given sage: S.plot(hey="hou") Traceback (most recent call last): diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index e732148a9a0..9d91fa13048 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -107,7 +107,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: ComplexIntervalFieldElement.__new__(ComplexIntervalFieldElement) Traceback (most recent call last): ... - TypeError: __cinit__() takes at least 1 positional argument (0 given) + TypeError: ...__cinit__() takes at least 1 positional argument (0 given) sage: ComplexIntervalFieldElement.__new__(ComplexIntervalFieldElement, CIF) [.. NaN ..] + [.. NaN ..]*I """ diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d121e29d537..f028dc48484 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -960,7 +960,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: coerce(CN, 1+I) Traceback (most recent call last): ... - TypeError: __init__() takes at least 2 positional arguments (1 given) + TypeError: ...__init__() takes at least 2 positional arguments (1 given) """ if self._prec != -1: mpfr_clear(self.__re) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 58e7be8dedd..a0fad76aa85 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -3247,7 +3247,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (1/2).gamma(5) Traceback (most recent call last): ... - TypeError: gamma() takes exactly 0 positional arguments (1 given) + TypeError: ...gamma() takes exactly 0 positional arguments (1 given) """ if prec: return self.n(prec).gamma() diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 0278d035255..398b0f150de 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -8059,7 +8059,7 @@ cdef class Expression(CommutativeRingElement): sage: abs(SR(-5),hold=True) Traceback (most recent call last): ... - TypeError: abs() takes no keyword arguments + TypeError: ...abs() takes no keyword arguments But this is possible using the method :meth:`abs`:: @@ -9573,7 +9573,7 @@ cdef class Expression(CommutativeRingElement): sage: x.gamma(y) Traceback (most recent call last): ... - TypeError: gamma() takes exactly 0 positional arguments (1 given) + TypeError: ...gamma() takes exactly 0 positional arguments (1 given) """ cdef GEx x sig_on() From 247a077ccf2f50276fac1550d7579cc1742e50d8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 21:01:06 -0700 Subject: [PATCH 179/355] git grep -l 'TypeError: .*() got an unexpected' | xargs sed -i.bak 's/TypeError: \(.*\)() got an unexpected/TypeError: ...\1() got an unexpected/' --- src/doc/de/tutorial/tour_linalg.rst | 2 +- src/doc/en/tutorial/tour_linalg.rst | 2 +- src/doc/fr/tutorial/tour_linalg.rst | 2 +- src/doc/ja/tutorial/tour_linalg.rst | 2 +- src/doc/pt/tutorial/tour_linalg.rst | 2 +- src/doc/ru/tutorial/tour_linalg.rst | 2 +- src/sage/functions/other.py | 4 ++-- src/sage/matroids/constructor.py | 8 ++++---- src/sage/misc/mrange.py | 2 +- src/sage/plot/graphics.py | 2 +- src/sage/repl/rich_output/pretty_print.py | 2 +- src/sage/rings/finite_rings/finite_field_constructor.py | 2 +- src/sage/sandpiles/sandpile.py | 2 +- src/sage/sets/cartesian_product.py | 2 +- src/sage/symbolic/expression.pyx | 2 +- src/sage/tests/benchmark.py | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/doc/de/tutorial/tour_linalg.rst b/src/doc/de/tutorial/tour_linalg.rst index 4a090f259ba..2a5467e8884 100644 --- a/src/doc/de/tutorial/tour_linalg.rst +++ b/src/doc/de/tutorial/tour_linalg.rst @@ -255,4 +255,4 @@ Beachten Sie, dass Python zwischen Klein- und Großschreibung unterscheidet: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/en/tutorial/tour_linalg.rst b/src/doc/en/tutorial/tour_linalg.rst index a38b6e1ac72..054e338cea7 100644 --- a/src/doc/en/tutorial/tour_linalg.rst +++ b/src/doc/en/tutorial/tour_linalg.rst @@ -249,4 +249,4 @@ Note that Python is case sensitive: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/fr/tutorial/tour_linalg.rst b/src/doc/fr/tutorial/tour_linalg.rst index 906793390ad..1343fa126fa 100644 --- a/src/doc/fr/tutorial/tour_linalg.rst +++ b/src/doc/fr/tutorial/tour_linalg.rst @@ -252,4 +252,4 @@ Notez que Python distingue les majuscules des minuscules : sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst index 769dbb32006..cf24ab37ed1 100644 --- a/src/doc/ja/tutorial/tour_linalg.rst +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -266,4 +266,4 @@ Pythonでは,大文字小文字が区別されることに注意: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/pt/tutorial/tour_linalg.rst b/src/doc/pt/tutorial/tour_linalg.rst index e7dd77f36dd..9cdf7671dd7 100644 --- a/src/doc/pt/tutorial/tour_linalg.rst +++ b/src/doc/pt/tutorial/tour_linalg.rst @@ -230,4 +230,4 @@ Note que o Python é sensível a maiúsculas e minúsculas: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/ru/tutorial/tour_linalg.rst b/src/doc/ru/tutorial/tour_linalg.rst index 7b5cf65426d..2e1e6620549 100644 --- a/src/doc/ru/tutorial/tour_linalg.rst +++ b/src/doc/ru/tutorial/tour_linalg.rst @@ -224,4 +224,4 @@ Sage поддерживает разреженную линейную алгеб sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 053e0120454..0deae352902 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -868,7 +868,7 @@ def sqrt(x, *args, **kwds): sage: sqrt(4,hold=True) Traceback (most recent call last): ... - TypeError: _do_sqrt() got an unexpected keyword argument 'hold' + TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' This illustrates that the bug reported in :trac:`6171` has been fixed:: @@ -876,7 +876,7 @@ def sqrt(x, *args, **kwds): sage: a.sqrt(prec=100) # this is supposed to fail Traceback (most recent call last): ... - TypeError: sqrt() got an unexpected keyword argument 'prec' + TypeError: ...sqrt() got an unexpected keyword argument 'prec' sage: sqrt(a, prec=100) 1.0488088481701515469914535137 sage: sqrt(4.00, prec=250) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 91b42df6446..650827756a7 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -663,19 +663,19 @@ def Matroid(groundset=None, data=None, **kwds): sage: Matroid("abc", bases=["abc"], foo="bar") Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'foo' + TypeError: ...Matroid() got an unexpected keyword argument 'foo' sage: Matroid(data=["x"], matrix=Matrix(1,1)) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'matrix' + TypeError: ...Matroid() got an unexpected keyword argument 'matrix' sage: Matroid(bases=["x"], matrix=Matrix(1,1)) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'matrix' + TypeError: ...Matroid() got an unexpected keyword argument 'matrix' sage: Matroid(Matrix(1,1), ring=ZZ, field=QQ) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'ring' + TypeError: ...Matroid() got an unexpected keyword argument 'ring' sage: Matroid(rank_function=lambda X: len(X)) Traceback (most recent call last): ... diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 41b9f4f211d..a36ef1bd128 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -700,7 +700,7 @@ def cantor_product(*args, **kwds): sage: next(cantor_product(count(), toto='hey')) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'toto' + TypeError: ...__init__() got an unexpected keyword argument 'toto' :: diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index dfe79c7b6f9..b2b6df12681 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1262,7 +1262,7 @@ def plot(self): sage: S.plot(hey="hou") Traceback (most recent call last): ... - TypeError: plot() got an unexpected keyword argument 'hey' + TypeError: ...plot() got an unexpected keyword argument 'hey' """ return self diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 9d4b5927f2b..f45ca3d126b 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -164,7 +164,7 @@ def pretty_print(self): sage: seq._concatenate_graphs().show(edge_labels=True) Traceback (most recent call last): ... - TypeError: matplotlib() got an unexpected keyword argument 'edge_labels' + TypeError: ...matplotlib() got an unexpected keyword argument 'edge_labels' """ from sage.plot.plot import Graphics from sage.graphs.graph import GenericGraph diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 3290a11ab19..0980ff8dbdf 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -513,7 +513,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, sage: GF.create_key_and_extra_args(9, 'a', foo='value') Traceback (most recent call last): ... - TypeError: create_key_and_extra_args() got an unexpected keyword argument 'foo' + TypeError: ...create_key_and_extra_args() got an unexpected keyword argument 'foo' Moreover, ``repr`` and ``elem_cache`` are ignored when not using givaro:: diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index a03112b98b4..dea3c742289 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -589,7 +589,7 @@ def __init__(self, g, sink=None): sage: G = Sandpile({0:[]}, 0, weighted=False) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'weighted' + TypeError: ...__init__() got an unexpected keyword argument 'weighted' """ # set graph name if isinstance(g, Graph) or isinstance(g, DiGraph): diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 4b75efb6315..0841971eb22 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -74,7 +74,7 @@ def __init__(self, sets, category, flatten=False): sage: cartesian_product([ZZ, ZZ], blub=None) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'blub' + TypeError: ...__init__() got an unexpected keyword argument 'blub' """ self._sets = tuple(sets) Parent.__init__(self, category=category) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 398b0f150de..555466765fb 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -8480,7 +8480,7 @@ cdef class Expression(CommutativeRingElement): sage: sqrt(4,hold=True) Traceback (most recent call last): ... - TypeError: _do_sqrt() got an unexpected keyword argument 'hold' + TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' """ return new_Expression_from_GEx(self._parent, g_hold2_wrapper(g_power_construct, self._gobj, g_ex1_2, hold)) diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 0f084b1f263..3649a81f4f8 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -1555,7 +1555,7 @@ def sage(self): sage: isinstance(B.sage(), float) Traceback (most recent call last): ... - TypeError: anlist() got an unexpected keyword argument 'pari_ints' + TypeError: ...anlist() got an unexpected keyword argument 'pari_ints' """ E = EllipticCurve([1,2,3,4,5]) From 82d9329a46c216015058fb115a9cbe8593528dda Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 21:02:47 -0700 Subject: [PATCH 180/355] git grep -l 'TypeError: .*() missing' | xargs sed -i.bak 's/TypeError: \(.*\)() missing/TypeError: ...\1() missing/' --- src/sage/algebras/commutative_dga.py | 2 +- src/sage/functions/other.py | 2 +- src/sage/plot/colors.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index a5e5404bf9f..e457a292838 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -3327,7 +3327,7 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, sage: AQ.differential() Traceback (most recent call last): ... - TypeError: differential() missing 1 required positional argument: + TypeError: ...differential() missing 1 required positional argument: 'diff' Now we add a differential to ``AQ``:: diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 0deae352902..ca90b214ae3 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -2132,7 +2132,7 @@ def __call__(self, l, **kwargs): sage: cases() Traceback (most recent call last): ... - TypeError: __call__() missing 1 required positional argument: 'l' + TypeError: ...__call__() missing 1 required positional argument: 'l' sage: cases(x) Traceback (most recent call last): diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index ca387975949..7a01d4cca1f 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -1240,7 +1240,7 @@ def float_to_html(r, g, b): sage: float_to_html((0.2, 0.6, 0.8)) # py3 Traceback (most recent call last): ... - TypeError: float_to_html() missing 2 required positional arguments: 'g' and 'b' + TypeError: ...float_to_html() missing 2 required positional arguments: 'g' and 'b' """ return "#%06x" % float_to_integer(r, g, b) @@ -1286,7 +1286,7 @@ def float_to_integer(r, g, b): sage: float_to_integer((0.2, 0.6, 0.8)) # py3 Traceback (most recent call last): ... - TypeError: float_to_integer() missing 2 required positional arguments: 'g' and 'b' + TypeError: ...float_to_integer() missing 2 required positional arguments: 'g' and 'b' """ r, g, b = map(mod_one, (r, g, b)) return int(r * 255) << 16 | int(g * 255) << 8 | int(b * 255) From e80b828810b1f4a9ffc97444939bec63a57b0575 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 21:06:05 -0700 Subject: [PATCH 181/355] git grep -l 'TypeError: float() argument must be.*' | xargs sed -i.bak 's/TypeError: float() argument must be.*/TypeError: float() argument must be a string or a... number.../' --- src/sage/graphs/base/boost_graph.pyx | 2 +- src/sage/graphs/generic_graph.py | 14 +++++++------- src/sage/plot/colors.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index af1de86c552..480ae451395 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -684,7 +684,7 @@ cpdef min_spanning_tree(g, sage: min_spanning_tree(g) Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... """ from sage.graphs.graph import Graph diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee9191b90a6..18e3b34bca9 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4297,31 +4297,31 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Prim_Boost") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Prim_fringe") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Prim_edge") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Kruskal") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Filter_Kruskal") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Kruskal_Boost") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="NetworkX") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: graphs.EmptyGraph().min_spanning_tree() [] diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index 7a01d4cca1f..6fb1ce5c285 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -813,11 +813,11 @@ def __truediv__(self, right): sage: papayawhip / yellow # py2 Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number + TypeError: float() argument must be a string or a... number... sage: papayawhip / yellow # py3 Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number, not 'Color' + TypeError: float() argument must be a string or a... number... """ return self * (1 / float(right)) From 98a1cee6371a648d4497907da168d2823ab0564f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 21:07:55 -0700 Subject: [PATCH 182/355] git grep -l 'AttributeError: can.* set attribute.*' | xargs sed -i.bak 's/AttributeError: can.* set attribute.*/AttributeError: can...t set attribute.../' --- src/sage/misc/lazy_attribute.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index ab55c9c0f24..9cee5d3c4b4 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -363,7 +363,7 @@ class lazy_attribute(_lazy_attribute): sage: a.x = 4 Traceback (most recent call last): ... - AttributeError: can...t set attribute + AttributeError: can...t set attribute... sage: a.__dict__ {} sage: a.x From 851114196ee741768ae0ffeb05ab6f451481a3ab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 21:09:51 -0700 Subject: [PATCH 183/355] git grep -l 'SyntaxError: invalid.*' | xargs sed -i.bak 's/SyntaxError: invalid.*/SyntaxError: invalid .../' --- src/doc/de/tutorial/interactive_shell.rst | 2 +- src/doc/en/tutorial/interactive_shell.rst | 2 +- src/doc/fr/tutorial/interactive_shell.rst | 2 +- src/doc/pt/tutorial/interactive_shell.rst | 2 +- src/doc/ru/tutorial/interactive_shell.rst | 2 +- src/sage/combinat/ncsf_qsym/tutorial.py | 2 +- src/sage/doctest/forker.py | 2 +- src/sage/misc/sage_eval.py | 2 +- src/sage/misc/sageinspect.py | 6 +++--- src/sage/repl/preparse.py | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/doc/de/tutorial/interactive_shell.rst b/src/doc/de/tutorial/interactive_shell.rst index 048f1c6f0ac..a95e8e83b53 100644 --- a/src/doc/de/tutorial/interactive_shell.rst +++ b/src/doc/de/tutorial/interactive_shell.rst @@ -385,7 +385,7 @@ z.B. ``NameError`` oder ``ValueError`` (vgl. Python Library Reference File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/en/tutorial/interactive_shell.rst b/src/doc/en/tutorial/interactive_shell.rst index 564de65aa24..0ca57bfaf5a 100644 --- a/src/doc/en/tutorial/interactive_shell.rst +++ b/src/doc/en/tutorial/interactive_shell.rst @@ -465,7 +465,7 @@ for a complete list of exceptions). For example, File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/fr/tutorial/interactive_shell.rst b/src/doc/fr/tutorial/interactive_shell.rst index 3f28f110c3a..bebb972e6d2 100644 --- a/src/doc/fr/tutorial/interactive_shell.rst +++ b/src/doc/fr/tutorial/interactive_shell.rst @@ -472,7 +472,7 @@ de référence de la bibliothèque de Python [PyLR]_ pour une liste complète). File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/pt/tutorial/interactive_shell.rst b/src/doc/pt/tutorial/interactive_shell.rst index cba3f29cfcd..64ef511d7e4 100644 --- a/src/doc/pt/tutorial/interactive_shell.rst +++ b/src/doc/pt/tutorial/interactive_shell.rst @@ -452,7 +452,7 @@ exemplo, File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/ru/tutorial/interactive_shell.rst b/src/doc/ru/tutorial/interactive_shell.rst index 51dffa1c923..7abfe99fe53 100644 --- a/src/doc/ru/tutorial/interactive_shell.rst +++ b/src/doc/ru/tutorial/interactive_shell.rst @@ -369,7 +369,7 @@ Wall time. Однако, если существует существенная File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/sage/combinat/ncsf_qsym/tutorial.py b/src/sage/combinat/ncsf_qsym/tutorial.py index ac452cdb142..6236a3ba2af 100644 --- a/src/sage/combinat/ncsf_qsym/tutorial.py +++ b/src/sage/combinat/ncsf_qsym/tutorial.py @@ -132,7 +132,7 @@ sage: M[] Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... Working with symmetric functions diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index c7859acd302..6036faadee1 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -581,7 +581,7 @@ def _run(self, test, compileflags, out): ....: @syntax error Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: a = 1 # py3 ....: @syntax error Traceback (most recent call last): diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index d5ddf7085bb..5f2b50ab625 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -171,7 +171,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): File "", line 1 $x = $y[Integer(3)] # Does Perl syntax work? ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... """ if isinstance(source, (list, tuple)): cmds = source[0] diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index f4729d30bbf..25b2124e868 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1141,7 +1141,7 @@ def _sage_getargspec_cython(source): sage: sgc('def f(*x = 5, z = {(1,2,3): True}): pass') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: sgc('def f(int *x = 5, z = {(1,2,3): True}): pass') Traceback (most recent call last): ... @@ -1153,7 +1153,7 @@ def _sage_getargspec_cython(source): sage: sgc('def f(int x = 5, , z = {(1,2,3): True}): pass') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... TESTS: @@ -1163,7 +1163,7 @@ def _sage_getargspec_cython(source): sage: def dummy_python(self, *args, x=1): pass # py2 Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: def dummy_python(self, *args, x=1): pass # py3 sage: sgc("def dummy_python(self, *args, x=1): pass") # py3 ArgSpec(args=['self', 'x'], varargs='args', keywords=None, defaults=(1,)) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e5ac7f7ab73..6e0e13713cf 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -118,7 +118,7 @@ sage: eval('4.__add__(3)') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... Symbolic functional notation:: From f72ebca8826b1b2362bb3d281bd9ff8cfdb5ab8f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 16 Sep 2021 14:22:32 +1000 Subject: [PATCH 184/355] Removing finite_part and redundant _element_constructor_ and change_ring(). Implementing Dirichlet print fallback. --- src/sage/data_structures/stream.py | 4 +- src/sage/rings/lazy_series.py | 210 ++--- src/sage/rings/lazy_series_ring.py | 1252 ++++++++++++++-------------- 3 files changed, 687 insertions(+), 779 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 552aeafcc19..e606f25579b 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1417,7 +1417,7 @@ def is_nonzero(self): class Stream_dirichlet_convolve(Stream_binary): - """ + r""" Operator for the Dirichlet convolution of two streams. INPUT: @@ -1499,7 +1499,7 @@ def get_coefficient(self, n): class Stream_dirichlet_invert(Stream_unary): - """ + r""" Operator for inverse with respect to Dirichlet convolution of the stream. INPUT: diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 662c2057858..6f790856cd1 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -168,51 +168,6 @@ def __init__(self, parent, coeff_stream): Element.__init__(self, parent) self._coeff_stream = coeff_stream - def finite_part(self, degree=None): - r""" - Return ``self`` truncated to ``degree`` as an element of an appropriate ring. - - INPUT: - - - ``degree`` -- ``None`` or an integer - - OUTPUT: - - If ``degree`` is not ``None``, the terms of the series of - degree greater than ``degree`` are removed first. If - ``degree`` is ``None`` and the series is not known to have - only finitely many nonzero coefficients, a ``ValueError`` is - raised. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = L([1,0,0,2,0,0,0,3], valuation=-3); f.finite_part() - z^-3 + 2 + 3*z^4 - sage: f.polynomial() - z^-3 + 2 + 3*z^4 - - sage: L = LazyDirichletSeriesRing(ZZ, "s") - sage: f = L([1,0,0,2,0,0,0,3], valuation=2); f.finite_part() - 3/9^s + 2/5^s + 1/2^s - - """ - P = self.parent() - L = P._laurent_poly_ring - coeff_stream = self._coeff_stream - if degree is None: - if isinstance(coeff_stream, Stream_zero): - return L.zero() - elif isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: - m = coeff_stream._degree - else: - raise ValueError("not a polynomial") - else: - m = degree + 1 - - v = coeff_stream.order() - return L.sum(self[i]*P.monomial(1, i) for i in range(v, m)) - def __getitem__(self, n): """ Return the coefficient of the term with exponent ``n`` of the series. @@ -819,6 +774,59 @@ def _unicode_art_(self): return UnicodeArt('Uninitialized Lazy Laurent Series') return self._format_series(unicode_art, True) + + def change_ring(self, ring): + r""" + Return ``self`` with coefficients converted to elements of ``ring``. + + INPUT: + + - ``ring`` -- a ring + + EXAMPLES: + + Dense Implementation:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + + Sparse Implementation:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M^-1 + z^-1 - 2 + z + O(z^6) + + A Dirichlet series example:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: s = L(constant=2) + sage: t = s.change_ring(QQ) + sage: t.parent() + Lazy Dirichlet Series Ring in z over Rational Field + sage: t^-1 + 1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z)) + """ + P = self.parent() + Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) + return Q.element_class(Q, self._coeff_stream) + # === module structure === def _add_(self, other): @@ -884,7 +892,6 @@ def _add_(self, other): sage: r = L([1,2,3], constant=-1) sage: r + t 2 + 3/2^z + 4/3^z - """ P = self.parent() left = self._coeff_stream @@ -1499,16 +1506,6 @@ def _div_(self, other): if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact)): if not left._constant and not right._constant: - # # alternatively: - # pl = self.finite_part() - # pr = other.finite_part() - # try: - # ret = pl / pr - # ret = P._laurent_poly_ring(ret) - # except (TypeError, ValueError, NotImplementedError): - # # We cannot divide the polynomials, so the result must be a series - # pass - # return P(ret) R = P._laurent_poly_ring pl = left._polynomial_part(R) pr = right._polynomial_part(R) @@ -1672,48 +1669,6 @@ class LazyLaurentSeries(LazyCauchyProductSeries): sage: TestSuite(f).run() """ - def change_ring(self, ring): - r""" - Return ``self`` with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES: - - Dense Implementation:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: s = 2 + z - sage: t = s.change_ring(QQ) - sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - - Sparse Implementation:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M ^-1 - z^-1 - 2 + z + O(z^6) - """ - from .lazy_series_ring import LazyLaurentSeriesRing - Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - def __call__(self, g): r""" Return the composition of ``self`` with ``g``. @@ -2412,7 +2367,7 @@ def _format_series(self, formatter, format_strings=False): 1/2 + 1/4*z^2 + 1/8*z^4 + 1/16*z^6 + O(z^7) """ P = self.parent() - R = P._laurent_poly_ring + R = P._internal_poly_ring z = R.gen() cs = self._coeff_stream v = cs._approximate_order @@ -2574,22 +2529,6 @@ def __invert__(self): P = self.parent() return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream)) - def change_ring(self, ring): - """ - Return this series with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - TESTS:: - - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) - """ - from .lazy_series_ring import LazyDirichletSeriesRing - Q = LazyDirichletSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) - def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. @@ -2618,6 +2557,13 @@ def _format_series(self, formatter, format_strings=False): (3 ) ( -s ) (---) (1) + (2 *(x - 1)) + ( 3 ) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: D = LazyDirichletSeriesRing(L, "s") + sage: f = D([2, 0, 1/(1-z), 3]); f + (2)/1^s + ((1+z+z^2+z^3+z^4+z^5+z^6+O(z^7))/3^s) + (3)/4^s + sage: f._format_series(ascii_art) + ((2)/1^s) + ((1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7))/3^s) + ((3)/4^s) """ P = self.parent() cs = self._coeff_stream @@ -2631,10 +2577,11 @@ def _format_series(self, formatter, format_strings=False): m = v + P.options.display_length atomic_repr = P._coeff_ring._repr_option('element_is_atomic') - mons = [P.monomial(self[i], i) for i in range(v, m) if self[i]] + varname = P.variable_name() + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] if not isinstance(cs, Stream_exact) or cs._constant: if P._coeff_ring is P.base_ring(): - bigO = ["O(%s)" % P.monomial(1, m)] + bigO = ["O(%s)" % P._monomial(1, m)] else: bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] else: @@ -2644,31 +2591,26 @@ def _format_series(self, formatter, format_strings=False): from sage.typeset.unicode_art import unicode_art from sage.typeset.ascii_art import ascii_art from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis if formatter == repr: poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) elif formatter == latex: poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") + elif formatter in [ascii_art, unicode_art]: + if formatter == ascii_art: + from sage.typeset.symbols import ascii_left_parenthesis as left_paren + from sage.typeset.symbols import ascii_right_parenthesis as right_paren else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: + from sage.typeset.symbols import unicode_left_parenthesis as left_paren + from sage.typeset.symbols import unicode_right_parenthesis as right_paren if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") + poly = formatter(*(mons + bigO), sep=" + ") else: def parenthesize(m): - a = unicode_art(m) + a = formatter(m) h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + return formatter(left_paren.character_art(h), + a, right_paren.character_art(h)) + poly = formatter(*([parenthesize(m) for m in mons] + bigO), sep=" + ") return poly + diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2cf7db18930..e4148ef6047 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -33,7 +33,8 @@ from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.lazy_series import (LazyCauchyProductSeries, +from sage.rings.lazy_series import (LazyModuleElement, + LazyCauchyProductSeries, LazyLaurentSeries, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -46,699 +47,686 @@ Stream_uninitialized ) - -class LazyLaurentSeriesRing(UniqueRepresentation, Parent): +class LazySeriesRing(UniqueRepresentation, Parent): """ - The ring of lazy Laurent series. - - The ring of Laurent series over a ring with the usual arithmetic - where the coefficients are computed lazily. - - INPUT: + Abstract base class for lazy series. + """ + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): + r""" + Construct a lazy series from ``x``. - - ``base_ring`` -- base ring - - ``names`` -- name of the generator - - ``sparse`` -- (default: ``True``) whether the implementation of - the series is sparse or not + INPUT: - EXAMPLES:: + - ``x`` -- data used to the define a Laurent series + - ``valuation`` -- integer (optional); integer; a lower bound for + the valuation of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``constant`` -- (optional) the eventual constant of the series + - ``coefficients`` -- (optional) a callable that defines the + coefficients of the series; must be ``None`` if ``x`` is provided; + see note below - sage: L. = LazyLaurentSeriesRing(QQ) - sage: 1 / (1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: 1 / (1 - z) == 1 / (1 - z) - True - sage: L in Fields - True + If ``valuation`` is specified and ``x`` is convertible into a Laurent + polynomial or is a lazy Laurent series, then the data is shifted so + that the result has the specified valuation. - Lazy Laurent series ring over a finite field:: + .. WARNING:: - sage: L. = LazyLaurentSeriesRing(GF(3)); L - Lazy Laurent Series Ring in z over Finite Field of size 3 - sage: e = 1 / (1 + z) - sage: e.coefficient(100) - 1 - sage: e.coefficient(100).parent() - Finite Field of size 3 + If ``valuation`` is specified and ``x`` is a lazy series, then + the valuation will be computed. If the series ``x`` is not + known to be zero, then this will run forever. - Series can be defined by specifying a coefficient function - along with a valuation or a degree where after the series - is evenutally constant:: + .. NOTE:: - sage: R. = QQ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: def coeff(n): - ....: if n < 0: - ....: return -2 + n - ....: if n == 0: - ....: return 6 - ....: return x + y^n - sage: f = L(coeff, valuation=-5) - sage: f - -7*z^-5 - 6*z^-4 - 5*z^-3 - 4*z^-2 - 3*z^-1 + 6 + (x + y)*z + O(z^2) - sage: 1 / (1 - f) - 1/7*z^5 - 6/49*z^6 + 1/343*z^7 + 8/2401*z^8 + 64/16807*z^9 - + 17319/117649*z^10 + (1/49*x + 1/49*y - 180781/823543)*z^11 + O(z^12) - sage: L(coeff, valuation=-3, degree=3, constant=x) - -5*z^-3 - 4*z^-2 - 3*z^-1 + 6 + (x + y)*z + (y^2 + x)*z^2 - + x*z^3 + x*z^4 + x*z^5 + O(z^6) + When working over a base ring that takes callables as valid + input, then passing a function as ``x`` might be converted to + the base ring. If instead the input is to be treated as the + function giving the coefficients of the lazy series being + cosntructed, then use the ``coefficients`` argument in this + case and do not provide ``x``. - Similarly, we can specify a polynomial or the initial - coefficients with anything that converts into the - corresponding Laurent polynomial ring:: + EXAMPLES:: - sage: L([1, x, y, 0, x+y]) - 1 + x*z + y*z^2 + (x + y)*z^4 - sage: L([1, x, y, 0, x+y], constant=2) - 1 + x*z + y*z^2 + (x + y)*z^4 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) - sage: L([1, x, y, 0, x+y], degree=7, constant=2) - 1 + x*z + y*z^2 + (x + y)*z^4 + 2*z^7 + 2*z^8 + 2*z^9 + O(z^10) - sage: L([1, x, y, 0, x+y], valuation=-2) - z^-2 + x*z^-1 + y + (x + y)*z^2 - sage: L([1, x, y, 0, x+y], valuation=-2, constant=3) - z^-2 + x*z^-1 + y + (x + y)*z^2 + 3*z^3 + 3*z^4 + 3*z^5 + O(z^6) - sage: L([1, x, y, 0, x+y], valuation=-2, degree=4, constant=3) - z^-2 + x*z^-1 + y + (x + y)*z^2 + 3*z^4 + 3*z^5 + 3*z^6 + O(z^7) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + 1 - Some additional examples over the integer ring:: + sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L in Fields - False - sage: 1 / (1 - 2*z)^3 - 1 + 6*z + 24*z^2 + 80*z^3 + 240*z^4 + 672*z^5 + 1792*z^6 + O(z^7) + sage: L(lambda i: i, valuation=5, constant=1, degree=10) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + sage: L(lambda i: i, valuation=5, constant=(1, 10)) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - sage: R. = LaurentPolynomialRing(ZZ) - sage: L(x^-2 + 3 + x) - z^-2 + 3 + z - sage: L(x^-2 + 3 + x, valuation=-5, constant=2) - z^-5 + 3*z^-3 + z^-2 + 2*z^-1 + 2 + 2*z + O(z^2) - sage: L(x^-2 + 3 + x, valuation=-5, degree=0, constant=2) - z^-5 + 3*z^-3 + z^-2 + 2 + 2*z + 2*z^2 + O(z^3) + sage: X = L(constant=5, degree=2); X + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: X.valuation() + 2 - We can also truncate, shift, and make eventually constant any - Laurent series:: + sage: def g(i): + ....: if i < 0: + ....: return 1 + ....: else: + ....: return 1 + sum(k for k in range(i+1)) + sage: e = L(g, valuation=-5); e + z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) + sage: f = e^-1; f + z^5 - z^6 - z^11 + O(z^12) + sage: f.coefficient(10) + 0 + sage: f[20] + 9 + sage: f[30] + -219 - sage: f = 1 / (z + z^2) - sage: f - z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) - sage: L(f, valuation=2) - z^2 - z^3 + z^4 - z^5 + z^6 - z^7 + z^8 + O(z^9) - sage: L(f, degree=3) - z^-1 - 1 + z - z^2 - sage: L(f, degree=3, constant=2) - z^-1 - 1 + z - z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6) - sage: L(f, valuation=1, degree=4) - z - z^2 + z^3 - sage: L(f, valuation=1, degree=4, constant=5) - z - z^2 + z^3 + 5*z^4 + 5*z^5 + 5*z^6 + O(z^7) + sage: L(valuation=2, constant=1) + z^2 + z^3 + z^4 + O(z^5) + sage: L(constant=1) + Traceback (most recent call last): + ... + ValueError: you must specify the degree for the polynomial 0 - Power series can be defined recursively (see :meth:`define()` for - more examples):: + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = L(None, valuation=0) - sage: s.define(1 + z*s^2) - sage: s - 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) + sage: f = L([1,2,3,4], valuation=-5) + sage: f + z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 + sage: g = L([1,3,5,7,9], valuation=5, constant=-1) + sage: g + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) - If we do not explcitly know the exact value of every coefficient, - then equality checking will depend on the computed coefficients. - If at a certain point we cannot prove two series are different - (which involves the coefficients we have computed), then we will - raise an error:: + Finally, ``x`` can be a Laurent polynomial:: - sage: f = 1 / (z + z^2); f - z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) - sage: f2 = f * 2 # currently no coefficients computed - sage: f3 = f * 3 # currently no coefficients computed - sage: f2 == f3 - Traceback (most recent call last): - ... - ValueError: undecidable - sage: f2 # computes some of the coefficients of f2 - 2*z^-1 - 2 + 2*z - 2*z^2 + 2*z^3 - 2*z^4 + 2*z^5 + O(z^6) - sage: f3 # computes some of the coefficients of f3 - 3*z^-1 - 3 + 3*z - 3*z^2 + 3*z^3 - 3*z^4 + 3*z^5 + O(z^6) - sage: f2 == f3 - False + sage: P. = LaurentPolynomialRing(QQ) + sage: p = x^-2 + 3*x^3 + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L(p) + x^-2 + 3*x^3 - The implementation of the ring can be either be a sparse or a dense one. - The default is a sparse implementation:: + sage: L(p, valuation=0) + 1 + 3*x^5 - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.is_sparse() - True - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: L.is_sparse() - False - """ - Element = LazyLaurentSeries + sage: L(p, valuation=1) + x + 3*x^6 - def __init__(self, base_ring, names, sparse=True, category=None): - """ - Initialize ``self``. + We construct a lazy Laurent series over another lazy Laurent series:: - TESTS:: + sage: R. = LazyLaurentSeriesRing(QQ) + sage: L. = LazyLaurentSeriesRing(R) + sage: e = L(lambda n: 1/factorial(n), 0); e + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: L(lambda n: 1/(1 + s^n), 0) + 1/2 + (1 - s + s^2 - s^3 + s^4 - s^5 + s^6 + O(s^7))*z + + (1 - s^2 + s^4 - s^6 + O(s^7))*z^2 + + (1 - s^3 + s^6 + O(s^7))*z^3 + (1 - s^4 + O(s^7))*z^4 + + (1 - s^5 + O(s^7))*z^5 + (1 - s^6 + O(s^7))*z^6 + O(z^7) - sage: L = LazyLaurentSeriesRing(ZZ, 't') - sage: elts = L.some_elements()[:-2] # skip the non-exact elements - sage: TestSuite(L).run(elements=elts, skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) - sage: L.category() - Category of infinite commutative no zero divisors algebras over - (euclidean domains and infinite enumerated sets and metric spaces) + We note that ``e`` builds correctly because ``R`` additionally + requires the valuation to be specified. - sage: L = LazyLaurentSeriesRing(QQ, 't') - sage: L.category() - Join of Category of complete discrete valuation fields - and Category of commutative algebras over (number fields and quotient fields and metric spaces) - and Category of infinite sets - sage: L = LazyLaurentSeriesRing(ZZ['x,y'], 't') - sage: L.category() - Category of infinite commutative no zero divisors algebras over - (unique factorization domains and commutative algebras over - (euclidean domains and infinite enumerated sets and metric spaces) - and infinite sets) - sage: E. = ExteriorAlgebra(QQ) - sage: L = LazyLaurentSeriesRing(E, 't') # not tested - """ - self._sparse = sparse - self._coeff_ring = base_ring - # We always use the dense because our CS_exact is implemented densely - self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names) + In the next example the argument is interpreted as a constant + polynomial, which happens to be a Dirichlet series:: - category = Algebras(base_ring.category()) - if base_ring in Fields(): - category &= CompleteDiscreteValuationFields() - else: - if "Commutative" in base_ring.category().axioms(): - category = category.Commutative() - if base_ring in IntegralDomains(): - category &= IntegralDomains() + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(D) + sage: L(lambda n: 1/factorial(n), valuation=0) + (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) - if base_ring.is_zero(): - category = category.Finite() - else: - category = category.Infinite() + We can also specify that the given function should be + interpreted as the coefficients of the Laurent series:: - Parent.__init__(self, base=base_ring, names=names, category=category) + sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - def _repr_(self): - """ - Return a string representation of ``self``. + TESTS: - EXAMPLES:: + Checking the valuation is consistent:: - sage: LazyLaurentSeriesRing(GF(2), 'z') - Lazy Laurent Series Ring in z over Finite Field of size 2 - """ - return "Lazy Laurent Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L([0,0,2,3], valuation=-4) + 2*z^-4 + 3*z^-3 + sage: L(range(5), valuation=-4) + z^-4 + 2*z^-3 + 3*z^-2 + 4*z^-1 + sage: P. = ZZ[] + sage: L(x^2 + x^5, valuation=-4) + z^-4 + z^-1 + sage: L(1, valuation=-4) + z^-4 + sage: L(L(1), valuation=-4) + z^-4 + sage: L(1/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + sage: L(z^-3/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + sage: L(z^3/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - def _latex_(self): - r""" - Return a latex representation of ``self``. + sage: L(z^3/(1-z), valuation=0) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - EXAMPLES:: + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L(lambda n: 1/(n+1), degree=3) + Traceback (most recent call last): + ... + ValueError: the valuation must be specified - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: latex(L) - \Bold{F}_{2} (\!(z)\!) - """ - from sage.misc.latex import latex - return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) + sage: L(5, valuation=3.1) + Traceback (most recent call last): + ... + ValueError: the valuation must be an integer - def characteristic(self): - """ - Return the characteristic of this lazy power series ring, which - is the same as the characteristic of its base ring. + sage: L(5, valuation=6/2) + 5*z^3 - EXAMPLES:: + This gives zero:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.characteristic() + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L(lambda n: 0, degree=3, valuation=0) + 0 + sage: L(L.zero(), degree=3) + 0 + sage: L(L.zero(), degree=3, valuation=2) + 0 + sage: L(L.zero(), degree=3, constant=0) + 0 + sage: L(L.zero(), degree=3, valuation=2, constant=0) 0 - sage: R. = LazyLaurentSeriesRing(GF(11)); R - Lazy Laurent Series Ring in w over Finite Field of size 11 - sage: R.characteristic() - 11 - """ - return self.base_ring().characteristic() + This does not:: - def is_sparse(self): - """ - Return whether ``self`` is sparse or not. + sage: L(lambda n: 0, degree=3, constant=1, valuation=0) + z^3 + z^4 + z^5 + O(z^6) + sage: L(L.zero(), degree=-3, constant=1) + z^-3 + z^-2 + z^-1 + O(1) + sage: L(L.zero(), valuation=2, constant=1) + z^2 + z^3 + z^4 + O(z^5) - EXAMPLES:: + This raises an error:: - sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=False) - sage: L.is_sparse() - False + sage: L(lambda n: 0, valuation=3, constant=1) + Traceback (most recent call last): + ... + ValueError: constant may only be specified if the degree is specified - sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=True) - sage: L.is_sparse() + We support the old input format for ``constant``:: + + sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) + sage: g = L(lambda i: i, valuation=-3, constant=(-1,3)) + sage: f == g + True + sage: g = L(lambda i: i, -3, (-1,3)) + sage: f == g True - """ - return self._sparse - def monomial(self, c, n): - r""" - Return the interpretation of the coefficient ``c`` at index ``n``. + sage: D = LazyDirichletSeriesRing(ZZ, 't') + sage: m = D(moebius) + sage: L(m) + z - z^2 - z^3 - z^5 + z^6 - z^7 + O(z^8) - EXAMPLES:: + .. TODO:: - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.monomial(1, 3) - z^3 - sage: L.monomial(2, -4) - 2*z^-4 + Add a method to change the sparse/dense implementation. """ - L = self._laurent_poly_ring - return L(c) * L.gen() ** n - - @cached_method - def gen(self, n=0): - r""" - Return the ``n``-th generator of ``self``. + if valuation is not None and valuation not in ZZ: + raise ValueError("the valuation must be an integer") - EXAMPLES:: + if x is None and coefficients is None: + if valuation is None: + raise ValueError("the valuation must be specified") + return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.gen() - z - sage: L.gen(3) - Traceback (most recent call last): - ... - IndexError: there is only one generator - """ - if n != 0: - raise IndexError("there is only one generator") - R = self.base_ring() - coeff_stream = Stream_exact([R.one()], self._sparse, - constant=R.zero(), order=1) - return self.element_class(self, coeff_stream) + if coefficients is not None and (not isinstance(x, int) or x): + raise ValueError("coefficients must be None if x is provided") - def ngens(self): - r""" - Return the number of generators of ``self``. + BR = self.base_ring() + if isinstance(constant, (tuple, list)): + constant, degree = constant + if isinstance(degree, (tuple, list)): + constant, degree = degree + if constant is not None: + constant = BR(constant) - This is always 1. + if coefficients is None: + # Try to build stuff using the internal polynomial ring constructor + R = self._internal_poly_ring + try: + x = R(x) + except (TypeError, ValueError): + pass - EXAMPLES:: + # If x has been converted to the Laurent polynomial ring + if parent(x) is R: + if not x and not constant: + return self.zero() + if x and valuation is not None: + x = x.shift(valuation - x.valuation()) + if degree is None and not x: + if valuation is None: + raise ValueError("you must specify the degree for the polynomial 0") + degree = valuation + if x == R.zero(): + coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) + return self.element_class(self, coeff_stream) + initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] + coeff_stream = Stream_exact(initial_coefficients, self._sparse, + order=x.valuation(), constant=constant, degree=degree) + return self.element_class(self, coeff_stream) - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.ngens() - 1 - """ - return 1 + # Handle when it is a lazy series + if isinstance(x, LazyModuleElement): + if x._coeff_stream._is_sparse is not self._sparse: + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") - @cached_method - def gens(self): - """ - Return the generators of ``self``. + # If x is known to be 0 + if isinstance(x._coeff_stream, Stream_zero): + if not constant: + return x + if degree is None: + if valuation is None: + raise ValueError("you must specify the degree for the polynomial 0") + degree = valuation + coeff_stream = Stream_exact([], self._sparse, order=degree, + constant=constant) + return self.element_class(self, coeff_stream) - EXAMPLES:: + # Make the result exact + if degree is not None: + # truncate the series and then possibly make constant + x_val = x._coeff_stream.order() + if not valuation: + valuation = x_val + initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] + if not any(initial_coefficients): + if not constant: + return self.zero() + # We learned some stuff about x; pass it along + x._coeff_stream._approximate_order += len(initial_coefficients) + initial_coefficients = [] + coeff_stream = Stream_exact(initial_coefficients, self._sparse, + order=valuation, constant=constant, degree=degree) + return self.element_class(self, coeff_stream) - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.gens() - (z,) - sage: 1/(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - """ - return tuple([self.gen(n) for n in range(self.ngens())]) + # We are just possibly shifting the result + ret = self.element_class(self, x._coeff_stream) + if valuation is None: + return ret + return x.shift(valuation - x._coeff_stream.order()) - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. + else: + x = coefficients - EXAMPLES:: + if callable(x): + if valuation is None: + raise ValueError("the valuation must be specified") + if degree is None: + if constant is not None: + raise ValueError("constant may only be specified if the degree is specified") + coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) + return self.element_class(self, coeff_stream) - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True + # degree is not None + if constant is None: + constant = BR.zero() + p = [BR(x(i)) for i in range(valuation, degree)] + if not any(p) and not constant: + return self.zero() + coeff_stream = Stream_exact(p, self._sparse, order=valuation, + constant=constant, degree=degree) + return self.element_class(self, coeff_stream) - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) + raise ValueError(f"unable to convert {x} into {self}") - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - EXAMPLES:: +class LazyLaurentSeriesRing(LazySeriesRing): + """ + The ring of lazy Laurent series. - sage: L = LazyLaurentSeriesRing(QQ, 'z') - sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) - 2 - sage: phi(2, valuation=-2) - 2*z^-2 - sage: phi(2, valuation=-2, constant=3, degree=1) - 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) + The ring of Laurent series over a ring with the usual arithmetic + where the coefficients are computed lazily. - def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): - """ - Construct a Laurent series from ``x``. + INPUT: - INPUT: + - ``base_ring`` -- base ring + - ``names`` -- name of the generator + - ``sparse`` -- (default: ``True``) whether the implementation of + the series is sparse or not - - ``x`` -- data used to the define a Laurent series - - ``valuation`` -- integer (optional); integer; a lower bound for - the valuation of the series - - ``degree`` -- (optional) the degree when the series is ``constant`` - - ``constant`` -- (optional) the eventual constant of the series - - ``coefficients`` -- (optional) a callable that defines the - coefficients of the series; must be ``None`` if ``x`` is provided; - see note below + EXAMPLES:: - If ``valuation`` is specified and ``x`` is convertible into a Laurent - polynomial or is a lazy Laurent series, then the data is shifted so - that the result has the specified valuation. + sage: L. = LazyLaurentSeriesRing(QQ) + sage: 1 / (1 - z) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: 1 / (1 - z) == 1 / (1 - z) + True + sage: L in Fields + True - .. WARNING:: + Lazy Laurent series ring over a finite field:: - If ``valuation`` is specified and ``x`` is a lazy series, then - the valuation will be computed. If the series ``x`` is not - known to be zero, then this will run forever. + sage: L. = LazyLaurentSeriesRing(GF(3)); L + Lazy Laurent Series Ring in z over Finite Field of size 3 + sage: e = 1 / (1 + z) + sage: e.coefficient(100) + 1 + sage: e.coefficient(100).parent() + Finite Field of size 3 - .. NOTE:: + Series can be defined by specifying a coefficient function + along with a valuation or a degree where after the series + is evenutally constant:: - When working over a base ring that takes callables as valid - input, then passing a function as ``x`` might be converted to - the base ring. If instead the input is to be treated as the - function giving the coefficients of the lazy series being - cosntructed, then use the ``coefficients`` argument in this - case and do not provide ``x``. + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: def coeff(n): + ....: if n < 0: + ....: return -2 + n + ....: if n == 0: + ....: return 6 + ....: return x + y^n + sage: f = L(coeff, valuation=-5) + sage: f + -7*z^-5 - 6*z^-4 - 5*z^-3 - 4*z^-2 - 3*z^-1 + 6 + (x + y)*z + O(z^2) + sage: 1 / (1 - f) + 1/7*z^5 - 6/49*z^6 + 1/343*z^7 + 8/2401*z^8 + 64/16807*z^9 + + 17319/117649*z^10 + (1/49*x + 1/49*y - 180781/823543)*z^11 + O(z^12) + sage: L(coeff, valuation=-3, degree=3, constant=x) + -5*z^-3 - 4*z^-2 - 3*z^-1 + 6 + (x + y)*z + (y^2 + x)*z^2 + + x*z^3 + x*z^4 + x*z^5 + O(z^6) - EXAMPLES:: + Similarly, we can specify a polynomial or the initial + coefficients with anything that converts into the + corresponding Laurent polynomial ring:: - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L(2) - 0 - sage: L(3) - 1 + sage: L([1, x, y, 0, x+y]) + 1 + x*z + y*z^2 + (x + y)*z^4 + sage: L([1, x, y, 0, x+y], constant=2) + 1 + x*z + y*z^2 + (x + y)*z^4 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) + sage: L([1, x, y, 0, x+y], degree=7, constant=2) + 1 + x*z + y*z^2 + (x + y)*z^4 + 2*z^7 + 2*z^8 + 2*z^9 + O(z^10) + sage: L([1, x, y, 0, x+y], valuation=-2) + z^-2 + x*z^-1 + y + (x + y)*z^2 + sage: L([1, x, y, 0, x+y], valuation=-2, constant=3) + z^-2 + x*z^-1 + y + (x + y)*z^2 + 3*z^3 + 3*z^4 + 3*z^5 + O(z^6) + sage: L([1, x, y, 0, x+y], valuation=-2, degree=4, constant=3) + z^-2 + x*z^-1 + y + (x + y)*z^2 + 3*z^4 + 3*z^5 + 3*z^6 + O(z^7) - sage: L. = LazyLaurentSeriesRing(ZZ) + Some additional examples over the integer ring:: - sage: L(lambda i: i, valuation=5, constant=1, degree=10) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - sage: L(lambda i: i, valuation=5, constant=(1, 10)) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L in Fields + False + sage: 1 / (1 - 2*z)^3 + 1 + 6*z + 24*z^2 + 80*z^3 + 240*z^4 + 672*z^5 + 1792*z^6 + O(z^7) - sage: X = L(constant=5, degree=2); X - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: X.valuation() - 2 + sage: R. = LaurentPolynomialRing(ZZ) + sage: L(x^-2 + 3 + x) + z^-2 + 3 + z + sage: L(x^-2 + 3 + x, valuation=-5, constant=2) + z^-5 + 3*z^-3 + z^-2 + 2*z^-1 + 2 + 2*z + O(z^2) + sage: L(x^-2 + 3 + x, valuation=-5, degree=0, constant=2) + z^-5 + 3*z^-3 + z^-2 + 2 + 2*z + 2*z^2 + O(z^3) - sage: def g(i): - ....: if i < 0: - ....: return 1 - ....: else: - ....: return 1 + sum(k for k in range(i+1)) - sage: e = L(g, valuation=-5); e - z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) - sage: f = e^-1; f - z^5 - z^6 - z^11 + O(z^12) - sage: f.coefficient(10) - 0 - sage: f[20] - 9 - sage: f[30] - -219 + We can also truncate, shift, and make eventually constant any + Laurent series:: - sage: L(valuation=2, constant=1) - z^2 + z^3 + z^4 + O(z^5) - sage: L(constant=1) - Traceback (most recent call last): - ... - ValueError: you must specify the degree for the polynomial 0 + sage: f = 1 / (z + z^2) + sage: f + z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) + sage: L(f, valuation=2) + z^2 - z^3 + z^4 - z^5 + z^6 - z^7 + z^8 + O(z^9) + sage: L(f, degree=3) + z^-1 - 1 + z - z^2 + sage: L(f, degree=3, constant=2) + z^-1 - 1 + z - z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6) + sage: L(f, valuation=1, degree=4) + z - z^2 + z^3 + sage: L(f, valuation=1, degree=4, constant=5) + z - z^2 + z^3 + 5*z^4 + 5*z^5 + 5*z^6 + O(z^7) - Alternatively, ``x`` can be a list of elements of the base ring. - Then these elements are read as coefficients of the terms of - degrees starting from the ``valuation``. In this case, ``constant`` - may be just an element of the base ring instead of a tuple or can be - simply omitted if it is zero:: + Power series can be defined recursively (see :meth:`define()` for + more examples):: - sage: f = L([1,2,3,4], valuation=-5) - sage: f - z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 - sage: g = L([1,3,5,7,9], valuation=5, constant=-1) - sage: g - z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: s = L(None, valuation=0) + sage: s.define(1 + z*s^2) + sage: s + 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - Finally, ``x`` can be a Laurent polynomial:: + If we do not explcitly know the exact value of every coefficient, + then equality checking will depend on the computed coefficients. + If at a certain point we cannot prove two series are different + (which involves the coefficients we have computed), then we will + raise an error:: - sage: P. = LaurentPolynomialRing(QQ) - sage: p = x^-2 + 3*x^3 - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L(p) - x^-2 + 3*x^3 + sage: f = 1 / (z + z^2); f + z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) + sage: f2 = f * 2 # currently no coefficients computed + sage: f3 = f * 3 # currently no coefficients computed + sage: f2 == f3 + Traceback (most recent call last): + ... + ValueError: undecidable + sage: f2 # computes some of the coefficients of f2 + 2*z^-1 - 2 + 2*z - 2*z^2 + 2*z^3 - 2*z^4 + 2*z^5 + O(z^6) + sage: f3 # computes some of the coefficients of f3 + 3*z^-1 - 3 + 3*z - 3*z^2 + 3*z^3 - 3*z^4 + 3*z^5 + O(z^6) + sage: f2 == f3 + False - sage: L(p, valuation=0) - 1 + 3*x^5 + The implementation of the ring can be either be a sparse or a dense one. + The default is a sparse implementation:: - sage: L(p, valuation=1) - x + 3*x^6 + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.is_sparse() + True + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: L.is_sparse() + False + """ + Element = LazyLaurentSeries - We construct a lazy Laurent series over another lazy Laurent series:: + def __init__(self, base_ring, names, sparse=True, category=None): + """ + Initialize ``self``. - sage: R. = LazyLaurentSeriesRing(QQ) - sage: L. = LazyLaurentSeriesRing(R) - sage: e = L(lambda n: 1/factorial(n), 0); e - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: L(lambda n: 1/(1 + s^n), 0) - 1/2 + (1 - s + s^2 - s^3 + s^4 - s^5 + s^6 + O(s^7))*z - + (1 - s^2 + s^4 - s^6 + O(s^7))*z^2 - + (1 - s^3 + s^6 + O(s^7))*z^3 + (1 - s^4 + O(s^7))*z^4 - + (1 - s^5 + O(s^7))*z^5 + (1 - s^6 + O(s^7))*z^6 + O(z^7) + TESTS:: - We note that ``e`` builds correctly because ``R`` additionally - requires the valuation to be specified. + sage: L = LazyLaurentSeriesRing(ZZ, 't') + sage: elts = L.some_elements()[:-2] # skip the non-exact elements + sage: TestSuite(L).run(elements=elts, skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + sage: L.category() + Category of infinite commutative no zero divisors algebras over + (euclidean domains and infinite enumerated sets and metric spaces) - In the next example the argument is interpreted as a constant - polynomial, which happens to be a Dirichlet series:: + sage: L = LazyLaurentSeriesRing(QQ, 't') + sage: L.category() + Join of Category of complete discrete valuation fields + and Category of commutative algebras over (number fields and quotient fields and metric spaces) + and Category of infinite sets + sage: L = LazyLaurentSeriesRing(ZZ['x,y'], 't') + sage: L.category() + Category of infinite commutative no zero divisors algebras over + (unique factorization domains and commutative algebras over + (euclidean domains and infinite enumerated sets and metric spaces) + and infinite sets) + sage: E. = ExteriorAlgebra(QQ) + sage: L = LazyLaurentSeriesRing(E, 't') # not tested + """ + self._sparse = sparse + self._coeff_ring = base_ring + # We always use the dense because our CS_exact is implemented densely + self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names) + self._internal_poly_ring = self._laurent_poly_ring - sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: L. = LazyLaurentSeriesRing(D) - sage: L(lambda n: 1/factorial(n), valuation=0) - (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) + category = Algebras(base_ring.category()) + if base_ring in Fields(): + category &= CompleteDiscreteValuationFields() + else: + if "Commutative" in base_ring.category().axioms(): + category = category.Commutative() + if base_ring in IntegralDomains(): + category &= IntegralDomains() - We can also specify that the given function should be - interpreted as the coefficients of the Laurent series:: + if base_ring.is_zero(): + category = category.Finite() + else: + category = category.Infinite() - sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + Parent.__init__(self, base=base_ring, names=names, category=category) - TESTS: + def _repr_(self): + """ + Return a string representation of ``self``. - Checking the valuation is consistent:: + EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L([0,0,2,3], valuation=-4) - 2*z^-4 + 3*z^-3 - sage: L(range(5), valuation=-4) - z^-4 + 2*z^-3 + 3*z^-2 + 4*z^-1 - sage: P. = ZZ[] - sage: L(x^2 + x^5, valuation=-4) - z^-4 + z^-1 - sage: L(1, valuation=-4) - z^-4 - sage: L(L(1), valuation=-4) - z^-4 - sage: L(1/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - sage: L(z^-3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - sage: L(z^3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + sage: LazyLaurentSeriesRing(GF(2), 'z') + Lazy Laurent Series Ring in z over Finite Field of size 2 + """ + return "Lazy Laurent Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) - sage: L(z^3/(1-z), valuation=0) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + def _latex_(self): + r""" + Return a latex representation of ``self``. - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L(lambda n: 1/(n+1), degree=3) - Traceback (most recent call last): - ... - ValueError: the valuation must be specified + EXAMPLES:: - sage: L(5, valuation=3.1) - Traceback (most recent call last): - ... - ValueError: the valuation must be an integer + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: latex(L) + \Bold{F}_{2} (\!(z)\!) + """ + from sage.misc.latex import latex + return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) - sage: L(5, valuation=6/2) - 5*z^3 + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. - This gives zero:: + EXAMPLES:: - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L(lambda n: 0, degree=3, valuation=0) - 0 - sage: L(L.zero(), degree=3) - 0 - sage: L(L.zero(), degree=3, valuation=2) - 0 - sage: L(L.zero(), degree=3, constant=0) - 0 - sage: L(L.zero(), degree=3, valuation=2, constant=0) + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.characteristic() 0 + sage: R. = LazyLaurentSeriesRing(GF(11)); R + Lazy Laurent Series Ring in w over Finite Field of size 11 + sage: R.characteristic() + 11 - This does not:: - - sage: L(lambda n: 0, degree=3, constant=1, valuation=0) - z^3 + z^4 + z^5 + O(z^6) - sage: L(L.zero(), degree=-3, constant=1) - z^-3 + z^-2 + z^-1 + O(1) - sage: L(L.zero(), valuation=2, constant=1) - z^2 + z^3 + z^4 + O(z^5) + """ + return self.base_ring().characteristic() - This raises an error:: + def is_sparse(self): + """ + Return whether ``self`` is sparse or not. - sage: L(lambda n: 0, valuation=3, constant=1) - Traceback (most recent call last): - ... - ValueError: constant may only be specified if the degree is specified + EXAMPLES:: - We support the old input format for ``constant``:: + sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=False) + sage: L.is_sparse() + False - sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) - sage: g = L(lambda i: i, valuation=-3, constant=(-1,3)) - sage: f == g - True - sage: g = L(lambda i: i, -3, (-1,3)) - sage: f == g + sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=True) + sage: L.is_sparse() True + """ + return self._sparse - sage: D = LazyDirichletSeriesRing(ZZ, 't') - sage: m = D(moebius) - sage: L(m) + @cached_method + def gen(self, n=0): + r""" + Return the ``n``-th generator of ``self``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.gen() + z + sage: L.gen(3) Traceback (most recent call last): ... - ValueError: unable to convert 1 - 1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(8^t)) into a lazy Laurent series + IndexError: there is only one generator + """ + if n != 0: + raise IndexError("there is only one generator") + R = self.base_ring() + coeff_stream = Stream_exact([R.one()], self._sparse, + constant=R.zero(), order=1) + return self.element_class(self, coeff_stream) + def ngens(self): + r""" + Return the number of generators of ``self``. - .. TODO:: + This is always 1. - Add a method to change the sparse/dense implementation. + EXAMPLES:: + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.ngens() + 1 """ - if valuation is not None and valuation not in ZZ: - raise ValueError("the valuation must be an integer") - - if x is None and coefficients is None: - if valuation is None: - raise ValueError("the valuation must be specified") - return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) - - if coefficients is not None and (not isinstance(x, int) or x): - raise ValueError("coefficients must be None if x is provided") - - R = self._laurent_poly_ring - BR = self.base_ring() - if isinstance(constant, (tuple, list)): - constant, degree = constant - if isinstance(degree, (tuple, list)): - constant, degree = degree - if constant is not None: - constant = BR(constant) + return 1 - if coefficients is None: - try: - # Try to build stuff using the polynomial ring constructor - x = R(x) - except (TypeError, ValueError): - pass + @cached_method + def gens(self): + """ + Return the generators of ``self``. - # If x has been converted to the Laurent polynomial ring - if parent(x) is R: - if not x and not constant: - return self.zero() - if x and valuation is not None: - x = x.shift(valuation - x.valuation()) - if degree is None and not x: - if valuation is None: - raise ValueError("you must specify the degree for the polynomial 0") - degree = valuation - if x == R.zero(): - coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) - return self.element_class(self, coeff_stream) - initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] - coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=x.valuation(), constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - if isinstance(x, LazyCauchyProductSeries): - if x._coeff_stream._is_sparse is not self._sparse: - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.gens() + (z,) + sage: 1/(1 - z) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + """ + return tuple([self.gen(n) for n in range(self.ngens())]) - # If x is known to be 0 - if isinstance(x._coeff_stream, Stream_zero): - if not constant: - return x - if degree is None: - if valuation is None: - raise ValueError("you must specify the degree for the polynomial 0") - degree = valuation - coeff_stream = Stream_exact([], self._sparse, order=degree, - constant=constant) - return self.element_class(self, coeff_stream) + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. - # Make the result exact - if degree is not None: - # truncate the series and then possibly make constant - x_val = x.valuation() - if not valuation: - valuation = x_val - initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] - if not any(initial_coefficients): - if not constant: - return self.zero() - # We learned some stuff about x; pass it along - x._coeff_stream._approximate_order += len(initial_coefficients) - initial_coefficients = [] - coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=valuation, constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - # We are just possibly shifting the result - ret = self.element_class(self, x._coeff_stream) - if valuation is None: - return ret - return x.shift(valuation - ret.valuation()) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True - else: - x = coefficients + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) - if callable(x): - if valuation is None: - raise ValueError("the valuation must be specified") - if degree is None: - if constant is not None: - raise ValueError("constant may only be specified if the degree is specified") - coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) - return self.element_class(self, coeff_stream) + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. - # degree is not None - if constant is None: - constant = BR.zero() - p = [BR(x(i)) for i in range(valuation, degree)] - if not any(p) and not constant: - return self.zero() - coeff_stream = Stream_exact(p, self._sparse, order=valuation, - constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - raise ValueError(f"unable to convert {x} into a lazy Laurent series") + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=-2) + 2*z^-2 + sage: phi(2, valuation=-2, constant=3, degree=1) + 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) def _an_element_(self): """ @@ -752,7 +740,7 @@ def _an_element_(self): """ R = self.base_ring() coeff_stream = Stream_exact([R.an_element(), 3, 0, 2*R.an_element(), 1], - self._sparse, order=-2, constant=R.one()) + self._sparse, order=-2, constant=R.one()) return self.element_class(self, coeff_stream) def some_elements(self): @@ -937,7 +925,7 @@ def series(self, coefficient, valuation, degree=None, constant=None): if degree is None: degree = valuation + len(coefficient) coeff_stream = Stream_exact(coefficient, self._sparse, order=valuation, - constant=constant, degree=degree) + constant=constant, degree=degree) return self.element_class(self, coeff_stream) if degree is not None and valuation > degree and constant: @@ -948,8 +936,21 @@ def series(self, coefficient, valuation, degree=None, constant=None): constant=constant, degree=degree) return t + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L._monomial(1, 3) + z^3 + sage: L._monomial(2, -4) + 2*z^-4 + """ + return self._laurent_poly_ring(c).shift(n) -class LazyDirichletSeriesRing(UniqueRepresentation, Parent): +class LazyDirichletSeriesRing(LazySeriesRing): """ Lazy Dirichlet series ring. @@ -982,6 +983,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._coeff_ring = base_ring # TODO: it would be good to have something better than the symbolic ring self._laurent_poly_ring = SR + self._internal_poly_ring = LaurentPolynomialRing(base_ring, names) category = Algebras(base_ring.category()) if base_ring in IntegralDomains(): @@ -1016,19 +1018,6 @@ def characteristic(self): """ return self.base_ring().characteristic() - def monomial(self, c, n): - r""" - Return the interpretation of the coefficient ``c`` at index ``n``. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.monomial(5, 3) - 5/3^z - """ - L = self._laurent_poly_ring - return L(c) * L(n) ** -L(self.variable_name()) - def _coerce_map_from_(self, S): """ Return ``True`` if a coercion from ``S`` exists. @@ -1066,15 +1055,15 @@ def _coerce_map_from_base_ring(self): # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. return self._generic_coerce_map(self.base_ring()) - def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None): - """ + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): + r""" Construct a Dirichlet series from ``x``. INPUT: - ``x`` -- data used to the define a Dirichlet series - ``valuation`` -- integer (optional); integer; a lower bound for - the valuation of the series + the exp of the valuation of the series - ``degree`` -- (optional) the degree when the series is ``constant`` - ``constant`` -- (optional) the eventual constant of the series @@ -1099,6 +1088,9 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(constant=1) 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) + sage: L(lambda i: i, valuation=3) + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + 9/9^z + O(1/(10^z)) + Alternatively, ``x`` can be a list of elements of the base ring. Then these elements are read as coefficients of the terms of degrees starting from the ``valuation``. In this case, ``constant`` @@ -1121,59 +1113,25 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No Add a method to make a copy of ``self._sparse``. """ - if valuation is None: + if isinstance(x, (list, tuple)): + p = self._internal_poly_ring(x) + if valuation is None: + if not p: + valuation = 1 + len(x) + x = p + else: + x = p.shift(1) + elif valuation is None: valuation = 1 - elif valuation not in ZZ or valuation <= 0: - raise ValueError("the valuation must be a positive integer") - if x is None: - return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) + if valuation is not None and (valuation not in ZZ or valuation <= 0): + raise ValueError("the valuation must be a positive integer") BR = self.base_ring() - if isinstance(constant, (tuple, list)): - constant, degree = constant - if isinstance(degree, (tuple, list)): - constant, degree = degree - if constant is None: - constant = BR(ZZ.zero()) - else: - constant = BR(constant) - if x in BR: x = BR(x) - if not x and not constant: - coeff_stream = Stream_zero(self._sparse) - return self.element_class(self, coeff_stream) - elif not x: - x = [] - else: - x = [x] - - if isinstance(x, (tuple, list)): - coeff_stream = Stream_exact(x, self._sparse, - order=valuation, - constant=constant, - degree=degree) - return self.element_class(self, coeff_stream) - if isinstance(x, LazyDirichletSeries): - if x._coeff_stream._is_sparse is self._sparse: - return self.element_class(self, x._coeff_stream) - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") - if callable(x): - if degree is not None: - if constant is None: - constant = ZZ.zero() - x = [BR(x(i)) for i in range(1, degree)] - coeff_stream = Stream_exact(x, self._sparse, - order=valuation, - constant=constant, - degree=degree) - return self.element_class(self, coeff_stream) - coeff_stream = Stream_function(x, BR, self._sparse, valuation) - return self.element_class(self, coeff_stream) - raise ValueError(f"unable to convert {x} into a lazy Dirichlet series") + return super()._element_constructor_(x, valuation, degree, constant, coefficients) def _an_element_(self): """ @@ -1217,13 +1175,21 @@ def zero(self): """ return self.element_class(self, Stream_zero(self._sparse)) - # add options to class - class options(GlobalOptions): - NAME = 'LazyDirichletSeriesRing' - module = 'sage.rings.lazy_series_ring' - display_length = dict(default=7, - description='the number of coefficients to display from the valuation', - checker=lambda x: x in ZZ and x > 0) - constant_length = dict(default=3, - description='the number of coefficients to display for nonzero constant series', - checker=lambda x: x in ZZ and x > 0) + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L._monomial(5, 3) + 5/3^z + """ + try: + L = self._laurent_poly_ring + return L(c) * L(n) ** -L(self.variable_name()) + except (ValueError, TypeError): + return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) + + options = LazyLaurentSeriesRing.options + From 65c586b0c2632ec8e35b29dba5488ea0db7e957d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Sep 2021 22:06:12 -0700 Subject: [PATCH 185/355] Fix 2 more doctests to accept exception messages reworded in python 3.10 --- src/sage/combinat/alternating_sign_matrix.py | 2 +- src/sage/databases/oeis.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 7dc60852255..681eec64400 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -848,7 +848,7 @@ def to_dyck_word(self, algorithm): sage: asm.to_dyck_word() Traceback (most recent call last): ... - TypeError: to_dyck_word() ...argument... + TypeError: ...to_dyck_word() ...argument... sage: asm.to_dyck_word(algorithm = 'notamethod') Traceback (most recent call last): ... diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 72fe3ed830e..318ab05f447 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -388,7 +388,7 @@ def __call__(self, query, max_results=3, first_result=0): sage: oeis() Traceback (most recent call last): ... - TypeError: __call__() ... + TypeError: ...__call__() ... """ if isinstance(query, str): if re.match('^A[0-9]{6}$', query): From ec282634db5fbb61c7731ba8998c356814887f70 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 16 Sep 2021 14:26:07 +0200 Subject: [PATCH 186/355] Trac #29581: tie construuctor to ring --- .../characteristic_cohomology_class.py | 435 +++++++++--------- .../manifolds/differentiable/vector_bundle.py | 6 +- 2 files changed, 222 insertions(+), 219 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 0459b64732a..4b9d99c7e15 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -282,12 +282,14 @@ from sage.combinat.free_module import IndexedFreeModuleElement from sage.misc.fast_methods import Singleton from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method, cached_function +from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method from .affine_connection import AffineConnection from .bundle_connection import BundleConnection from .levi_civita_connection import LeviCivitaConnection -from sage.rings.rational_field import QQ +from sage.symbolic.expression import Expression +from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): @@ -775,7 +777,7 @@ def __init__(self, base, vbundle): max_degree=dim, mul_symbol='⌣', mul_latex_symbol=r'\smile') - def _element_constructor_(self, x, name=None, latex_name=None): + def _element_constructor_(self, x, **kwargs): r""" Convert ``x`` into ``self``. @@ -784,11 +786,16 @@ def _element_constructor_(self, x, name=None, latex_name=None): sage: M = Manifold(8, 'M') sage: TM = M.tangent_bundle() sage: CR = TM.characteristic_cohomology_class_ring() - sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p = CR('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M sage: CR(p, name='pontr') Characteristic cohomology class pontr(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M """ + if isinstance(x, (str, Expression)) or is_Polynomial(x): + return self._build_element(x, **kwargs) + R = self.base_ring() if x in R: @@ -808,9 +815,216 @@ def _element_constructor_(self, x, name=None, latex_name=None): else: raise TypeError(f"do not know how to make x (= {x}) " f"an element of self (={self})") - + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') return self.element_class(self, d, name=name, latex_name=latex_name) + @cached_method + def _build_element(self, *args, **kwargs): + r""" + Construct a characteristic cohomology class. + + The result is cached. + + INPUT: + + - ``val`` -- the input data corresponding to the characteristic class + using the Chern-Weil homomorphism; this argument can be either a + symbolic expression, a polynomial or one of the following predefined + classes: + + - ``'Chern'`` -- total Chern class, + - ``'ChernChar'`` -- Chern character, + - ``'Todd'`` -- Todd class, + - ``'Pontryagin'`` -- total Pontryagin class, + - ``'Hirzebruch'`` -- Hirzebruch class, + - ``'AHat'`` -- `\hat{A}` class, + - ``'Euler'`` -- Euler class. + + - ``name`` -- (default: ``None``) string representation given to the + characteristic class; if ``None`` the default algebra representation or + predefined name is used + - ``latex_name`` -- (default: ``None``) LaTeX name given to the + characteristic class; if ``None`` the value of ``name`` is used + - ``class_type`` -- (default: ``None``) class type of the characteristic + cohomology class; the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type + - ``'additive'`` -- returns a class of additive type + - ``'Pfaffian'`` -- returns a class of Pfaffian type + + This argument must be stated if ``val`` is a polynomial or symbolic + expression. + + EXAMPLES: + + Total Pontryagin class of an 8-dimensional manifold:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over the + 8-dimensional differentiable manifold M + + Define a multiplicative class (see :func:`multiplicative_sequence`):: + + sage: P. = PolynomialRing(QQ) + sage: f = 1 + x - x^2 + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 + p_1 - p_1^2 + 3*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + + Pass a symbolic expression, whose Taylor expansion at zero will be used:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: x = var('x') + sage: f = cos(x) + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 - 1/2*p_1^2 + p_2)(TM) of the Tangent + bundle TM over the 8-dimensional differentiable manifold M + """ + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') + base_ring = self.base_ring() + class_type = kwargs.get('class_type') + vbundle = self._vbundle + val = args[0] + dim = vbundle._base_space._dim + + # predefined classes accessible via class names + if isinstance(val, str): + from sage.arith.misc import factorial, bernoulli + + P = PolynomialRing(base_ring, 'x') + x = P.gen() + if val == 'Chern': + if vbundle._field_type != 'complex': + raise ValueError( + f'total Chern class not defined on {vbundle}') + if name is None: + name = 'c' + class_type = 'multiplicative' + val = 1 + x + if val == 'Pontryagin': + if vbundle._field_type != 'real': + raise ValueError( + f'total Pontryagin class not defined on {vbundle}') + if name is None: + name = 'p' + class_type = 'multiplicative' + val = 1 + x + elif val == 'ChernChar': + if vbundle._field_type != 'complex': + raise ValueError( + f'Chern character not defined on {vbundle}') + if name is None: + name = 'ch' + if latex_name is None: + latex_name = r'\mathrm{ch}' + class_type = 'additive' + coeff = [1 / factorial(k) for k in + range(dim // 2 + 1)] # exp(x) + val = P(coeff) + elif val == 'Todd': + if vbundle._field_type != 'complex': + raise ValueError(f'Todd class not defined on {vbundle}') + if name is None: + name = 'Td' + if latex_name is None: + latex_name = r'\mathrm{Td}' + class_type = 'multiplicative' + val = 1 + x / 2 + for k in range(1, dim // 2 + 1): + val += (-1) ** (k + 1) / factorial(2 * k) * bernoulli( + 2 * k) * x ** (2 * k) + elif val == 'Hirzebruch': + if vbundle._field_type != 'real': + raise ValueError( + f'Hirzebruch class not defined on {vbundle}') + if name is None: + name = 'L' + if latex_name is None: + latex_name = 'L' + class_type = 'multiplicative' + coeff = [2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k) + for k in range(dim // 4 + 1)] + val = P(coeff) + elif val == 'AHat': + if vbundle._field_type != 'real': + raise ValueError(f'AHat class not defined on {vbundle}') + if name is None: + name = 'A^' + if latex_name is None: + latex_name = r'\hat{A}' + class_type = 'multiplicative' + coeff = [- (2 ** (2 * k) - 2) / 2 ** (2 * k) * bernoulli( + 2 * k) / factorial(2 * k) + for k in range(dim // 4 + 1)] + val = P(coeff) + elif val == 'Euler': + if vbundle._field_type != 'real' or not vbundle.has_orientation(): + raise ValueError(f'Euler class not defined on {vbundle}') + if name is None: + name = 'e' + class_type = 'Pfaffian' + val = x + else: + ValueError(f'predefined class "{val}" unknown') + + # turn symbolic expression into a polynomial via Taylor expansion + if isinstance(val, Expression): + x = val.default_variable() + P = PolynomialRing(base_ring, x) + + if vbundle._field_type == 'real': + pow_range = dim // 4 + elif vbundle._field_type == 'complex': + pow_range = dim // 2 + else: + ValueError(f'field type of {vbundle} must be real or complex') + + val = P(val.taylor(x, 0, pow_range)) + + # turn polynomial into a characteristic cohomology class via sequences + if is_Polynomial(val): + if class_type is None: + raise TypeError(f'class_type must be stated if {val} ' + f'is a polynomial') + n = self.ngens() + s = 0 # shift; important in case of Euler class generator + if self._algorithm is PontryaginEulerAlgorithm(): + s = 1 # skip Euler class + n -= 1 # ignore Euler class + + if class_type == 'additive': + sym = additive_sequence(val, vbundle._rank, n) + elif class_type == 'multiplicative': + sym = multiplicative_sequence(val, n) + elif class_type == 'Pfaffian': + P = val.parent() + x = P.gen() + val = (val(x) - val(-x)) / 2 # project to odd functions + val = P([(-1) ** k * val[2 * k + 1] for k in range(n + 1)]) + sym = multiplicative_sequence(val, n) + else: + AttributeError('unkown class type') + + d = {} + w_vec = self._weighted_vectors + for p, c in sym: + vec = [0] * self.ngens() + if class_type == 'Pfaffian': + vec[0] = 1 # always multiply with e + for i in p: + vec[i - 1 + s] += 1 + key = w_vec(vec) + d[key] = c + res = self._from_dict(d) + res.set_name(name=name, latex_name=latex_name) + return res + + # Nothing worked? Then something went wrong! + raise ValueError(f'cannot convert {val} into an element of {self}') + def _repr_(self): r""" String representation of the object. @@ -947,217 +1161,6 @@ def additive_sequence(q, k, n=None): mon_pol = m._from_dict(m_dict) return Sym.e()(mon_pol) -@cached_function -def CharacteristicCohomologyClass(*args, **kwargs): - r""" - Construct a characteristic cohomology class. - - The result is cached. - - INPUT: - - - ``vbundle`` -- the vector bundle over which the characteristic - cohomology class shall be defined; this argument is skipped when invoked - directly from the vector bundle (see - :meth:`sage.manifolds.differentiable.vector_bundle.characteristic_cohomology_class`) - - ``val`` -- the input data corresponding to the characteristic class - using the Chern-Weil homomorphism; this argument can be either a - symbolic expression, a polynomial or one of the following predefined - classes: - - - ``'Chern'`` -- total Chern class, - - ``'ChernChar'`` -- Chern character, - - ``'Todd'`` -- Todd class, - - ``'Pontryagin'`` -- total Pontryagin class, - - ``'Hirzebruch'`` -- Hirzebruch class, - - ``'AHat'`` -- `\hat{A}` class, - - ``'Euler'`` -- Euler class. - - - ``base_ring`` -- (default: ``QQ``) base ring over which the - characteristic cohomology class ring shall be defined - - ``name`` -- (default: ``None``) string representation given to the - characteristic class; if ``None`` the default algebra representation or - predefined name is used - - ``latex_name`` -- (default: ``None``) LaTeX name given to the - characteristic class; if ``None`` the value of ``name`` is used - - ``class_type`` -- (default: ``None``) class type of the characteristic - cohomology class; the following options are possible: - - - ``'multiplicative'`` -- returns a class of multiplicative type - - ``'additive'`` -- returns a class of additive type - - ``'Pfaffian'`` -- returns a class of Pfaffian type - - This argument must be stated if ``val`` is a polynomial or symbolic - expression. - - EXAMPLES: - - Total Pontryagin class of an 8-dimensional manifold:: - - sage: M = Manifold(8, 'M') - sage: TM = M.tangent_bundle() - sage: p = TM.characteristic_cohomology_class('Pontryagin'); p - Characteristic cohomology class p(TM) of the Tangent bundle TM over the - 8-dimensional differentiable manifold M - - Define a multiplicative class (see :func:`multiplicative_sequence`):: - - sage: P. = PolynomialRing(QQ) - sage: f = 1 + x - x^2 - sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class - Characteristic cohomology class (1 + p_1 - p_1^2 + 3*p_2)(TM) of the - Tangent bundle TM over the 8-dimensional differentiable manifold M - - Pass a symbolic expression, whose Taylor expansion at zero will be used:: - - sage: M = Manifold(8, 'M') - sage: TM = M.tangent_bundle() - sage: x = var('x') - sage: f = cos(x) - sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class - Characteristic cohomology class (1 - 1/2*p_1^2 + p_2)(TM) of the Tangent - bundle TM over the 8-dimensional differentiable manifold M - """ - from sage.rings.polynomial.polynomial_ring import is_PolynomialRing - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.symbolic.expression import Expression - - name, latex_name = kwargs.get('name'), kwargs.get('latex_name') - base_ring = kwargs.get('base_ring', QQ) - class_type = kwargs.get('class_type') - vbundle = args[0] - val = args[1] # input value - R = CharacteristicCohomologyClassRing(base_ring, vbundle) - dim = vbundle._base_space._dim - - # predefined classes accessible via class names - if isinstance(val, str): - from sage.arith.misc import factorial, bernoulli - - P = PolynomialRing(base_ring, 'x') - x = P.gen() - if val == 'Chern': - if vbundle._field_type != 'complex': - raise ValueError(f'total Chern class not defined on {vbundle}') - if name is None: - name = 'c' - class_type = 'multiplicative' - val = 1 + x - if val == 'Pontryagin': - if vbundle._field_type != 'real': - raise ValueError(f'total Pontryagin class not defined on {vbundle}') - if name is None: - name = 'p' - class_type = 'multiplicative' - val = 1 + x - elif val == 'ChernChar': - if vbundle._field_type != 'complex': - raise ValueError(f'Chern character not defined on {vbundle}') - if name is None: - name = 'ch' - if latex_name is None: - latex_name = r'\mathrm{ch}' - class_type = 'additive' - coeff = [1 / factorial(k) for k in range(dim // 2 + 1)] # exp(x) - val = P(coeff) - elif val == 'Todd': - if vbundle._field_type != 'complex': - raise ValueError(f'Todd class not defined on {vbundle}') - if name is None: - name = 'Td' - if latex_name is None: - latex_name = r'\mathrm{Td}' - class_type = 'multiplicative' - val = 1 + x / 2 - for k in range(1, dim // 2 + 1): - val += (-1)**(k+1) / factorial(2*k) * bernoulli(2*k) * x**(2*k) - elif val == 'Hirzebruch': - if vbundle._field_type != 'real': - raise ValueError(f'Hirzebruch class not defined on {vbundle}') - if name is None: - name = 'L' - if latex_name is None: - latex_name = 'L' - class_type = 'multiplicative' - coeff = [2**(2*k) * bernoulli(2*k) / factorial(2*k) - for k in range(dim // 4 + 1)] - val = P(coeff) - elif val == 'AHat': - if vbundle._field_type != 'real': - raise ValueError(f'AHat class not defined on {vbundle}') - if name is None: - name = 'A^' - if latex_name is None: - latex_name = r'\hat{A}' - class_type = 'multiplicative' - coeff = [- (2**(2*k) - 2) / 2**(2*k) * bernoulli(2*k) / factorial(2*k) - for k in range(dim // 4 + 1)] - val = P(coeff) - elif val == 'Euler': - if vbundle._field_type != 'real' or not vbundle.has_orientation(): - raise ValueError(f'Euler class not defined on {vbundle}') - if name is None: - name = 'e' - class_type = 'Pfaffian' - val = x - else: - ValueError(f'predefined class "{val}" unknown') - - # turn symbolic expression into a polynomial via Taylor expansion - if isinstance(val, Expression): - x = val.default_variable() - P = PolynomialRing(base_ring, x) - - if vbundle._field_type == 'real': - pow_range = dim // 4 - elif vbundle._field_type == 'complex': - pow_range = dim // 2 - else: - ValueError(f'field type of {vbundle} must be real or complex') - - val = P(val.taylor(x, 0, pow_range)) - - # turn polynomial into a characteristic cohomology class via sequences - if is_PolynomialRing(val.parent()): - if class_type is None: - raise TypeError(f'class_type must be stated if {val} ' - f'is a polynomial') - n = R.ngens() - s = 0 # shift; important in case of Euler class generator - if R._algorithm is PontryaginEulerAlgorithm(): - s = 1 # skip Euler class - n -= 1 # ignore Euler class - - if class_type == 'additive': - sym = additive_sequence(val, vbundle._rank, n) - elif class_type == 'multiplicative': - sym = multiplicative_sequence(val, n) - elif class_type == 'Pfaffian': - P = val.parent() - x = P.gen() - val = (val(x) - val(-x)) / 2 # project to odd functions - val = P([(-1)**k * val[2*k+1] for k in range(n + 1)]) - sym = multiplicative_sequence(val, n) - else: - AttributeError('unkown class type') - - d = {} - w_vec = R._weighted_vectors - for p, c in sym: - vec = [0] * R.ngens() - if class_type == 'Pfaffian': - vec[0] = 1 # always multiply with e - for i in p: - vec[i - 1 + s] += 1 - key = w_vec(vec) - d[key] = c - res = R._from_dict(d) - res.set_name(name=name, latex_name=latex_name) - return res - - # last resort: try coercion - return R(val, name=name, latex_name=latex_name) - def fast_wedge_power(form, n): r""" diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index e0a2f4ee440..b23207a6d3d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -274,9 +274,9 @@ def characteristic_cohomology_class(self, *args, **kwargs): :class:`~sage.manifolds.differentiable.characteristic_class.CharacteristicClass`. """ - from .characteristic_cohomology_class import CharacteristicCohomologyClass - - return CharacteristicCohomologyClass(self, *args, **kwargs) + base_ring = kwargs.get('base_ring', QQ) + R = self.characteristic_cohomology_class_ring(base_ring) + return R(*args, **kwargs) characteristic_class = deprecated_function_alias(29581, characteristic_cohomology_class) From c5370ec74eb85fd267c558ea8bad0e74512402b1 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 16 Sep 2021 23:35:10 +0200 Subject: [PATCH 187/355] Trac #29581: remove line breaks due to hard wrap in editor --- .../characteristic_cohomology_class.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 4b9d99c7e15..2bf2a2b8d77 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -898,24 +898,21 @@ def _build_element(self, *args, **kwargs): x = P.gen() if val == 'Chern': if vbundle._field_type != 'complex': - raise ValueError( - f'total Chern class not defined on {vbundle}') + raise ValueError(f'total Chern class not defined on {vbundle}') if name is None: name = 'c' class_type = 'multiplicative' val = 1 + x if val == 'Pontryagin': if vbundle._field_type != 'real': - raise ValueError( - f'total Pontryagin class not defined on {vbundle}') + raise ValueError(f'total Pontryagin class not defined on {vbundle}') if name is None: name = 'p' class_type = 'multiplicative' val = 1 + x elif val == 'ChernChar': if vbundle._field_type != 'complex': - raise ValueError( - f'Chern character not defined on {vbundle}') + raise ValueError(f'Chern character not defined on {vbundle}') if name is None: name = 'ch' if latex_name is None: @@ -938,8 +935,7 @@ def _build_element(self, *args, **kwargs): 2 * k) * x ** (2 * k) elif val == 'Hirzebruch': if vbundle._field_type != 'real': - raise ValueError( - f'Hirzebruch class not defined on {vbundle}') + raise ValueError(f'Hirzebruch class not defined on {vbundle}') if name is None: name = 'L' if latex_name is None: From 0f2355f513cb400c317f46f315c3164535366842 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 17 Sep 2021 09:33:53 +1000 Subject: [PATCH 188/355] Fixing doc errors and pyflakes; using sparse poly ring for Dirichlet internal poly ring. --- src/sage/rings/lazy_series.py | 11 +++++------ src/sage/rings/lazy_series_ring.py | 9 ++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 6f790856cd1..d739c6025cf 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2068,11 +2068,11 @@ def revert(self): The compositional inverse exists if and only if: - - `val(f) = 1', or + - `val(f) = 1`, or - `f = a + b z` with `a b \neq 0`, or - - `f = a/z' with `a \neq 0` + - `f = a/z` with `a \neq 0` EXAMPLES:: @@ -2102,7 +2102,7 @@ def revert(self): ... ValueError: cannot determine whether the compositional inverse exists - We look at some cases where the compositional inverse does not exist.: + We look at some cases where the compositional inverse does not exist: `f = 0`:: @@ -2115,7 +2115,7 @@ def revert(self): ... ValueError: compositional inverse does not exist - `val(f) ! = 1 and f(0) * f(1) = 0`:: + `val(f) ! = 1` and `f(0) * f(1) = 0`:: sage: (z^2).revert() Traceback (most recent call last): @@ -2126,7 +2126,6 @@ def revert(self): Traceback (most recent call last): ... ValueError: compositional inverse does not exist - """ P = self.parent() if self.valuation() == 1: @@ -2153,7 +2152,7 @@ def revert(self): raise ValueError("cannot determine whether the compositional inverse exists") def approximate_series(self, prec, name=None): - """ + r""" Return the Laurent series with absolute precision ``prec`` approximated from this series. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index e4148ef6047..75337c3a279 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -26,15 +26,14 @@ from sage.categories.rings import Rings from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields -from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields, CompleteDiscreteValuationRings +from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields from sage.misc.cachefunc import cached_method -from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.lazy_series import (LazyModuleElement, - LazyCauchyProductSeries, LazyLaurentSeries, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -983,7 +982,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._coeff_ring = base_ring # TODO: it would be good to have something better than the symbolic ring self._laurent_poly_ring = SR - self._internal_poly_ring = LaurentPolynomialRing(base_ring, names) + self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=True) category = Algebras(base_ring.category()) if base_ring in IntegralDomains(): @@ -1141,7 +1140,7 @@ def _an_element_(self): sage: L = LazyDirichletSeriesRing(ZZ, 'z') sage: L.an_element() - 1/(4^z) + 1/(5^z) + 1/(6^z) + ... + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) """ c = self.base_ring().an_element() return self.element_class(self, Stream_exact([], self._sparse, constant=c, order=4)) From 5a02ded00107f3a315147ec972382c45ec76da58 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 17 Sep 2021 14:08:31 +0200 Subject: [PATCH 189/355] fix regression --- src/sage/interfaces/fricas.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 16563a8e044..ed15c2bc7e9 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -205,7 +205,6 @@ from sage.docs.instancedoc import instancedoc from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity from sage.misc.lazy_import import lazy_import lazy_import('sage.libs.pynac.pynac', ['symbol_table', 'register_symbol']) lazy_import('sage.calculus.var', ['var', 'function']) @@ -213,10 +212,7 @@ FRICAS_CONSTANTS = {'%i': I, '%e': e, - '%pi': pi, - 'infinity': infinity, - 'plusInfinity': infinity, - 'minusInfinity': -infinity} + '%pi': pi} FRICAS_SINGLE_LINE_START = 3 # where output starts when it fits next to the line number FRICAS_MULTI_LINE_START = 2 # and when it doesn't @@ -591,7 +587,11 @@ def _register_symbols(): from sage.functions.other import abs from sage.functions.gamma import gamma from sage.misc.functional import symbolic_sum, symbolic_prod - register_symbol(pi, {'fricas': 'pi'}) # pi is also a function in fricas + from sage.rings.infinity import infinity + register_symbol(pi, {'fricas': 'pi'}) # %pi::INFORM is %pi, but (pi) also exists + register_symbol(lambda: infinity, {'fricas': 'infinity'}) # %infinity::INFORM is (infinity) + register_symbol(lambda: infinity, {'fricas': 'plusInfinity'}) # %plusInfinity::INFORM is (minusInfinity) + register_symbol(lambda: -infinity, {'fricas': 'minusInfinity'}) # %minusInfinity::INFORM is (minusInfinity) register_symbol(cos, {'fricas': 'cos'}) register_symbol(sin, {'fricas': 'sin'}) register_symbol(tan, {'fricas': 'tan'}) From 8b67f8b028c5ceb68514dd613ca3b088b679d44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 17 Sep 2021 14:36:25 +0200 Subject: [PATCH 190/355] adding doctests --- src/sage/schemes/projective/projective_point.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index 838e782af67..d252a63d692 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -706,6 +706,18 @@ def global_height(self, prec=None): sage: Q = P.point([K(4/3), K.gen(7), K.gen(5)]) sage: Q.global_height() 1.38629436111989 + + TESTS:: + + sage: P = ProjectiveSpace(QQ, 2) + sage: P(1/1,2/3,5/8).global_height() + log(24) + + sage: x = polygen(QQ, 'x') + sage: F. = NumberField(x^3 - 5) + sage: P = ProjectiveSpace(F, 2) + sage: P(u,u^2/5,1).global_height() + 1.07295860828940 """ if prec is None: prec = 53 From 82e30dce8070c28ff4dfaaca7c0f8cc03656c250 Mon Sep 17 00:00:00 2001 From: Mike Hansen Date: Sat, 18 Sep 2021 01:02:36 +0200 Subject: [PATCH 191/355] Trac #30602: Use Integer when creating Partition objects from ZS1_* iterators --- src/sage/combinat/partition.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 12b264a43cc..2f823fab37f 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -6655,9 +6655,15 @@ def __iter__(self): sage: [x for x in Partitions(4)] [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] + + TESTS:: + + sage: all(isinstance(i, Integer) for p in Partitions(4) for i in p) + True + """ for p in ZS1_iterator(self.n): - yield self.element_class(self, p) + yield self.element_class(self, [Integer(i) for i in p]) def subset(self, **kwargs): r""" @@ -6787,10 +6793,17 @@ def __iter__(self): ....: == number_of_partitions_length(n, k) ....: for n in range(9) for k in range(n+2) ) True + + TESTS:: + + sage: partitions = Partitions(9, length=3) + sage: all(isinstance(i, Integer) for p in partitions for i in p) + True + """ for p in ZS1_iterator_nk(self.n - self.k, self.k): - v = [i + 1 for i in p] - adds = [1] * (self.k - len(v)) + v = [Integer(i + 1) for i in p] + adds = [Integer(1)] * (self.k - len(v)) yield self.element_class(self, v + adds) def cardinality(self, algorithm='hybrid'): From 007700a609949e47d60b102bfac47d73d4a5cb7f Mon Sep 17 00:00:00 2001 From: Mike Hansen Date: Sat, 18 Sep 2021 04:04:11 +0200 Subject: [PATCH 192/355] Trac #30483: Use itertools to iterate through Combinations --- src/sage/combinat/combination.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 674c2c96ba2..38152061cd0 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -24,6 +24,8 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import itertools + from sage.rings.all import ZZ, Integer from sage.arith.all import binomial from .integer_vector import IntegerVectors @@ -421,24 +423,18 @@ def cardinality(self): class Combinations_setk(Combinations_msetk): - def _iterator(self, items, len_items, n): + def _iterator(self, items, n): """ An iterator for all the n-combinations of items. EXAMPLES:: - sage: it = Combinations([1,2,3,4],3)._iterator([1,2,3,4],4,3) + sage: it = Combinations([1,2,3,4],3)._iterator([1,2,3,4],3) sage: list(it) [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] """ - for i in range(len_items): - v = items[i: i + 1] - if n == 1: - yield v - else: - rest = items[i + 1:] - for c in self._iterator(rest, len_items - i - 1, n - 1): - yield v + c + for combination in itertools.combinations(items, n): + yield list(combination) def _iterator_zero(self): """ @@ -454,8 +450,8 @@ def _iterator_zero(self): def __iter__(self): r""" - Posted by Raymond Hettinger, 2006/03/23, to the Python Cookbook: - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/474124 + Uses Python's :func:`itertools.combinations` to iterate through all + of the combinations. EXAMPLES:: @@ -474,7 +470,7 @@ def __iter__(self): if self.k == 0: return self._iterator_zero() else: - return self._iterator(self.mset, len(self.mset), self.k) + return self._iterator(self.mset, self.k) def list(self): """ From e35065cf3af39d883e1d25ba741f3505287039a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 18 Sep 2021 11:49:16 +0200 Subject: [PATCH 193/355] now with numeric doctests --- src/sage/schemes/projective/projective_point.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index d252a63d692..7da8f254e31 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -675,14 +675,14 @@ def global_height(self, prec=None): sage: P. = ProjectiveSpace(QQ,2) sage: Q = P.point([4, 4, 1/30]) sage: Q.global_height() - log(120) + 4.78749174278205 :: sage: P. = ProjectiveSpace(ZZ,2) sage: Q = P([4, 1, 30]) sage: Q.global_height() - log(30) + 3.40119738166216 :: @@ -711,7 +711,7 @@ def global_height(self, prec=None): sage: P = ProjectiveSpace(QQ, 2) sage: P(1/1,2/3,5/8).global_height() - log(24) + 3.17805383034795 sage: x = polygen(QQ, 'x') sage: F. = NumberField(x^3 - 5) @@ -737,7 +737,7 @@ def global_height(self, prec=None): d = K.degree() if d == 1: height = max(abs(xi) for xi in x) / gcd(x) - return height.log() + return height.log().n(prec=prec) finite = ~sum(K.ideal(xi) for xi in x).norm() infinite = prod(max(abs(xi.complex_embedding(prec, i)) From 0f2e375438e22feee19998f03a2980407698c388 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 19:52:32 -0700 Subject: [PATCH 194/355] git grep -l 'all import ZZ' src/sage | xargs sed -i.bak 's/sage[.]rings[.]all import ZZ *$/sage.rings.integer_ring import ZZ/' --- src/sage/algebras/affine_nil_temperley_lieb.py | 2 +- src/sage/algebras/clifford_algebra.py | 2 +- src/sage/algebras/commutative_dga.py | 2 +- src/sage/algebras/hall_algebra.py | 2 +- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- src/sage/algebras/lie_algebras/free_lie_algebra.py | 2 +- src/sage/algebras/lie_algebras/lie_algebra.py | 2 +- src/sage/algebras/lie_algebras/onsager.py | 2 +- .../algebras/lie_algebras/rank_two_heisenberg_virasoro.py | 2 +- src/sage/algebras/lie_algebras/virasoro.py | 2 +- .../bosonic_ghosts_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/lie_conformal_algebra_element.py | 2 +- .../lie_conformal_algebras/weyl_lie_conformal_algebra.py | 2 +- src/sage/algebras/q_system.py | 2 +- src/sage/algebras/quantum_groups/fock_space.py | 2 +- src/sage/algebras/quantum_matrix_coordinate_algebra.py | 2 +- src/sage/algebras/yangian.py | 2 +- src/sage/categories/groups.py | 2 +- src/sage/categories/semigroups.py | 4 ++-- src/sage/coding/binary_code.pyx | 2 +- src/sage/combinat/alternating_sign_matrix.py | 2 +- src/sage/combinat/colored_permutations.py | 2 +- src/sage/combinat/composition.py | 2 +- src/sage/combinat/crystals/kac_modules.py | 2 +- src/sage/combinat/crystals/multisegments.py | 2 +- src/sage/combinat/crystals/tensor_product_element.pyx | 2 +- src/sage/combinat/cyclic_sieving_phenomenon.py | 2 +- src/sage/combinat/designs/incidence_structures.py | 2 +- src/sage/combinat/gelfand_tsetlin_patterns.py | 2 +- src/sage/combinat/hall_polynomial.py | 2 +- src/sage/combinat/integer_vector.py | 2 +- src/sage/combinat/integer_vector_weighted.py | 2 +- src/sage/combinat/k_tableau.py | 2 +- src/sage/combinat/matrices/latin.py | 2 +- src/sage/combinat/ncsf_qsym/combinatorics.py | 2 +- src/sage/combinat/ncsf_qsym/ncsf.py | 2 +- src/sage/combinat/ncsf_qsym/qsym.py | 2 +- src/sage/combinat/ncsym/ncsym.py | 2 +- src/sage/combinat/posets/moebius_algebra.py | 2 +- src/sage/combinat/q_analogues.py | 2 +- src/sage/combinat/root_system/cartan_matrix.py | 2 +- src/sage/combinat/root_system/cartan_type.py | 2 +- src/sage/combinat/root_system/integrable_representations.py | 2 +- src/sage/combinat/root_system/reflection_group_real.py | 2 +- src/sage/combinat/root_system/root_space.py | 2 +- src/sage/combinat/root_system/type_A.py | 2 +- src/sage/combinat/root_system/type_E.py | 2 +- src/sage/combinat/root_system/type_F.py | 2 +- src/sage/combinat/root_system/type_super_A.py | 2 +- .../combinat/root_system/weight_lattice_realizations.py | 4 ++-- src/sage/combinat/root_system/weyl_characters.py | 2 +- src/sage/combinat/sf/llt.py | 2 +- src/sage/combinat/species/cycle_species.py | 2 +- src/sage/combinat/species/permutation_species.py | 2 +- src/sage/combinat/super_tableau.py | 2 +- src/sage/combinat/superpartition.py | 2 +- src/sage/combinat/tableau.py | 4 ++-- src/sage/combinat/tuple.py | 2 +- .../dynamics/arithmetic_dynamics/product_projective_ds.py | 2 +- src/sage/functions/exp_integral.py | 2 +- src/sage/functions/special.py | 2 +- src/sage/game_theory/matching_game.py | 2 +- src/sage/geometry/cone_catalog.py | 6 +++--- src/sage/geometry/fan_isomorphism.py | 2 +- src/sage/geometry/polyhedron/backend_cdd.py | 2 +- src/sage/geometry/polyhedron/backend_ppl.py | 2 +- .../geometry/polyhedron/combinatorial_polyhedron/base.pyx | 2 +- .../polyhedron/combinatorial_polyhedron/list_of_faces.pyx | 2 +- src/sage/geometry/polyhedron/palp_database.py | 2 +- src/sage/geometry/polyhedron/representation.py | 2 +- src/sage/groups/abelian_gps/abelian_aut.py | 2 +- src/sage/groups/additive_abelian/additive_abelian_group.py | 2 +- .../groups/additive_abelian/additive_abelian_wrapper.py | 2 +- src/sage/groups/fqf_orthogonal.py | 2 +- src/sage/groups/matrix_gps/binary_dihedral.py | 2 +- src/sage/groups/matrix_gps/coxeter_group.py | 2 +- src/sage/groups/matrix_gps/finitely_generated.py | 2 +- src/sage/groups/matrix_gps/group_element.pyx | 2 +- src/sage/groups/matrix_gps/heisenberg.py | 2 +- src/sage/groups/matrix_gps/matrix_group.py | 2 +- src/sage/groups/matrix_gps/named_group.py | 2 +- src/sage/groups/matrix_gps/orthogonal.py | 2 +- src/sage/groups/perm_gps/permgroup.py | 2 +- src/sage/homology/koszul_complex.py | 2 +- src/sage/interfaces/axiom.py | 4 ++-- src/sage/interfaces/chomp.py | 2 +- src/sage/interfaces/macaulay2.py | 4 ++-- src/sage/interfaces/mwrank.py | 2 +- src/sage/libs/eclib/homspace.pyx | 2 +- src/sage/libs/eclib/mat.pyx | 2 +- src/sage/libs/flint/fmpz_poly.pyx | 2 +- src/sage/libs/gap/libgap.pyx | 2 +- src/sage/matrix/matrix1.pyx | 2 +- src/sage/matroids/matroid.pyx | 2 +- src/sage/modular/arithgroup/arithgroup_element.pyx | 2 +- src/sage/modular/arithgroup/arithgroup_generic.py | 2 +- src/sage/modular/arithgroup/arithgroup_perm.py | 2 +- src/sage/modular/arithgroup/congroup.pyx | 2 +- src/sage/modular/arithgroup/congroup_gamma1.py | 2 +- src/sage/modular/local_comp/liftings.py | 2 +- src/sage/modular/modform/ambient_R.py | 2 +- src/sage/modular/modform_hecketriangle/element.py | 2 +- src/sage/modular/modform_hecketriangle/subspace.py | 2 +- src/sage/modules/tensor_operations.py | 2 +- src/sage/monoids/free_abelian_monoid.py | 4 ++-- src/sage/monoids/free_monoid.py | 2 +- src/sage/monoids/indexed_free_monoid.py | 2 +- src/sage/numerical/linear_functions.pyx | 2 +- src/sage/quadratic_forms/constructions.py | 2 +- src/sage/quadratic_forms/random_quadraticform.py | 2 +- src/sage/quadratic_forms/ternary_qf.py | 2 +- src/sage/rings/function_field/function_field.py | 2 +- src/sage/rings/function_field/place.py | 2 +- src/sage/rings/ideal.py | 4 ++-- src/sage/rings/integer.pyx | 2 +- src/sage/rings/invariants/reconstruction.py | 2 +- src/sage/rings/number_field/class_group.py | 2 +- src/sage/rings/number_field/small_primes_of_degree_one.py | 2 +- src/sage/rings/padics/padic_valuation.py | 4 ++-- src/sage/rings/padics/pow_computer_flint.pyx | 2 +- src/sage/rings/padics/pow_computer_relative.pyx | 2 +- src/sage/rings/padics/relaxed_template.pxi | 2 +- src/sage/rings/polynomial/skew_polynomial_finite_field.pyx | 2 +- src/sage/rings/ring.pyx | 2 +- src/sage/rings/semirings/tropical_semiring.pyx | 2 +- src/sage/rings/valuation/gauss_valuation.py | 4 ++-- src/sage/rings/valuation/inductive_valuation.py | 2 +- src/sage/rings/valuation/valuation_space.py | 2 +- src/sage/rings/valuation/value_group.py | 4 ++-- src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx | 2 +- src/sage/schemes/elliptic_curves/saturation.py | 2 +- src/sage/schemes/generic/divisor.py | 2 +- src/sage/schemes/generic/homset.py | 2 +- src/sage/schemes/hyperelliptic_curves/invariants.py | 2 +- src/sage/schemes/projective/projective_subscheme.py | 2 +- src/sage/schemes/toric/homset.py | 2 +- src/sage/schemes/toric/morphism.py | 2 +- src/sage/schemes/toric/points.py | 2 +- src/sage/schemes/toric/sheaf/klyachko.py | 2 +- src/sage/schemes/toric/toric_subscheme.py | 2 +- src/sage/schemes/toric/weierstrass_covering.py | 2 +- src/sage/sets/primes.py | 2 +- src/sage/sets/real_set.py | 2 +- src/sage/structure/element.pyx | 2 +- src/sage/symbolic/ring.pyx | 4 ++-- src/sage/symbolic/tests.py | 2 +- 146 files changed, 159 insertions(+), 159 deletions(-) diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 4f38d110e1c..7115271eab9 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -11,7 +11,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.weyl_group import WeylGroup from sage.rings.ring import Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.cachefunc import cached_method diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dfb3ff479b6..9993f6cda68 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -25,7 +25,7 @@ from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.free_module import FreeModule, FreeModule_generic from sage.matrix.constructor import Matrix from sage.matrix.args import MatrixArgs diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index a5e5404bf9f..b4a0d7831ce 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -92,7 +92,7 @@ from sage.matrix.constructor import matrix from sage.modules.free_module import VectorSpace from sage.modules.free_module_element import vector -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.homset import RingHomset_generic from sage.rings.morphism import RingHomomorphism_im_gens from sage.rings.polynomial.term_order import TermOrder diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index 20b8b9c624c..a8ea8d18aff 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -20,7 +20,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.hall_polynomial import hall_polynomial from sage.combinat.sf.sf import SymmetricFunctions -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from functools import cmp_to_key, reduce diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index ae50b39a3e0..35cb17c9e65 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -26,7 +26,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.realizations import Realizations, Category_realization_of_parent from sage.categories.all import AlgebrasWithBasis, FiniteDimensionalAlgebrasWithBasis, CoxeterGroups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.arith.all import is_square from sage.combinat.root_system.coxeter_group import CoxeterGroup diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index 81acd327602..085a83e8120 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -42,7 +42,7 @@ from sage.algebras.lie_algebras.morphism import LieAlgebraHomomorphism_im_gens from sage.misc.superseded import experimental_warning -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class FreeLieBasis_abstract(FinitelyGeneratedLieAlgebra, IndexedGenerators, BindableClass): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index ad1a76d123f..fa683e3ee7f 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -30,7 +30,7 @@ from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.ring import Ring from sage.matrix.matrix_space import MatrixSpace from sage.sets.family import Family, AbstractFamily diff --git a/src/sage/algebras/lie_algebras/onsager.py b/src/sage/algebras/lie_algebras/onsager.py index 0368a1a32a0..32bf898f470 100644 --- a/src/sage/algebras/lie_algebras/onsager.py +++ b/src/sage/algebras/lie_algebras/onsager.py @@ -197,7 +197,7 @@ def basis(self): Lazy family (Onsager monomial(i))_{i in Disjoint union of Family (Integer Ring, Positive integers)} """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.positive_integers import PositiveIntegers I = DisjointUnionEnumeratedSets([ZZ, PositiveIntegers()], diff --git a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py index a208c5b5c1f..d0d2f0ec4ba 100644 --- a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +++ b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 90369cc0386..fbf29870f72 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras from sage.categories.modules import Modules -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.sets.family import Family from sage.sets.set import Set diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 47a7bb15823..b0e049a0c93 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -85,7 +85,7 @@ def __init__(self, R, ngens=2, names=None, index_set=None): sage: V = lie_conformal_algebras.BosonicGhosts(QQ) sage: TestSuite(V).run() """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ try: assert (ngens in ZZ and ngens > 0 and ngens % 2 == 0) except AssertionError: diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py index 31b68b23be3..3d244ca72ec 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py @@ -58,7 +58,7 @@ def T(self,n=1): sage: (L + 2*G.T() + 4*C).T(2) 2*T^(2)L + 12*T^(3)G """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if n not in ZZ or n < 0: raise ValueError("n must be a nonnegative Integer") if n == 0 or self.is_zero(): diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index 68e0841ec85..1f0ecb5b748 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -132,7 +132,7 @@ def __init__(self,R,ngens=None, gram_matrix=None, names=None, from sage.matrix.matrix_space import MatrixSpace if ngens: try: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ assert ngens in ZZ and ngens % 2 == 0 except AssertionError: raise ValueError("ngens needs to be an even positive "+ diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index 8103916d8f1..9f4f9b7367b 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -23,7 +23,7 @@ from sage.misc.misc_c import prod from sage.categories.algebras import Algebras -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index f3703018e02..33e9eb0d686 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -25,7 +25,7 @@ from sage.categories.modules_with_basis import ModulesWithBasis from sage.categories.realizations import Realizations, Category_realization_of_parent -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field import FractionField from sage.rings.finite_rings.integer_mod_ring import IntegerModRing diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 498aa34811d..f93f147758b 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -25,7 +25,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class QuantumMatrixCoordinateAlgebra_abstract(CombinatorialFreeModule): diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index f01eeb93cbe..1d6df948b18 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -22,7 +22,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 600572b671b..335cb4af368 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -514,7 +514,7 @@ def free(index_set=None, names=None, **kwds): sage: F. = Groups().Commutative().free(); F Multiplicative Abelian group isomorphic to Z x Z x Z """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if names is not None: if isinstance(names, str): if ',' not in names and index_set in ZZ: diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 49207666782..31da05bd00c 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -454,7 +454,7 @@ def trivial_representation(self, base_ring=None, side="twosided"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import TrivialRepresentation return TrivialRepresentation(self, base_ring) @@ -474,7 +474,7 @@ def regular_representation(self, base_ring=None, side="left"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import RegularRepresentation return RegularRepresentation(self, base_ring, side) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 056e3a51e63..d2450bfb601 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -4088,7 +4088,7 @@ cdef class BinaryCodeClassifier: for j from 0 <= j < B.nrows: temp_basis[j] = permute_word_by_wp(can_lab_inv, temp_basis[j]) from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.groups.perm_gps.constructor import PermutationGroupElement from sage.interfaces.gap import gap diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 7dc60852255..b5dc876693b 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -45,7 +45,7 @@ from sage.matrix.constructor import matrix from sage.modules.free_module_element import zero_vector from sage.misc.all import cached_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import factorial from sage.rings.integer import Integer from sage.combinat.posets.lattices import LatticePoset diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index eb139497a52..e291eabd08c 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -19,7 +19,7 @@ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.number_field.number_field import CyclotomicField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class ColoredPermutation(MultiplicativeGroupElement): diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 52cdc1010b0..930ae037346 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -36,7 +36,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from .combinat import CombinatorialElement from sage.categories.cartesian_product import cartesian_product diff --git a/src/sage/combinat/crystals/kac_modules.py b/src/sage/combinat/crystals/kac_modules.py index 51005ec5047..f6244cd4158 100644 --- a/src/sage/combinat/crystals/kac_modules.py +++ b/src/sage/combinat/crystals/kac_modules.py @@ -15,7 +15,7 @@ from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.categories.regular_supercrystals import RegularSuperCrystals from sage.combinat.crystals.tensor_product import CrystalOfTableaux diff --git a/src/sage/combinat/crystals/multisegments.py b/src/sage/combinat/crystals/multisegments.py index ca12ef818f4..7db77030117 100644 --- a/src/sage/combinat/crystals/multisegments.py +++ b/src/sage/combinat/crystals/multisegments.py @@ -20,7 +20,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.root_system.cartan_type import CartanType from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation): r""" diff --git a/src/sage/combinat/crystals/tensor_product_element.pyx b/src/sage/combinat/crystals/tensor_product_element.pyx index 8357f890ccd..d2d88740133 100644 --- a/src/sage/combinat/crystals/tensor_product_element.pyx +++ b/src/sage/combinat/crystals/tensor_product_element.pyx @@ -36,7 +36,7 @@ from sage.structure.parent cimport Parent from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.functions.other import ceil from sage.combinat.tableau import Tableau -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ ############################################################################## # Support classes diff --git a/src/sage/combinat/cyclic_sieving_phenomenon.py b/src/sage/combinat/cyclic_sieving_phenomenon.py index e4e64868730..023d123ab94 100644 --- a/src/sage/combinat/cyclic_sieving_phenomenon.py +++ b/src/sage/combinat/cyclic_sieving_phenomenon.py @@ -24,7 +24,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 66f2ef0891d..5d904202fa7 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1136,7 +1136,7 @@ def incidence_matrix(self): [0 1 1 1] """ from sage.matrix.constructor import Matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ A = Matrix(ZZ, self.num_points(), self.num_blocks(), sparse=True) for j, b in enumerate(self._blocks): for i in b: diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index a7c245f13ea..72ee0eb4d7f 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -45,7 +45,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.cachefunc import cached_method from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partitions from sage.combinat.tableau import Tableau, SemistandardTableaux from sage.combinat.combinatorial_map import combinatorial_map diff --git a/src/sage/combinat/hall_polynomial.py b/src/sage/combinat/hall_polynomial.py index 575087d7335..b2b36260ad0 100644 --- a/src/sage/combinat/hall_polynomial.py +++ b/src/sage/combinat/hall_polynomial.py @@ -17,7 +17,7 @@ #***************************************************************************** from sage.misc.all import prod -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partition from sage.combinat.q_analogues import q_binomial diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 6f785645b63..ea9be362fdc 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -42,7 +42,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.rings.infinity import PlusInfinity from sage.arith.all import binomial -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.semirings.all import NN from sage.rings.integer import Integer diff --git a/src/sage/combinat/integer_vector_weighted.py b/src/sage/combinat/integer_vector_weighted.py index 3f1e52c0a09..8f1b68ffe85 100644 --- a/src/sage/combinat/integer_vector_weighted.py +++ b/src/sage/combinat/integer_vector_weighted.py @@ -22,7 +22,7 @@ from sage.categories.sets_with_grading import SetsWithGrading from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.rings.integer import Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.integer_vector import IntegerVector from sage.combinat.words.word import Word from sage.combinat.permutation import Permutation diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 005f3504456..1e9e57b8d86 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -39,7 +39,7 @@ from sage.combinat.partition import Partition, Partitions from sage.combinat.root_system.weyl_group import WeylGroup from sage.combinat.core import Core -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.functions.generalized import sgn from sage.misc.flatten import flatten from sage.combinat.skew_partition import SkewPartition diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 765b2065cae..45be6c01400 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -130,7 +130,7 @@ # **************************************************************************** from sage.matrix.all import matrix -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.all import Integer from sage.matrix.matrix_integer_dense import Matrix_integer_dense from sage.groups.perm_gps.permgroup_element import PermutationGroupElement diff --git a/src/sage/combinat/ncsf_qsym/combinatorics.py b/src/sage/combinat/ncsf_qsym/combinatorics.py index e3662ff2912..35a2cc1eb7b 100644 --- a/src/sage/combinat/ncsf_qsym/combinatorics.py +++ b/src/sage/combinat/ncsf_qsym/combinatorics.py @@ -21,7 +21,7 @@ from sage.misc.cachefunc import cached_function from sage.combinat.composition import Composition, Compositions from sage.combinat.composition_tableau import CompositionTableaux -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ # The following might call for defining a morphism from ``structure diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index 2ab7a4c8f44..f145ecde76d 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -5013,7 +5013,7 @@ def _to_complete_transition_matrix(self, n): return (matrix([[]]), []) CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ MS = MatrixSpace(ZZ, len(CO)) return (MS([[number_of_SSRCT(al,be) for be in CO] for al in CO]).inverse(), CO) diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index f76f1891ad3..3a46c666078 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -2897,7 +2897,7 @@ def _from_monomial_transition_matrix(self, n): return (matrix([[]]), []) CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ MS = MatrixSpace(ZZ, len(CO)) M = MS([[number_of_SSRCT(al, be) for al in CO] for be in CO]) return (M.inverse_of_unit(), CO) diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index 95c46b177be..1a5caa8f2e7 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -29,7 +29,7 @@ from sage.combinat.sf.sf import SymmetricFunctions from sage.matrix.matrix_space import MatrixSpace from sage.sets.set import Set -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from functools import reduce def matchings(A, B): diff --git a/src/sage/combinat/posets/moebius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py index 539548bd55c..9ed121e66c2 100644 --- a/src/sage/combinat/posets/moebius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -26,7 +26,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class BasisAbstract(CombinatorialFreeModule, BindableClass): diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index a294575f775..02d284cb061 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -17,7 +17,7 @@ from sage.misc.cachefunc import cached_function from sage.misc.all import prod from sage.structure.element import parent -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.dyck_word import DyckWords from sage.combinat.partition import _Partitions diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 0a02a262f7c..0b0aac2306e 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -34,7 +34,7 @@ from sage.misc.classcall_metaclass import typecall from sage.misc.misc import powerset from sage.matrix.matrix_integer_sparse import Matrix_integer_sparse -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 8cc8bafa19e..ea50c75079e 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -479,7 +479,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method from sage.misc.lazy_import import LazyImport -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import Infinity from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 080bbf21971..de677e03deb 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -14,7 +14,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.category_object import CategoryObject from sage.categories.modules import Modules -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import Matrix from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index ac27b0e073f..310e9f5305b 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -46,7 +46,7 @@ from sage.misc.cachefunc import cached_function, cached_method, cached_in_parent_method from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.interfaces.gap3 import gap3 from sage.combinat.root_system.reflection_group_complex import ComplexReflectionGroup, IrreducibleComplexReflectionGroup from sage.misc.sage_eval import sage_eval diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 46215563e3d..42709ef1847 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -9,7 +9,7 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method, cached_in_parent_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.free_module import CombinatorialFreeModule from .root_lattice_realizations import RootLatticeRealizations import functools diff --git a/src/sage/combinat/root_system/type_A.py b/src/sage/combinat/root_system/type_A.py index f76cf3e9cbe..ef014e05d66 100644 --- a/src/sage/combinat/root_system/type_A.py +++ b/src/sage/combinat/root_system/type_A.py @@ -10,7 +10,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations from . import ambient_space diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 7c910ecab6d..5c49a148806 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -12,7 +12,7 @@ # **************************************************************************** from . import ambient_space -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.family import Family class AmbientSpace(ambient_space.AmbientSpace): diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index f7b9dbcf667..744ef0547bb 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -12,7 +12,7 @@ # **************************************************************************** from . import ambient_space -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.family import Family # TODO: double check that this can't be defined over ZZ diff --git a/src/sage/combinat/root_system/type_super_A.py b/src/sage/combinat/root_system/type_super_A.py index 17cf933e14c..1bbbbfdcbff 100644 --- a/src/sage/combinat/root_system/type_super_A.py +++ b/src/sage/combinat/root_system/type_super_A.py @@ -11,7 +11,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from . import ambient_space from .cartan_type import SuperCartanType_standard diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index 033152d42ec..e8ae792ecaf 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -215,7 +215,7 @@ def __init_extra__(self): The embeddings are systematically tested in :meth:`_test_weight_lattice_realization`. """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from .weight_space import WeightSpace K = self.base_ring() # If self is the root lattice or the root space, we don't want @@ -247,7 +247,7 @@ def _test_weight_lattice_realization(self, **options): sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization() """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ tester = self._tester(**options) Lambda = self.fundamental_weights() alphacheck = self.simple_coroots() diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 977d191646d..22a7eca5513 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -18,7 +18,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.misc.functional import is_even -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class WeylCharacterRing(CombinatorialFreeModule): diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index d7e4af8fe94..01302cff7d3 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -33,7 +33,7 @@ from . import sfa import sage.combinat.ribbon_tableau as ribbon_tableau import sage.combinat.skew_partition -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partition, Partitions, _Partitions from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index ba41b643d73..83c82fc44a3 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -16,7 +16,7 @@ from .structure import GenericSpeciesStructure from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import divisors, euler_phi from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 57b282e211b..d8ae5c216ea 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -20,7 +20,7 @@ from .structure import GenericSpeciesStructure from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/super_tableau.py b/src/sage/combinat/super_tableau.py index 27affb9aeb5..a6db36f2319 100644 --- a/src/sage/combinat/super_tableau.py +++ b/src/sage/combinat/super_tableau.py @@ -23,7 +23,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family from sage.structure.parent import Parent from sage.rings.integer import Integer diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index b7658bcbe02..3de4852411d 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -86,7 +86,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.rings.integer import Integer from sage.structure.global_options import GlobalOptions -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index ab24316debc..cd0d38681da 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1125,7 +1125,7 @@ def to_sign_matrix(self, max_entry=None): ... ValueError: the entries must be non-negative integers """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.sets.positive_integers import PositiveIntegers PI = PositiveIntegers() for row in self: @@ -6439,7 +6439,7 @@ def random_element(self): sage: SemistandardTableaux(6, max_entry=7).random_element() # random [[2, 4, 4, 6, 6, 6]] """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import diagonal_matrix from sage.combinat.rsk import RSK kchoose2m1 = self.max_entry * (self.max_entry - 1) // 2 - 1 diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index ae380274f1a..9b773e0be70 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -17,7 +17,7 @@ # **************************************************************************** from sage.libs.gap.libgap import libgap -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py index 74f05820b49..825fdf9187a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py @@ -27,7 +27,7 @@ from copy import copy from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem from sage.dynamics.arithmetic_dynamics.projective_ds import DynamicalSystem_projective -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.quotient_ring import QuotientRing_generic from sage.schemes.product_projective.morphism import ProductProjectiveSpaces_morphism_ring diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index b20f7779f1a..4a1a897ade0 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -55,7 +55,7 @@ mpmath_utils_call = mpmath_utils.call # eliminate some overhead in _evalf_ from sage.rings.real_mpfr import RealField -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.functions.log import exp, log from sage.functions.trig import sin, cos from sage.functions.hyperbolic import sinh, cosh diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index d48208a21d0..21d8c67c607 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -161,7 +161,7 @@ from sage.rings.integer import Integer from sage.rings.complex_mpfr import ComplexField from sage.misc.latex import latex -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.symbolic.constants import pi from sage.symbolic.function import BuiltinFunction from sage.libs.mpmath import utils as mpmath_utils diff --git a/src/sage/game_theory/matching_game.py b/src/sage/game_theory/matching_game.py index b35f80c4b2f..8dcd3eb14a2 100644 --- a/src/sage/game_theory/matching_game.py +++ b/src/sage/game_theory/matching_game.py @@ -20,7 +20,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from copy import deepcopy from sage.graphs.bipartite_graph import BipartiteGraph diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index 94e4c136bb6..005f341e353 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -237,7 +237,7 @@ def nonnegative_orthant(ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) @@ -466,7 +466,7 @@ def rearrangement(p, ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) @@ -599,7 +599,7 @@ def schur(ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index 18a6c9b199a..a66d9ac6fd7 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -11,7 +11,7 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import column_matrix, matrix from sage.geometry.cone import Cone diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index d839bc3ca5e..7b48eb7b45b 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -16,7 +16,7 @@ from subprocess import Popen, PIPE -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 69702213084..3ac2bb267f7 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -3,7 +3,7 @@ """ from sage.structure.element import Element -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.arith.functions import LCM_list from sage.misc.functional import denominator diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 05cbd28ae2f..d4eac87cee0 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1096,7 +1096,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C.incidence_matrix().base_ring() Integer Ring """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix cdef Matrix_integer_dense incidence_matrix = matrix( ZZ, self.n_Vrepresentation(), self.n_Hrepresentation(), 0) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 98b3d4df828..5ea9711090d 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -477,7 +477,7 @@ cdef class ListOfFaces: sage: facets.matrix().transpose() == Vrep.matrix() True """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix cdef Matrix_integer_dense M = matrix( ZZ, self.n_faces(), self.n_atoms(), 0) diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 158ea5c38ca..a9bd90eca8b 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -33,7 +33,7 @@ from subprocess import Popen, PIPE from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.interfaces.process import terminate diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 1fcefddd53b..a5c4f73bd4f 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -17,7 +17,7 @@ from sage.structure.sage_object import SageObject from sage.structure.element import is_Vector from sage.structure.richcmp import richcmp_method, richcmp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector from copy import copy diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index a4ad9f41524..18afe029eda 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -82,7 +82,7 @@ from sage.groups.libgap_mixin import GroupMixinLibGAP from sage.libs.gap.libgap import libgap from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.unique_representation import CachedRepresentation diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 2c76b75e0cd..d94255e2d3f 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -9,7 +9,7 @@ from sage.groups.old import AbelianGroup from sage.modules.fg_pid.fgp_module import FGP_Module_class from sage.modules.fg_pid.fgp_element import FGP_Element -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def AdditiveAbelianGroup(invs, remember_generators = True): r""" diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index b27c8a8f1a0..566a07c4d33 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -50,7 +50,7 @@ """ from . import additive_abelian_group as addgp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.categories.morphism import Morphism from sage.structure.element import parent from sage.modules.free_module_element import vector diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index ae9fc2fae2d..b4ac8242f96 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -51,7 +51,7 @@ from sage.libs.gap.libgap import libgap from sage.groups.abelian_gps.abelian_aut import AbelianGroupAutomorphismGroup_subgroup, AbelianGroupAutomorphism, AbelianGroupAutomorphismGroup_gap from sage.modules.torsion_quadratic_module import TorsionQuadraticModule -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.all import matrix from sage.categories.action import Action diff --git a/src/sage/groups/matrix_gps/binary_dihedral.py b/src/sage/groups/matrix_gps/binary_dihedral.py index 44b2d3ef729..0edae3511c2 100644 --- a/src/sage/groups/matrix_gps/binary_dihedral.py +++ b/src/sage/groups/matrix_gps/binary_dihedral.py @@ -21,7 +21,7 @@ from sage.rings.number_field.number_field import CyclotomicField from sage.matrix.matrix_space import MatrixSpace from sage.categories.groups import Groups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class BinaryDihedralGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index ec8db50992e..3a2781d8c24 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -27,7 +27,7 @@ from sage.matrix.args import SparseEntry from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField from sage.rings.number_field.number_field import QuadraticField, is_QuadraticField diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index a69e5bfd325..d4d9849684d 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -62,7 +62,7 @@ # https://www.gnu.org/licenses/ ############################################################################## -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.all import QQbar from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 1bf2b88e6d5..d15e2a6802b 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -84,7 +84,7 @@ from sage.groups.libgap_wrapper cimport ElementLibGAP from sage.structure.element import is_Matrix from sage.structure.factorization import Factorization from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ cpdef is_MatrixGroupElement(x): diff --git a/src/sage/groups/matrix_gps/heisenberg.py b/src/sage/groups/matrix_gps/heisenberg.py index 4fefcd47ebb..bec87b2cc1a 100644 --- a/src/sage/groups/matrix_gps/heisenberg.py +++ b/src/sage/groups/matrix_gps/heisenberg.py @@ -22,7 +22,7 @@ from sage.matrix.matrix_space import MatrixSpace from sage.categories.groups import Groups from sage.categories.rings import Rings -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from copy import copy class HeisenbergGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 19536eace9a..e82abf76246 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -364,7 +364,7 @@ def sign_representation(self, base_ring=None, side="twosided"): 2*B['v'] """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationMatrixGroup return SignRepresentationMatrixGroup(self, base_ring) diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 38f7de9b02c..39bb43c710a 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -97,7 +97,7 @@ def normalize_args_vectorspace(*args, **kwds): sage: normalize_args_vectorspace(2, QQ) (2, Rational Field) """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if len(args) == 1: V = args[0] try: diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 4896cd64b81..f049e7b21a1 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -84,7 +84,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_base import is_FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 719be201a98..10cf6c1aebf 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -4727,7 +4727,7 @@ def sign_representation(self, base_ring=None, side="twosided"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationPermgroup return SignRepresentationPermgroup(self, base_ring) diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index 83cbe9dd243..c83605db2f5 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -16,7 +16,7 @@ from sage.structure.parent import Parent from sage.combinat.combination import rank from sage.arith.all import binomial -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex_class diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 22ed05c8606..09016ab1f67 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -844,7 +844,7 @@ def _sage_(self): from sage.rings.all import RDF return RDF(repr(self)) elif type in ["PositiveInteger", "Integer"]: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(repr(self)) elif type.startswith('Polynomial'): from sage.rings.all import PolynomialRing @@ -886,7 +886,7 @@ def _sage_domain(self): P = self._check_valid() name = str(self) if name == 'Integer': - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ elif name == 'DoubleFloat': from sage.rings.all import RDF diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index 00f4b3f93b3..cd1fc546b97 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -834,7 +834,7 @@ def process_generators_chain(gen_string, dim, base_ring=None): [(1, 1), (0, 0, 1)] """ from sage.modules.all import vector - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if base_ring is None: base_ring = ZZ # each dim in gens starts with a string like diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 64dd877ab05..27fa95f9b9c 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1540,7 +1540,7 @@ def _sage_(self): cls_cls_str = str(self.cls().cls()) if repr_str == "ZZ": - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ elif repr_str == "QQ": from sage.rings.all import QQ @@ -1659,7 +1659,7 @@ def _sage_(self): else: #Handle the integers and rationals separately if cls_str == "ZZ": - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(repr_str) elif cls_str == "QQ": from sage.rings.all import QQ diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index 1bab65a9174..636b7d6d961 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -123,7 +123,7 @@ def validate_mwrank_input(s): """ if isinstance(s,(list,tuple)): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if len(s)!=5: raise ValueError("%s is not valid input to mwrank (should have 5 entries)" % s) try: diff --git a/src/sage/libs/eclib/homspace.pyx b/src/sage/libs/eclib/homspace.pyx index b891d77fb8f..5efc6050723 100644 --- a/src/sage/libs/eclib/homspace.pyx +++ b/src/sage/libs/eclib/homspace.pyx @@ -10,7 +10,7 @@ from .mat cimport MatrixFactory from sage.matrix.all import MatrixSpace from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer cdef MatrixFactory MF = MatrixFactory() diff --git a/src/sage/libs/eclib/mat.pyx b/src/sage/libs/eclib/mat.pyx index 9cd06f9b344..d740a695654 100644 --- a/src/sage/libs/eclib/mat.pyx +++ b/src/sage/libs/eclib/mat.pyx @@ -5,7 +5,7 @@ Cremona matrices from ..eclib cimport scalar, addscalar from sage.matrix.all import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense diff --git a/src/sage/libs/flint/fmpz_poly.pyx b/src/sage/libs/flint/fmpz_poly.pyx index 97338c79cad..ba7f81d7143 100644 --- a/src/sage/libs/flint/fmpz_poly.pyx +++ b/src/sage/libs/flint/fmpz_poly.pyx @@ -454,6 +454,6 @@ cdef class Fmpz_poly(SageObject): sage: Fmpz_poly([-1,0,0,1])._sage_() x^3 - 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ[var](self.list()) diff --git a/src/sage/libs/gap/libgap.pyx b/src/sage/libs/gap/libgap.pyx index 3db0bbfded8..9f9f62be13a 100644 --- a/src/sage/libs/gap/libgap.pyx +++ b/src/sage/libs/gap/libgap.pyx @@ -217,7 +217,7 @@ from .element cimport * from sage.structure.parent cimport Parent from sage.structure.element cimport Vector -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from sage.misc.randstate cimport current_randstate diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 80b6d583d19..5c6f8a0f324 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -2393,7 +2393,7 @@ cdef class Matrix(Matrix0): :meth:`get_is_zero_unsafe` for derived matrix classes. """ if ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ ring = ZZ cdef object zero = ring.zero() diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 511435f6a35..4cd886ba16b 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -339,7 +339,7 @@ from sage.graphs.graph import Graph from sage.matrix.constructor import matrix from .utilities import newlabel, sanitize_contractions_deletions, spanning_forest, spanning_stars -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.numerical.mip import MixedIntegerLinearProgram from sage.matroids.lean_matrix cimport BinaryMatrix, TernaryMatrix diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 61875fc6161..1fff86aa7ab 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -16,7 +16,7 @@ Elements of Arithmetic Subgroups from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element from sage.structure.richcmp cimport richcmp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modular.cusps import Cusp from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index a2a97d403d9..bb7973f64cc 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -15,7 +15,7 @@ from sage.groups.old import Group from sage.categories.groups import Groups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import lcm from sage.misc.cachefunc import cached_method from copy import copy # for making copies of lists of cusps diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 5ea925b2a0d..fc70a66e4e1 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -100,7 +100,7 @@ from .all import SL2Z from .arithgroup_generic import ArithmeticSubgroup -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method import sage.arith.all as arith diff --git a/src/sage/modular/arithgroup/congroup.pyx b/src/sage/modular/arithgroup/congroup.pyx index cc6c8a557c0..e30a9daf5c9 100644 --- a/src/sage/modular/arithgroup/congroup.pyx +++ b/src/sage/modular/arithgroup/congroup.pyx @@ -27,7 +27,7 @@ arith_int = sage.rings.fast_arith.arith_int() from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.modular.modsym.p1list import lift_to_sl2z from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ Mat2Z = MatrixSpace(ZZ,2) cdef Matrix_integer_dense genS, genT, genI diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index c6f1024ba92..c73e55d1856 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -16,7 +16,7 @@ from sage.misc.all import prod from .congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import euler_phi as phi, moebius, divisors from sage.modular.dirichlet import DirichletGroup diff --git a/src/sage/modular/local_comp/liftings.py b/src/sage/modular/local_comp/liftings.py index f629bc659b0..e862031f4b2 100644 --- a/src/sage/modular/local_comp/liftings.py +++ b/src/sage/modular/local_comp/liftings.py @@ -6,7 +6,7 @@ problems. """ -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import crt, inverse_mod from sage.modular.modsym.p1list import lift_to_sl2z diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index 97ac8ef61eb..a09a61f1b39 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -12,7 +12,7 @@ from . import ambient from .cuspidal_submodule import CuspidalSubmodule_R -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method class ModularFormsAmbient_R(ambient.ModularFormsAmbient): diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index fc9a11523d5..4f8114f1125 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -284,7 +284,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): sage: L(10).n(53) -23.9781792831... """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.symbolic.all import pi from sage.functions.other import sqrt from sage.lfunctions.dokchitser import Dokchitser diff --git a/src/sage/modular/modform_hecketriangle/subspace.py b/src/sage/modular/modform_hecketriangle/subspace.py index de082946919..50a5eb10337 100644 --- a/src/sage/modular/modform_hecketriangle/subspace.py +++ b/src/sage/modular/modform_hecketriangle/subspace.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.module import Module from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index 16eb8717e36..9c943262319 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -66,7 +66,7 @@ from sage.modules.free_module import FreeModule_ambient_field from sage.misc.all import prod from sage.matrix.constructor import matrix -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def symmetrized_coordinate_sums(dim, n): diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index f07eb143c50..288436ab56a 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -60,7 +60,7 @@ from sage.categories.monoids import Monoids from .free_abelian_monoid_element import FreeAbelianMonoidElement from sage.rings.integer import Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.factory import UniqueFactory @@ -303,7 +303,7 @@ def cardinality(self): +Infinity """ if self.__ngens == 0: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() from sage.rings.infinity import infinity return infinity diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index f132af2a8d4..9855e5e1a84 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -33,7 +33,7 @@ from sage.combinat.words.finite_word import FiniteWord_class from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def is_FreeMonoid(x): diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 144a9579072..69168f1e1bd 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -28,7 +28,7 @@ from sage.categories.sets_cat import Sets from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 6d0c0604c37..38200304e79 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -1075,7 +1075,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): if coeff == R.one() and not constant_term: return '' try: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ coeff = ZZ(coeff) # print as integer if possible except (TypeError, ValueError): pass diff --git a/src/sage/quadratic_forms/constructions.py b/src/sage/quadratic_forms/constructions.py index 8d892b45d08..cf7460c1f88 100644 --- a/src/sage/quadratic_forms/constructions.py +++ b/src/sage/quadratic_forms/constructions.py @@ -5,7 +5,7 @@ ## Some extra routines to make the QuadraticForm class more useful. ## -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.quadratic_forms.quadratic_form import QuadraticForm diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index 371d89a2a59..7a980bf6d4f 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -4,7 +4,7 @@ from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.quadratic_forms.ternary_qf import TernaryQF from sage.rings.ring import is_Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ ################################################ ## Routines to create a random quadratic form ## diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index bb44c44cde6..da426c84395 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -27,7 +27,7 @@ # **************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import gcd, kronecker_symbol from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index b7d7c1127fb..6c2945fbc64 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -3402,7 +3402,7 @@ def L_polynomial(self, name='t'): sage: F.L_polynomial() 2*t^2 + t + 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ q = self.constant_field().order() g = self.genus() diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index d95b0d84ef9..43abc67a6fb 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -59,7 +59,7 @@ from sage.arith.all import lcm -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.qqbar import QQbar from sage.rings.number_field.number_field_base import NumberField diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 53076ac62ed..3a135b8f982 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -693,7 +693,7 @@ def is_maximal(self): sage: S.ideal(4).is_maximal() False """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ: # The following test only works for quotients of Z/nZ: for @@ -821,7 +821,7 @@ def is_prime(self): For general rings, uses the list of associated primes. """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ and R.is_finite(): # For quotient rings of ZZ, prime is the same as maximal. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 12f4124655c..4e79c64fca6 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3227,7 +3227,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if self.parent() is ZZ: return abs(self) raise NotImplementedError diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index 321b7705868..b9db4e07521 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -375,7 +375,7 @@ def _reduce_invariants(invariants, weights): sage: _reduce_invariants(invariants, weights) [3, 75, 250] """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ factors = [dict(I.factor()) for I in invariants] scalar = ZZ(1) n = len(weights) diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index d0468a3c2d2..34e801aad2a 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -44,7 +44,7 @@ from sage.groups.abelian_gps.values import AbelianGroupWithValues_class, AbelianGroupWithValuesElement from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement from sage.structure.element import MonoidElement -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class FractionalIdealClass(AbelianGroupWithValuesElement): diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index 235cdd63549..93cb7d97f70 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -99,7 +99,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class Small_primes_of_degree_one_iter(): r""" diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index f47f1d8de5b..c489221589f 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -148,7 +148,7 @@ def create_key_for_integers(self, R, prime): 2-adic valuation """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if prime is None: raise ValueError("prime must be specified for this ring") from sage.rings.valuation.valuation import DiscretePseudoValuation @@ -462,7 +462,7 @@ def __init__(self, parent, p): """ DiscreteValuation.__init__(self, parent) - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ self._p = ZZ(p) def p(self): diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index 3868c11a6f7..4d64096e4ee 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -17,7 +17,7 @@ from sage.libs.flint.fmpz cimport fmpz_init, fmpz_one, fmpz_mul, fmpz_set, fmpz_ from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport richcmp_not_equal from sage.rings.integer cimport Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint diff --git a/src/sage/rings/padics/pow_computer_relative.pyx b/src/sage/rings/padics/pow_computer_relative.pyx index d80419863bb..f28a46f03b7 100644 --- a/src/sage/rings/padics/pow_computer_relative.pyx +++ b/src/sage/rings/padics/pow_computer_relative.pyx @@ -36,7 +36,7 @@ from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_pow_ui from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport richcmp_not_equal from sage.rings.integer cimport Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method cdef class PowComputer_relative(PowComputer_class): diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 48a0468bc91..6c155e1c8a3 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -43,7 +43,7 @@ from sage.structure.element cimport have_same_parent from sage.structure.coerce cimport coercion_model from sage.misc.prandom import randint -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.rings.infinity import Infinity diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 7ae80a01254..bb7fd4275cd 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -27,7 +27,7 @@ AUTHOR:: from sage.structure.element cimport parent from sage.rings.ring cimport Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.matrix.matrix_space import MatrixSpace from sage.matrix.matrix2 import NotFullRankError diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 0be5b7f5d3e..7cc9c6d3f70 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -1113,7 +1113,7 @@ cdef class Ring(ParentWithGens): for P, e in f.factor(): if P.degree() == 1: return -P[0] - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ raise ValueError("no %s root of unity in %r" % (ZZ(n).ordinal_str(), self)) def zeta_order(self): diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index ab9e785b7f0..8466b9c47b0 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -28,7 +28,7 @@ from sage.structure.richcmp cimport rich_to_bool from sage.categories.semirings import Semirings from sage.categories.map cimport Map from sage.sets.family import Family -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ import operator diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 3730c21ba22..b1758aa6ea6 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -491,7 +491,7 @@ def E(self): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() def F(self): @@ -508,7 +508,7 @@ def F(self): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() def change_domain(self, ring): diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index 5cafb68bfff..c5749796737 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -901,7 +901,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a verbose("Augmented %s to %s"%(self, w), level=13) assert slope is -infinity or 0 in w.newton_polygon(G).slopes(repetition=False) - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ assert (phi.degree() / self.phi().degree()) in ZZ degree_bound = multiplicities[slope] * phi.degree() assert degree_bound <= G.degree() diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index f64072338b5..a4ace6dbece 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -918,7 +918,7 @@ def shift(self, x, s): x^2 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ x = self.domain().coerce(x) s = self.value_group()(s) if s == 0: diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index a3981336668..bc5d0840df1 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -531,7 +531,7 @@ def _solve_linear_program(self, target): return {0 : exp} if len(self._generators) == 2 and self._generators[0] == - self._generators[1]: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ exp = target / self._generators[0] if exp not in ZZ: return None @@ -679,7 +679,7 @@ def some_elements(self): return for g in self._generators: yield g - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ for x in (ZZ**len(self._generators)).some_elements(): yield QQ.coerce(sum([abs(c)*g for c,g in zip(x,self._generators)])) diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 3868c0a73b7..1cc70925faf 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -17,7 +17,7 @@ Descent on elliptic curves over `\QQ` with a 2-isogeny from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen cdef object x_ZZ = polygen(ZZ) from sage.rings.polynomial.real_roots import real_roots diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index f4612b287c7..7befb02a772 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -51,7 +51,7 @@ #***************************************************************************** from sage.rings.finite_rings.all import GF -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import kronecker_symbol as kro from sage.structure.sage_object import SageObject diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py index 32f8077c12b..01450320948 100644 --- a/src/sage/schemes/generic/divisor.py +++ b/src/sage/schemes/generic/divisor.py @@ -43,7 +43,7 @@ from sage.misc.latex import latex from sage.misc.repr import repr_lincomb from sage.misc.search import search -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.formal_sum import FormalSum from .morphism import is_SchemeMorphism diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index b97d2d61e5e..a1aa946614e 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -40,7 +40,7 @@ from sage.structure.factory import UniqueFactory from sage.structure.parent import Set_generic -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.ring import CommutativeRing from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index 4274bd90cc6..29634192e46 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -13,7 +13,7 @@ - Nick Alexander """ -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.all import PolynomialRing diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 8b91a17accf..abeeda9799b 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -28,7 +28,7 @@ from sage.matrix.constructor import matrix -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import is_RationalField diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index f13482bae0c..88516ae0b5e 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -107,7 +107,7 @@ from sage.categories.finite_fields import FiniteFields -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 0d8ed6f20d0..7e891014a65 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -369,7 +369,7 @@ from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.structure.sequence import Sequence -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import gcd from sage.misc.all import cached_method from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 2ea3067e8ab..81e7bfc8a03 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -676,7 +676,7 @@ def cone_points_iter(self): [(0, 0), (0, 1)] """ from sage.matrix.constructor import matrix, block_matrix, identity_matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ nrays = len(self.rays()) N = self.multiplicative_group_order() # Want cokernel of the log rescalings in (ZZ/N)^(#rays). But diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 1ed3ac290b4..d7e933efa84 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -47,7 +47,7 @@ from sage.structure.all import SageObject from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import vector, block_matrix, zero_matrix from sage.geometry.cone import is_Cone diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 29bf06672dc..78a31099445 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -21,7 +21,7 @@ #***************************************************************************** from sage.calculus.functions import jacobian -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme): diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 9a631813c1a..4689d47f789 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -104,7 +104,7 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.all import vector from sage.rings.all import invariant_theory from sage.schemes.toric.weierstrass import ( diff --git a/src/sage/sets/primes.py b/src/sage/sets/primes.py index 0b8f99a3642..89cf22eef56 100644 --- a/src/sage/sets/primes.py +++ b/src/sage/sets/primes.py @@ -14,7 +14,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from .set import Set_generic from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.arith.all import nth_prime diff --git a/src/sage/sets/real_set.py b/src/sage/sets/real_set.py index 0c9d276edf2..d271ec56a07 100644 --- a/src/sage/sets/real_set.py +++ b/src/sage/sets/real_set.py @@ -91,7 +91,7 @@ class RealSet. from sage.categories.topological_spaces import TopologicalSpaces from sage.categories.sets_cat import EmptySetError from sage.sets.set import Set_base, Set_boolean_operators, Set_add_sub_operators -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.real_lazy import LazyFieldElement, RLF from sage.rings.infinity import infinity, minus_infinity diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index d610bbb71cc..7cdddb22644 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -4223,7 +4223,7 @@ def is_InfinityElement(x): cdef class InfinityElement(RingElement): def __invert__(self): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(0) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 80860d9afb9..3047fce842e 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -31,7 +31,7 @@ from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ # is_SymbolicVariable used to be defined here; re-export it from sage.symbolic.expression import _is_SymbolicVariable as is_SymbolicVariable @@ -1192,7 +1192,7 @@ cdef class NumpyToSRMorphism(Morphism): import numpy if issubclass(numpy_type, numpy.integer): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ self._intermediate_ring = ZZ elif issubclass(numpy_type, numpy.floating): from sage.rings.all import RDF diff --git a/src/sage/symbolic/tests.py b/src/sage/symbolic/tests.py index 8cd32c4eba7..b09ae5cc4b8 100644 --- a/src/sage/symbolic/tests.py +++ b/src/sage/symbolic/tests.py @@ -29,7 +29,7 @@ def rational_powers_memleak(): sage: rational_powers_memleak() False """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ import gc gc.collect() c0 = sum(1 for obj in gc.get_objects()) From 8a9ae7d39167f6382cfdfd477212dae854f5bc19 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 19:55:14 -0700 Subject: [PATCH 195/355] git grep -l 'all import QQ' src/sage | xargs sed -i.bak 's/sage[.]rings[.]all import QQ *$/sage.rings.rational_field import QQ/' --- src/sage/algebras/rational_cherednik_algebra.py | 2 +- src/sage/algebras/yokonuma_hecke_algebra.py | 2 +- src/sage/categories/loop_crystals.py | 2 +- src/sage/combinat/crystals/affine_factorization.py | 2 +- src/sage/combinat/crystals/kirillov_reshetikhin.py | 2 +- src/sage/combinat/crystals/littelmann_path.py | 2 +- .../combinat/rigged_configurations/bij_type_A2_dual.py | 2 +- .../rigged_configurations/rigged_configurations.py | 2 +- src/sage/combinat/root_system/branching_rules.py | 2 +- src/sage/combinat/root_system/cartan_matrix.py | 2 +- .../combinat/root_system/weight_lattice_realizations.py | 2 +- src/sage/combinat/sf/macdonald.py | 2 +- src/sage/combinat/species/recursive_species.py | 2 +- src/sage/combinat/species/species.py | 2 +- src/sage/combinat/subword_complex.py | 4 ++-- src/sage/combinat/words/morphism.py | 2 +- src/sage/game_theory/normal_form_game.py | 2 +- src/sage/geometry/polyhedron/base_QQ.py | 2 +- src/sage/geometry/polyhedron/double_description.py | 2 +- .../polyhedron/double_description_inhomogeneous.py | 4 ++-- src/sage/interfaces/macaulay2.py | 4 ++-- src/sage/interfaces/octave.py | 2 +- src/sage/interfaces/polymake.py | 2 +- src/sage/misc/random_testing.py | 4 ++-- src/sage/modular/abvar/abvar_ambient_jacobian.py | 2 +- src/sage/modular/abvar/torsion_point.py | 2 +- src/sage/modular/modform/j_invariant.py | 2 +- src/sage/modular/modsym/heilbronn.pyx | 8 ++++---- src/sage/numerical/backends/interactivelp_backend.pyx | 2 +- src/sage/numerical/backends/logging_backend.py | 4 ++-- src/sage/numerical/backends/matrix_sdp_backend.pyx | 2 +- src/sage/numerical/backends/ppl_backend.pyx | 4 ++-- src/sage/rings/function_field/function_field_valuation.py | 4 ++-- src/sage/rings/number_field/morphism.py | 2 +- src/sage/rings/padics/padic_valuation.py | 2 +- src/sage/rings/polynomial/multi_polynomial_ideal.py | 2 +- src/sage/rings/valuation/gauss_valuation.py | 2 +- src/sage/schemes/elliptic_curves/ell_egros.py | 2 +- src/sage/schemes/elliptic_curves/ell_field.py | 2 +- src/sage/schemes/elliptic_curves/saturation.py | 2 +- src/sage/schemes/toric/divisor_class.pyx | 2 +- src/sage/symbolic/constants.py | 2 +- src/sage/symbolic/random_tests.py | 2 +- 43 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index 7d7e9f7929f..880a7112b8e 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -19,7 +19,7 @@ from sage.sets.family import Family from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class RationalCherednikAlgebra(CombinatorialFreeModule): diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 33c432bef41..976b6e448e9 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -18,7 +18,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.categories.algebras import Algebras from sage.categories.rings import Rings from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 06bd9f55a17..06e7a4eae50 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -855,7 +855,7 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): True """ if q is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ q = QQ['q'].gens()[0] P0 = self.weight_lattice_realization().classical() B = P0.algebra(q.parent()) diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index 9b4d2be0a4e..e273a5c09c2 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -152,7 +152,7 @@ def __init__(self, w, n, x = None): cartan_type = CartanType(['A',n-1]) self._cartan_type = cartan_type from sage.combinat.sf.sf import SymmetricFunctions - from sage.rings.all import QQ + from sage.rings.rational_field import QQ Sym = SymmetricFunctions(QQ) s = Sym.schur() support = s(w.stanley_symmetric_function()).support() diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 2cb25976f54..e3a1767263b 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -31,7 +31,7 @@ from sage.categories.homset import Hom from sage.categories.map import Map from sage.rings.integer import Integer -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.combinat.crystals.affine import (AffineCrystalFromClassical, AffineCrystalFromClassicalElement, AffineCrystalFromClassicalAndPromotion, diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 187d5fd0b92..4efbef4a0c3 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -800,7 +800,7 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): True """ if q is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ q = QQ['q'].gens()[0] #P0 = self.weight_lattice_realization().classical() P0 = RootSystem(self.cartan_type().classical()).weight_lattice() diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py index 50533fbc842..57a17f31e83 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py @@ -39,7 +39,7 @@ from sage.combinat.rigged_configurations.bij_type_C import RCToKRTBijectionTypeC from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class KRTToRCBijectionTypeA2Dual(KRTToRCBijectionTypeC): r""" diff --git a/src/sage/combinat/rigged_configurations/rigged_configurations.py b/src/sage/combinat/rigged_configurations/rigged_configurations.py index c16b92649ee..702be558013 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -30,7 +30,7 @@ from sage.structure.parent import Parent from sage.combinat.misc import IterableFunctionCall import sage.combinat.tableau as tableau -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.categories.loop_crystals import KirillovReshetikhinCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.rigged_configurations.kleber_tree import KleberTree, VirtualKleberTree diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index ded9b53460b..4947d1357db 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -15,7 +15,7 @@ from sage.structure.sage_object import SageObject from sage.combinat.root_system.cartan_type import CartanType from sage.modules.free_module_element import vector -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.functional import is_even, is_odd diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 0b0aac2306e..2bffa360060 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -490,7 +490,7 @@ def symmetrizer(self): # The result from is_symmetrizable needs to be scaled # to integer coefficients from sage.arith.all import LCM - from sage.rings.all import QQ + from sage.rings.rational_field import QQ scalar = LCM([QQ(x).denominator() for x in sym]) return Family( {iset[i]: ZZ(val*scalar) for i, val in enumerate(sym)} ) diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index e8ae792ecaf..5257356f2fc 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -947,7 +947,7 @@ def _symmetric_form_matrix(self): M = M.inverse() if a[0] != 1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ S = matrix([~a[0]]+[0]*(r-1)) A = cm.symmetrized_matrix().change_ring(QQ).stack(S) else: diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 938b09d23dd..cf3cfe3cfe8 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -54,7 +54,7 @@ from . import sfa from sage.combinat.partition import Partitions_n, _Partitions from sage.matrix.all import MatrixSpace -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.all import prod from sage.misc.cachefunc import cached_function import functools diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index 7af1a0dee36..04121797d6e 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -17,7 +17,7 @@ #***************************************************************************** from sage.combinat.species.species import GenericCombinatorialSpecies from sage.combinat.species.structure import SpeciesStructureWrapper -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class CombinatorialSpeciesStructure(SpeciesStructureWrapper): diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index aa5e29356d2..26a0c2e58ec 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -51,7 +51,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from .generating_series import OrdinaryGeneratingSeriesRing, ExponentialGeneratingSeriesRing, CycleIndexSeriesRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index 2e447d7076a..eb3a06fb6b4 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -1689,7 +1689,7 @@ def minkowski_summand(self, i): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex """ G = self.group() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if G.coxeter_matrix().is_crystallographic(): min_sum = [[QQ(v) for v in F.extended_weight_configuration()[i]] for F in self] else: @@ -1740,7 +1740,7 @@ def brick_polytope(self, coefficients=None): """ BV = self.brick_vectors(coefficients=coefficients) G = self.group() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if G.coxeter_matrix().is_crystallographic(): BV = [[QQ(v) for v in V] for V in BV] else: diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index bc6a540c2d0..05cb8365956 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -96,7 +96,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_list import lazy_list from sage.sets.set import Set -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.rings.infinity import Infinity from sage.rings.integer_ring import IntegerRing from sage.rings.integer import Integer diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index 0ca60758b69..0378dc23abb 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -636,7 +636,7 @@ from .parser import Parser from sage.misc.latex import latex from sage.misc.misc import powerset -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix from sage.matrix.constructor import vector diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index c02940a820e..c1a490efc10 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -2,7 +2,7 @@ Base class for polyhedra over `\QQ` """ -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.misc.all import prod from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index d8d85adde6e..ee8cb5a7e86 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -74,7 +74,7 @@ import itertools from sage.misc.cachefunc import cached_method -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.modules.free_module_element import vector from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index a113fde50b3..e23d6f03e77 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -363,7 +363,7 @@ def verify(self, inequalities, equations): sage: H = Hrep2Vrep(QQ, 1, [(1,2)], []) sage: H.verify([(1,2)], []) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return @@ -558,7 +558,7 @@ def verify(self, vertices, rays, lines): sage: V2H = Vrep2Hrep(QQ, 2, vertices, rays, lines) sage: V2H.verify(vertices, rays, lines) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 27fa95f9b9c..3b33827969e 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1543,7 +1543,7 @@ def _sage_(self): from sage.rings.integer_ring import ZZ return ZZ elif repr_str == "QQ": - from sage.rings.all import QQ + from sage.rings.rational_field import QQ return QQ if cls_cls_str == "Type": @@ -1662,7 +1662,7 @@ def _sage_(self): from sage.rings.integer_ring import ZZ return ZZ(repr_str) elif cls_str == "QQ": - from sage.rings.all import QQ + from sage.rings.rational_field import QQ repr_str = self.external_string() if "/" not in repr_str: repr_str = repr_str + "/1" diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index d5e74dce41b..845fa0fd264 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -503,7 +503,7 @@ def solve_linear_system(self, A, b): if m != len(b): raise ValueError("dimensions of A and b must be compatible") from sage.matrix.all import MatrixSpace - from sage.rings.all import QQ + from sage.rings.rational_field import QQ MS = MatrixSpace(QQ,m,1) b = MS(list(b)) # converted b to a "column vector" sA = self.sage2octave_matrix_string(A) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 8ac83e87ad6..48282c7158a 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -1577,7 +1577,7 @@ def str_to_base_ring(s): return base_ring(a) + base_ring(b)*base_ring.gen() elif 'Rational' in T1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ str_to_base_ring = lambda s: QQ(s) else: diff --git a/src/sage/misc/random_testing.py b/src/sage/misc/random_testing.py index c1eda49d940..13ff9be3b57 100644 --- a/src/sage/misc/random_testing.py +++ b/src/sage/misc/random_testing.py @@ -178,7 +178,7 @@ def test_add_commutes(trials, verbose=False): sage: test_add_commutes(10) sage: test_add_commutes(1000) # long time """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ for _ in range(trials): a = QQ.random_element() b = QQ.random_element() @@ -252,7 +252,7 @@ def test_add_is_mul(trials, verbose=False): Random seed: 216390410596009428782506007128692114173 AssertionError() """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ for _ in range(trials): a = QQ.random_element() b = QQ.random_element() diff --git a/src/sage/modular/abvar/abvar_ambient_jacobian.py b/src/sage/modular/abvar/abvar_ambient_jacobian.py index 6b81afe0545..d6338c53262 100644 --- a/src/sage/modular/abvar/abvar_ambient_jacobian.py +++ b/src/sage/modular/abvar/abvar_ambient_jacobian.py @@ -15,7 +15,7 @@ from .abvar import (ModularAbelianVariety_modsym_abstract, simple_factorization_of_modsym_space, modsym_lattices, ModularAbelianVariety_modsym) -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.modular.modsym.modsym import ModularSymbols from sage.modular.modform.constructor import Newforms diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index e35677813be..56150c69943 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -223,7 +223,7 @@ def _richcmp_(self, right, op): [(1/3, 0)] """ A = self.parent().abelian_variety() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice(): return rich_to_bool(op, 0) return richcmp(self.__element, right.__element, op) diff --git a/src/sage/modular/modform/j_invariant.py b/src/sage/modular/modform/j_invariant.py index 2189c32b5f8..3cb5085fa02 100644 --- a/src/sage/modular/modform/j_invariant.py +++ b/src/sage/modular/modform/j_invariant.py @@ -3,7 +3,7 @@ """ from .eis_series import eisenstein_series_qexp from .vm_basis import delta_qexp -from sage.rings.all import QQ +from sage.rings.rational_field import QQ def j_invariant_qexp(prec=10, K=QQ): r""" diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 89a88c25aa1..5995ef1bb1b 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -552,7 +552,7 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): # and #P^1(N) columns. cdef Matrix_rational_dense T from sage.matrix.all import matrix - from sage.rings.all import QQ + from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1), sparse=False) original_base_ring = R.base_ring() if original_base_ring != QQ: @@ -672,7 +672,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) """ cdef p1list.P1List P1 = p1list.P1List(N) - from sage.rings.all import QQ + from sage.rings.rational_field import QQ K = chi.base_ring() if K == QQ: @@ -771,7 +771,7 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): (0, -2, 0, 2, -2, -1) """ cdef p1list.P1List P1 = p1list.P1List(N) - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if chi.base_ring() != QQ: raise TypeError("character must takes values in QQ") @@ -869,7 +869,7 @@ def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): # and #P^1(N) * (k-1) columns. cdef Matrix_rational_dense T from sage.matrix.all import matrix - from sage.rings.all import QQ + from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1)*(k-1), sparse=False) if R.base_ring() != QQ: diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 42a035a3230..91308598355 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -68,7 +68,7 @@ cdef class InteractiveLPBackend: """ if base_ring is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ self.lp = InteractiveLPProblem([], [], [], base_ring=base_ring) diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index 01bdf712f6e..901dbdd3b88 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -183,7 +183,7 @@ def base_ring(self): sage: lb = LoggingBackend(backend=b) sage: lb.base_ring() Real Double Field - sage: from sage.rings.all import QQ + sage: from sage.rings.rational_field import QQ sage: lb = LoggingBackend(backend=b, base_ring=QQ) sage: lb.base_ring() Rational Field @@ -232,7 +232,7 @@ def _test_{name}(cls, tester=None, **options): tester = p._tester(**options) '''.replace("SAGE:", "sage:") # so that the above test does not get picked up by the doctester -from sage.rings.all import QQ +from sage.rings.rational_field import QQ def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=QQ): diff --git a/src/sage/numerical/backends/matrix_sdp_backend.pyx b/src/sage/numerical/backends/matrix_sdp_backend.pyx index 11dbaf5bb6e..d04446c2287 100644 --- a/src/sage/numerical/backends/matrix_sdp_backend.pyx +++ b/src/sage/numerical/backends/matrix_sdp_backend.pyx @@ -51,7 +51,7 @@ cdef class MatrixSDPBackend(GenericSDPBackend): self.set_sense(-1) if base_ring is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ self._base_ring = base_ring diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index 8f7154137ad..74306eeee8e 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -67,7 +67,7 @@ cdef class PPLBackend(GenericBackend): """ if base_ring is not None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if base_ring is not QQ: raise TypeError('The PPL backend only supports rational data.') @@ -90,7 +90,7 @@ cdef class PPLBackend(GenericBackend): self.set_sense(-1) cpdef base_ring(self): - from sage.rings.all import QQ + from sage.rings.rational_field import QQ return QQ cpdef zero(self): diff --git a/src/sage/rings/function_field/function_field_valuation.py b/src/sage/rings/function_field/function_field_valuation.py index 2bcff1b1d25..bff8ad4b1b3 100644 --- a/src/sage/rings/function_field/function_field_valuation.py +++ b/src/sage/rings/function_field/function_field_valuation.py @@ -150,7 +150,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.structure.factory import UniqueFactory -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.rings.valuation.valuation import DiscreteValuation, DiscretePseudoValuation, InfiniteDiscretePseudoValuation, NegativeInfiniteDiscretePseudoValuation @@ -1247,7 +1247,7 @@ def scale(self, scalar): 3 * (x)-adic valuation (in Rational function field in x over Finite Field of size 2 after x |--> 1/x) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if scalar in QQ and scalar > 0 and scalar != 1: return self.domain().valuation((self._base_valuation.scale(scalar), self._to_base, self._from_base)) return super(FunctionFieldMappedValuation_base, self).scale(scalar) diff --git a/src/sage/rings/number_field/morphism.py b/src/sage/rings/number_field/morphism.py index c6e2b0bd425..174252dad61 100644 --- a/src/sage/rings/number_field/morphism.py +++ b/src/sage/rings/number_field/morphism.py @@ -130,7 +130,7 @@ def preimage(self, y): V,VtoK,KtoV = self.domain().absolute_vector_space() # construct the transformation matrix from K to L by making the columns be the image of the basis of V_K in V_L using the homomorphism from sage.matrix.constructor import matrix - from sage.rings.all import QQ + from sage.rings.rational_field import QQ M = matrix(QQ, [LtoV(self(VtoK(e))) for e in V.basis()]).transpose() self._transformation_data = (M,LtoV,VtoK) diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index c489221589f..30689e3d0d0 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -1248,7 +1248,7 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): if error < v: return self.domain().zero() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.rings.all import Qp precision_ring = Qp(self.p(), QQ(error).floor() + 1 - v) reduced = precision_ring(x) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 57c274c4ebd..b5abbb026e7 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4723,7 +4723,7 @@ def degree_of_semi_regularity(self): if m <= n: raise ValueError("This function requires an overdefined system of polynomials.") - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.misc.misc_c import prod from sage.rings.power_series_ring import PowerSeriesRing diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index b1758aa6ea6..d537568b4d3 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -690,7 +690,7 @@ def scale(self, scalar): Gauss valuation induced by 3 * 2-adic valuation """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if scalar in QQ and scalar > 0 and scalar != 1: return GaussValuation(self.domain(), self._base_valuation.scale(scalar)) return super(GaussValuation_generic, self).scale(scalar) diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index ab7460a8e28..09ed54aa31f 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -90,7 +90,7 @@ # **************************************************************************** from sage.misc.all import xmrange -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from .constructor import EllipticCurve, EllipticCurve_from_j diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index bd7a8027b0c..d11395872c2 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -697,7 +697,7 @@ def descend_to(self, K, f=None): # j-invariant is in the image, otherwise return an empty list: j = self.j_invariant() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if K == QQ: try: jK = QQ(j) diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 7befb02a772..aacb40350a2 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -123,7 +123,7 @@ def __init__(self, E, verbose=False): self._N = E.discriminant().norm() self._field = K = E.base_field() if K.absolute_degree() == 1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.rings.polynomial.all import polygen self._Kpol = polygen(QQ) else: diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index 52874594a51..dd13fac0235 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -60,7 +60,7 @@ from sage.libs.gmp.mpq cimport * from sage.misc.all import latex from sage.modules.all import vector from sage.modules.vector_rational_dense cimport Vector_rational_dense -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.rings.rational cimport Rational from sage.structure.element cimport Element, Vector from sage.structure.element import is_Vector diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index a24bbcebc38..e2f25ca1129 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -787,7 +787,7 @@ def minpoly(self, bits=None, degree=None, epsilon=0): sage: golden_ratio.minpoly() x^2 - x - 1 """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ x = QQ['x'].gen(0) return x**2 - x - 1 diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index e4b9a1fa619..ae824fcef98 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -14,7 +14,7 @@ from sage.misc.prandom import randint, random import operator -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.symbolic.ring import SR from sage.libs.pynac.pynac import symbol_table from sage.symbolic.constants import (pi, e, golden_ratio, log2, euler_gamma, From 7b7cfc3c43ea3f9a69e69cfbae999c6b9e8bb19d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:02:52 -0700 Subject: [PATCH 196/355] git grep -l 'all import prod' src/sage | xargs sed -i.bak 's/sage[.]misc[.]all import prod *$/sage.misc.misc_c import prod/' --- src/sage/categories/finite_complex_reflection_groups.py | 2 +- src/sage/coding/code_constructions.py | 2 +- src/sage/coding/linear_code.py | 2 +- src/sage/combinat/alternating_sign_matrix.py | 2 +- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 4 ++-- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/derangements.py | 2 +- src/sage/combinat/fully_packed_loop.py | 2 +- src/sage/combinat/gelfand_tsetlin_patterns.py | 2 +- src/sage/combinat/hall_polynomial.py | 2 +- src/sage/combinat/misc.py | 2 +- src/sage/combinat/necklace.py | 2 +- src/sage/combinat/partition.py | 2 +- src/sage/combinat/plane_partition.py | 2 +- src/sage/combinat/q_analogues.py | 2 +- .../combinat/root_system/weight_lattice_realizations.py | 2 +- src/sage/combinat/sf/elementary.py | 2 +- src/sage/combinat/sf/homogeneous.py | 2 +- src/sage/combinat/sf/jack.py | 2 +- src/sage/combinat/sf/macdonald.py | 2 +- src/sage/combinat/sf/ns_macdonald.py | 2 +- src/sage/combinat/sf/powersum.py | 2 +- src/sage/combinat/sf/schur.py | 2 +- src/sage/combinat/sf/sfa.py | 2 +- src/sage/combinat/similarity_class_type.py | 2 +- src/sage/combinat/sloane_functions.py | 2 +- src/sage/combinat/species/misc.py | 2 +- src/sage/combinat/species/product_species.py | 2 +- src/sage/combinat/species/series.py | 2 +- src/sage/combinat/tableau.py | 2 +- src/sage/combinat/words/word_generators.py | 2 +- src/sage/crypto/boolean_function.pyx | 2 +- src/sage/functions/other.py | 2 +- src/sage/geometry/hyperplane_arrangement/arrangement.py | 2 +- src/sage/geometry/integral_points.pyx | 2 +- src/sage/geometry/polyhedron/backend_normaliz.py | 2 +- src/sage/geometry/polyhedron/base.py | 2 +- src/sage/geometry/polyhedron/base_QQ.py | 2 +- src/sage/graphs/chrompoly.pyx | 2 +- src/sage/graphs/matchpoly.pyx | 2 +- src/sage/groups/abelian_gps/abelian_group.py | 2 +- src/sage/groups/abelian_gps/abelian_group_morphism.py | 2 +- src/sage/groups/abelian_gps/dual_abelian_group_element.py | 2 +- src/sage/groups/abelian_gps/values.py | 2 +- src/sage/groups/generic.py | 2 +- src/sage/groups/group.pyx | 2 +- src/sage/groups/libgap_wrapper.pyx | 2 +- src/sage/interacts/library_cython.pyx | 2 +- src/sage/matrix/matrix_rational_dense.pyx | 2 +- src/sage/misc/mrange.py | 2 +- src/sage/modular/abvar/abvar.py | 2 +- src/sage/modular/abvar/finite_subgroup.py | 2 +- src/sage/modular/arithgroup/congroup_gamma.py | 2 +- src/sage/modular/arithgroup/congroup_gamma0.py | 2 +- src/sage/modular/arithgroup/congroup_gamma1.py | 2 +- src/sage/modular/dims.py | 2 +- src/sage/modular/dirichlet.py | 2 +- src/sage/modular/modform/element.py | 2 +- src/sage/modular/modform/ring.py | 2 +- src/sage/modular/modform_hecketriangle/abstract_space.py | 2 +- src/sage/modular/modsym/p1list_nf.py | 2 +- src/sage/modular/modsym/space.py | 2 +- src/sage/modular/quatalg/brandt.py | 2 +- src/sage/modules/fg_pid/fgp_module.py | 4 ++-- src/sage/modules/tensor_operations.py | 2 +- .../quadratic_form__mass__Conway_Sloane_masses.py | 2 +- .../quadratic_form__mass__Siegel_densities.py | 2 +- .../quadratic_forms/quadratic_form__ternary_Tornaria.py | 2 +- src/sage/rings/number_field/S_unit_solver.py | 2 +- src/sage/rings/number_field/number_field_element.pyx | 2 +- src/sage/rings/number_field/number_field_ideal.py | 2 +- src/sage/rings/number_field/unit_group.py | 2 +- src/sage/rings/polynomial/multi_polynomial.pyx | 2 +- src/sage/rings/polynomial/multi_polynomial_element.py | 2 +- src/sage/rings/rational_field.py | 2 +- src/sage/rings/valuation/inductive_valuation.py | 2 +- src/sage/schemes/affine/affine_morphism.py | 2 +- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 2 +- src/sage/schemes/elliptic_curves/ell_finite_field.py | 2 +- src/sage/schemes/elliptic_curves/ell_rational_field.py | 2 +- src/sage/schemes/elliptic_curves/heegner.py | 2 +- src/sage/schemes/elliptic_curves/height.py | 2 +- src/sage/schemes/elliptic_curves/isogeny_small_degree.py | 8 ++++---- src/sage/schemes/elliptic_curves/mod_sym_num.pyx | 2 +- src/sage/schemes/product_projective/rational_point.py | 2 +- src/sage/schemes/product_projective/space.py | 2 +- src/sage/schemes/product_projective/subscheme.py | 2 +- src/sage/schemes/projective/projective_morphism.py | 2 +- src/sage/schemes/toric/points.py | 2 +- src/sage/schemes/toric/toric_subscheme.py | 2 +- src/sage/schemes/toric/weierstrass.py | 2 +- src/sage/symbolic/expression.pyx | 2 +- 92 files changed, 97 insertions(+), 97 deletions(-) diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 817b762c2ac..bb3df827890 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -12,7 +12,7 @@ # **************************************************************************** from sage.misc.abstract_method import abstract_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index e5b48049d11..c5971d48e9e 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -40,7 +40,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import quadratic_residues, gcd from sage.structure.sequence import Sequence, Sequence_generic diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 7c68023292c..eb50986d29e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -223,7 +223,7 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.functional import is_even from sage.misc.cachefunc import cached_method from sage.misc.randstate import current_randstate diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index b5dc876693b..8699f80ac26 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -35,7 +35,7 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.flatten import flatten -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 8ce5cc5c1b0..ec28a9887ef 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -46,7 +46,7 @@ from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType_Irreducible, QuiverMutationType_Reducible from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite from random import randint -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.matrix.all import identity_matrix from sage.matrix.constructor import matrix from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver @@ -1812,7 +1812,7 @@ def coefficient(self,k): sage: [ S.coefficient(k) for k in range(3) ] [y0, 1/y2, 1/y1] """ - from sage.misc.all import prod + from sage.misc.misc_c import prod if k in self._nlist: k = self._nlist.index(k) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 1b63e315221..a923461c6b6 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -156,7 +156,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.libs.all import pari from sage.misc.prandom import randint -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function from sage.structure.sage_object import SageObject from sage.structure.parent import Parent diff --git a/src/sage/combinat/derangements.py b/src/sage/combinat/derangements.py index 4ad088c9575..d9db2b087e1 100644 --- a/src/sage/combinat/derangements.py +++ b/src/sage/combinat/derangements.py @@ -26,7 +26,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.prandom import random, randrange from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.all import ZZ, QQ diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 07aa49ffacc..05e4ab5fd25 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -40,7 +40,7 @@ from sage.matrix.constructor import matrix from sage.arith.all import factorial from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod # edges of a fpl in terms of the six vertex possible configurations R = (1, 0) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index 72ee0eb4d7f..4cd334ceaf6 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -49,7 +49,7 @@ from sage.combinat.partition import Partitions from sage.combinat.tableau import Tableau, SemistandardTableaux from sage.combinat.combinatorial_map import combinatorial_map -from sage.misc.all import prod +from sage.misc.misc_c import prod class GelfandTsetlinPattern(ClonableArray, diff --git a/src/sage/combinat/hall_polynomial.py b/src/sage/combinat/hall_polynomial.py index b2b36260ad0..cd540de429c 100644 --- a/src/sage/combinat/hall_polynomial.py +++ b/src/sage/combinat/hall_polynomial.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partition from sage.combinat.q_analogues import q_binomial diff --git a/src/sage/combinat/misc.py b/src/sage/combinat/misc.py index 6a17f46d24c..d3bdbccf03a 100644 --- a/src/sage/combinat/misc.py +++ b/src/sage/combinat/misc.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod class DoublyLinkedList(): """ diff --git a/src/sage/combinat/necklace.py b/src/sage/combinat/necklace.py index 475433bf44d..bbfb5c215d2 100644 --- a/src/sage/combinat/necklace.py +++ b/src/sage/combinat/necklace.py @@ -29,7 +29,7 @@ from sage.arith.all import euler_phi, factorial, divisors, gcd from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.misc import DoublyLinkedList diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 12b264a43cc..1b6eb3e96f4 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -296,7 +296,7 @@ lazy_import('sage.combinat.skew_partition', 'SkewPartition') lazy_import('sage.combinat.partition_tuple', 'PartitionTuple') -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.prandom import randrange from sage.misc.cachefunc import cached_method, cached_function diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 75feecd7107..d49c05e8774 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -31,7 +31,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.posets.posets import Poset from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.tableau import Tableau diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index 02d284cb061..8968c7f140e 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -15,7 +15,7 @@ from sage.misc.cachefunc import cached_function -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.element import parent from sage.rings.integer_ring import ZZ from sage.combinat.dyck_word import DyckWords diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index 5257356f2fc..3ad10279619 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -21,7 +21,7 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.categories.category_types import Category_over_base_ring from sage.combinat.family import Family from .root_lattice_realizations import RootLatticeRealizations diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 3e1bb2607ad..755c3cd51bd 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -19,7 +19,7 @@ #***************************************************************************** from . import multiplicative, classical from sage.combinat.partition import Partition -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial from sage.rings.all import infinity diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 25635d42c14..98162e978dc 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -28,7 +28,7 @@ from . import multiplicative, classical from sage.combinat.partition import Partition from sage.rings.all import infinity -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 514823e82fb..74d02ab7c53 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -35,7 +35,7 @@ from sage.rings.all import Integer, QQ from sage.arith.all import gcd, lcm from sage.rings.fraction_field import is_FractionField -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom, End from sage.rings.fraction_field import FractionField diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index cf3cfe3cfe8..fc16c278d11 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -55,7 +55,7 @@ from sage.combinat.partition import Partitions_n, _Partitions from sage.matrix.all import MatrixSpace from sage.rings.rational_field import QQ -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function import functools diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index 7ac278837c8..d2a0928b2a6 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -8,7 +8,7 @@ from sage.combinat.combination import Combinations from sage.combinat.permutation import Permutation from sage.rings.all import QQ, PolynomialRing -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.backtrack import GenericBacktracker from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index eb33d33963a..b4181b239eb 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -22,7 +22,7 @@ from sage.arith.all import divisors from sage.rings.all import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.misc.all import prod +from sage.misc.misc_c import prod class SymmetricFunctionAlgebra_power(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index ca4858e744f..7cc7f800135 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -19,7 +19,7 @@ from . import classical import sage.libs.lrcalc.lrcalc as lrcalc -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.arith.misc import factorial diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 89b1b35abfe..09f89dcb93c 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -221,7 +221,7 @@ from sage.categories.tensor import tensor from sage.combinat.free_module import CombinatorialFreeModule from sage.matrix.constructor import matrix -from sage.misc.all import prod +from sage.misc.misc_c import prod from copy import copy from functools import reduce diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index cba51173f03..a77f5b65bca 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -176,7 +176,7 @@ class type, it is also possible to compute the number of classes of that type # **************************************************************************** from itertools import chain, product -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.misc import factorial from sage.arith.all import moebius, divisors from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index a890c188bed..4307051be34 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -321,7 +321,7 @@ def __getitem__(self, n): from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ from sage.combinat import combinat -from sage.misc.all import prod +from sage.misc.misc_c import prod # This one should be here! diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index ba1193e6097..60436e72d23 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -17,7 +17,7 @@ #***************************************************************************** from sage.groups.all import PermutationGroup, PermutationGroup_generic, PermutationGroupElement, SymmetricGroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from functools import wraps def change_support(perm, support, change_perm=None): diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 4bbee606925..77894d6f572 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -411,7 +411,7 @@ def _equation(self, var_mapping): sage: S.algebraic_equation_system() [node0 - z^2] """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(var_mapping[operand] for operand in self._state_info) diff --git a/src/sage/combinat/species/series.py b/src/sage/combinat/species/series.py index ea79a9c9c0e..b312148a2f3 100644 --- a/src/sage/combinat/species/series.py +++ b/src/sage/combinat/species/series.py @@ -34,7 +34,7 @@ from .stream import Stream, Stream_class from .series_order import bounded_decrement, increment, inf, unk from sage.rings.all import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from functools import partial from sage.misc.misc import is_iterator from sage.misc.repr import repr_lincomb diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index cd0d38681da..3cb05d80804 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -106,7 +106,7 @@ import sage.misc.prandom as random from sage.combinat import permutation from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.misc import powerset from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 26d31aefb9d..9b5c7fe08fb 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -1898,7 +1898,7 @@ def s_adic(self, sequence, letters, morphisms=None): from sage.combinat.words.word import FiniteWord_class if isinstance(sequence,(tuple,list,str,FiniteWord_class)) \ and hasattr(letters, "__len__") and len(letters) == 1: - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(seq)(letters) from itertools import tee diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index a8aa0f48fbb..7225596517b 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -1000,7 +1000,7 @@ cdef class BooleanFunction(SageObject): s = vector(self.truth_table()).support() from sage.combinat.combination import Combinations - from sage.misc.all import prod + from sage.misc.misc_c import prod from sage.matrix.constructor import Matrix from sage.arith.all import binomial diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 053e0120454..68287710987 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1794,7 +1794,7 @@ def _binomial_sym(self, n, k): if k == 1: return n - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(n - i for i in range(k)) / factorial(k) def _eval_(self, n, k): diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 05b5181342c..ed2a048d38a 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -2937,7 +2937,7 @@ def varchenko_matrix(self, names='h'): (h2 - 1) * (h2 + 1) * (h1 - 1) * (h1 + 1) """ from sage.matrix.constructor import identity_matrix - from sage.misc.all import prod + from sage.misc.misc_c import prod k = len(self) R = PolynomialRing(QQ, names, k) h = R.gens() diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index 37e1d23339d..7ba6d62e03f 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -22,7 +22,7 @@ from sage.rings.all import QQ, RR, ZZ from sage.rings.integer cimport Integer from sage.arith.all import gcd, lcm from sage.combinat.permutation import Permutation -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule from sage.modules.vector_integer_dense cimport Vector_integer_dense from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index d23b90b4933..ce7bede84a8 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -25,7 +25,7 @@ from sage.structure.element import Element from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.features import PythonModule from sage.misc.lazy_import import lazy_import lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 040e09f7df8..183d862978a 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -37,7 +37,7 @@ from sage.cpython.string import bytes_to_str from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.randstate import current_randstate from sage.misc.superseded import deprecated_function_alias diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index c1a490efc10..520e871ecb1 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -4,7 +4,7 @@ from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from .base import Polyhedron_base diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index e1b9c80d2a0..07d87a6d509 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -30,7 +30,7 @@ from memory_allocator cimport MemoryAllocator from sage.libs.gmp.mpz cimport * from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod def chromatic_polynomial(G, return_tree_basis=False): diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 434e6bbf8bd..3226350f7be 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -41,7 +41,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.libs.flint.fmpz cimport * from sage.libs.flint.fmpz_poly cimport * diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 5ae1a14a997..00cf0f3c9d7 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -210,7 +210,7 @@ from sage.arith.all import divisors, gcd, lcm from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import mrange, cartesian_product_iterator from sage.groups.group import AbelianGroup as AbelianGroupBase from sage.categories.groups import Groups diff --git a/src/sage/groups/abelian_gps/abelian_group_morphism.py b/src/sage/groups/abelian_gps/abelian_group_morphism.py index 623cacc4554..518946ea839 100644 --- a/src/sage/groups/abelian_gps/abelian_group_morphism.py +++ b/src/sage/groups/abelian_gps/abelian_group_morphism.py @@ -22,7 +22,7 @@ from sage.interfaces.gap import gap from sage.categories.morphism import Morphism -from sage.misc.all import prod +from sage.misc.misc_c import prod def is_AbelianGroupMorphism(f): diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index 1c4120c7b53..a4f2879fb3d 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -57,7 +57,7 @@ import operator from sage.arith.all import LCM -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.groups.abelian_gps.element_base import AbelianGroupElementBase from functools import reduce diff --git a/src/sage/groups/abelian_gps/values.py b/src/sage/groups/abelian_gps/values.py index e411ecbf407..27e91cf30ed 100644 --- a/src/sage/groups/abelian_gps/values.py +++ b/src/sage/groups/abelian_gps/values.py @@ -70,7 +70,7 @@ # http://www.gnu.org/licenses/ ########################################################################## -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.integer import Integer from sage.categories.morphism import Morphism from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 7cec7db1333..af6221de6b4 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -111,7 +111,7 @@ from copy import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.rings.integer_ring as integer_ring import sage.rings.integer from sage.arith.srange import xsrange diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index d54fdc7b5f2..9fdc2b87db2 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -219,7 +219,7 @@ cdef class Group(Parent): sage: G.an_element() f0*f1*f2*f3 """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(self.gens()) def quotient(self, H, **kwds): diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index d06bebe881b..451cb5c65c2 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -430,7 +430,7 @@ class ParentLibGAP(SageObject): sage: G._an_element_() a*b """ - from sage.misc.all import prod + from sage.misc.misc_c import prod gens = self.gens() if gens: return prod(gens) diff --git a/src/sage/interacts/library_cython.pyx b/src/sage/interacts/library_cython.pyx index 6e23ef27d42..59fbc931e6b 100644 --- a/src/sage/interacts/library_cython.pyx +++ b/src/sage/interacts/library_cython.pyx @@ -16,7 +16,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod cpdef julia(ff_j, z, int iterations): diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index d67529c0a7e..bf343014db5 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -116,7 +116,7 @@ from sage.arith.all import gcd from .matrix2 import decomp_seq from .matrix0 import Matrix as Matrix_base -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose, get_verbose ######################################################### diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 41b9f4f211d..943f96ed249 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -19,7 +19,7 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod def _len(L): diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 9367c4d3d37..36ab3162839 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -58,7 +58,7 @@ from sage.modular.modform.constructor import Newform from sage.matrix.all import matrix, block_diagonal_matrix, identity_matrix from sage.modules.all import vector -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.misc import is_prime from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.sets.primes import Primes diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 85bff44ad2e..3c2aefc0ab9 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -105,7 +105,7 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.all import QQ, ZZ, QQbar, Integer from sage.arith.all import lcm -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.element import coercion_model diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index 5250d5669bc..4625c7abc15 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -11,7 +11,7 @@ #***************************************************************************** from .congroup_generic import CongruenceSubgroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import ZZ, Zmod, QQ from sage.rings.integer import GCD_list from sage.groups.matrix_gps.finitely_generated import MatrixGroup diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index 724e3901c87..f1fc3f493d8 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.all import IntegerModRing, ZZ from sage.arith.all import kronecker_symbol -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.modular.modsym.p1list import sage.arith.all as arith diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index c73e55d1856..ca1bf498514 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -14,7 +14,7 @@ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from .congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor from sage.rings.integer_ring import ZZ from sage.arith.all import euler_phi as phi, moebius, divisors diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 1bf9aba3773..9ad307a4937 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -47,7 +47,7 @@ from sage.arith.all import factor, is_prime, valuation -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import Mod, Integer, IntegerModRing from sage.rings.rational_field import frac from . import dirichlet diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 96e70a3ed00..c0b9d3022a9 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -58,7 +58,7 @@ # **************************************************************************** import sage.categories.all as cat -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.misc.prandom as random from sage.modules.free_module import FreeModule import sage.modules.free_module_element as free_module_element diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 52aa43f9b8b..36814052068 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -39,7 +39,7 @@ from sage.arith.all import lcm, divisors, moebius, sigma, factor, crt from sage.arith.srange import xsrange from sage.matrix.constructor import matrix -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 0d04d1899cb..f328f891e1c 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -22,7 +22,7 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.all import Integer, QQ, ZZ -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 9e122b1abe7..abea0961e0c 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -2276,7 +2276,7 @@ def rationalize_series(self, laurent_series, coeff_bound = 1e-10, denom_factor = """ from sage.rings.all import prime_range - from sage.misc.all import prod + from sage.misc.misc_c import prod from warnings import warn denom_factor = ZZ(denom_factor) diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 91f7efada6f..c366a15fbb6 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -1198,7 +1198,7 @@ def psi(N): if not N.is_integral(): raise ValueError("psi only defined for integral ideals") - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([(np+1)*np**(e-1) \ for np,e in [(p.absolute_norm(),e) \ for p,e in N.factor()]]) diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 8e40d26f645..a4b1378547e 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -27,7 +27,7 @@ import sage.matrix.matrix_space as matrix_space from sage.modules.free_module_element import FreeModuleElement from sage.modules.free_module import EchelonMatrixKey -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.modular.hecke.all as hecke from sage.arith.all import divisors, next_prime from sage.rings.fast_arith import prime_range diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 5fbde461d12..81a775c99c4 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -203,7 +203,7 @@ # **************************************************************************** # imports -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.rings.all import Integer, ZZ, QQ, PolynomialRing, GF, CommutativeRing diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index db8fd8cabb7..009d8679e21 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1741,7 +1741,7 @@ def cardinality(self): except AttributeError: pass from sage.rings.all import infinity - from sage.misc.all import prod + from sage.misc.misc_c import prod v = self.invariants() self.__cardinality = infinity if 0 in v else prod(v) return self.__cardinality @@ -2006,7 +2006,7 @@ def test_morphism_0(*args, **kwds): phi = random_fgp_morphism_0(*args, **kwds) K = phi.kernel() I = phi.image() - from sage.misc.all import prod + from sage.misc.misc_c import prod if prod(K.invariants()): assert prod(phi.domain().invariants()) % prod(K.invariants()) == 0 assert I.is_submodule(phi.codomain()) diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index 9c943262319..3550946581b 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -64,7 +64,7 @@ from collections import defaultdict from sage.modules.free_module import FreeModule_ambient_field -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index fb35d04f53e..f91857adb82 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -5,7 +5,7 @@ from sage.rings.rational_field import QQ from sage.arith.all import kronecker_symbol, legendre_symbol, prime_divisors, is_prime, fundamental_discriminant from sage.symbolic.constants import pi -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index a7116516724..2941df73430 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -12,7 +12,7 @@ import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import mrange from sage.functions.all import floor from sage.rings.integer_ring import ZZ diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 9960396049a..a206070ef30 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -16,7 +16,7 @@ from sage.misc.functional import is_odd from sage.libs.pari.all import pari -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import (factor, gcd, prime_to_m_part, CRT_vectors, hilbert_symbol, kronecker_symbol) diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index f8e733dd7dc..f3ec1bd7148 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -68,7 +68,7 @@ from sage.rings.finite_rings.integer_mod import mod from sage.rings.padics.factory import Qp from sage.combinat.combination import Combinations -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial from sage.matrix.constructor import matrix, identity_matrix, vector, block_matrix, zero_matrix from sage.modules.free_module_element import zero_vector diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index d3091966f3f..b6606bf4618 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1989,7 +1989,7 @@ cdef class NumberFieldElement(FieldElement): raise ArithmeticError("non-principal ideal in factorization") element_fac = [(P.gens_reduced()[0],e) for P,e in fac] # Compute the product of the p^e to figure out the unit - from sage.misc.all import prod + from sage.misc.misc_c import prod element_product = prod([p**e for p,e in element_fac], K(1)) from sage.structure.all import Factorization return Factorization(element_fac, unit=self/element_product) diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 54d7ebb1535..01e6d610e59 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -47,7 +47,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.ideal import Ideal_generic -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import xmrange_iter from sage.misc.cachefunc import cached_method from sage.structure.element import MultiplicativeGroupElement diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index f3a940f80c5..d8f9b7a9c2f 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -163,7 +163,7 @@ from sage.groups.abelian_gps.values import AbelianGroupWithValues_class from sage.structure.proof.proof import get_flag from sage.libs.pari.all import pari -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 8106cf5f7a5..b63805a4135 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -15,7 +15,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.coerce cimport coercion_model from sage.misc.derivative import multi_derivative -from sage.misc.all import prod +from sage.misc.misc_c import prod def is_MPolynomial(x): return isinstance(x, MPolynomial) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 472a9ea4322..cbade28354c 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -54,7 +54,7 @@ #***************************************************************************** from sage.structure.element import CommutativeRingElement, coerce_binop -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.rings.integer from sage.rings.qqbar_decorators import handle_AA_and_QQbar from . import polydict diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 295f126caf9..059593e3836 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -1374,7 +1374,7 @@ def selmer_group_iterator(self, S, m, proof=True): """ KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True) one = self.one() - from sage.misc.all import prod + from sage.misc.misc_c import prod from itertools import product for ev in product(*[range(o) for o in ords]): yield prod((p**e for p,e in zip(KSgens, ev)), one) diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index c5749796737..5e8f48f496d 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -1295,7 +1295,7 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi F = list(F) if compute_unit: - from sage.misc.all import prod + from sage.misc.misc_c import prod unit *= self.lift(self.residue_ring()(prod([ psi.leading_coefficient()**e for psi,e in F ]))) # A potential speedup that we tried to implement here: diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 63a4f348af9..d8dae3b68a0 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -55,7 +55,7 @@ from sage.categories.homset import Hom, End from sage.categories.fields import Fields -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index ebbd2d2fc0c..12bfc890e26 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3783,7 +3783,7 @@ def split_kernel_polynomial(poly): sage: poly.factor() (x + 10) * (x + 12) * (x + 16) """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([p for p,e in poly.squarefree_decomposition()]) def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="starks"): diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index ffbf9e97553..9945c5bb0c7 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -1429,7 +1429,7 @@ def supersingular_j_polynomial(p, use_cache=True): if p in supersingular_j_polynomials: return J.parent()(supersingular_j_polynomials[p]) - from sage.misc.all import prod + from sage.misc.misc_c import prod m=(p-1)//2 X,T = PolynomialRing(GF(p),2,names=['X','T']).gens() H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1)) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index c900269c530..847a1485f8b 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -7064,7 +7064,7 @@ def elliptic_curve_congruence_graph(curves): from sage.graphs.graph import Graph from sage.arith.all import lcm from sage.rings.fast_arith import prime_range - from sage.misc.all import prod + from sage.misc.misc_c import prod G = Graph() G.add_vertices([curve.cremona_label() for curve in curves]) n = len(curves) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 97bd761d067..fc7d07086a8 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -93,7 +93,7 @@ # **************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 858946c5bb7..599f69ba1eb 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -1061,7 +1061,7 @@ def ME(self): sage: E.discriminant()/E.minimal_model().discriminant() 4096 """ - from sage.misc.all import prod + from sage.misc.misc_c import prod if self.K is QQ: return prod([p ** (e - self.E.local_data(p).discriminant_valuation()) for p, e in self.E.discriminant().factor()], QQ.one()) diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index abf03a0a1bb..bb38a7318e3 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -218,7 +218,7 @@ def Psi(l, use_stored=True): # Here the generic kernel polynomials are actually calculated: j = Fricke_module(l) k = j - 1728 - from sage.misc.all import prod + from sage.misc.misc_c import prod f = prod([p for p, e in j.factor() if e == 3] + [p for p, e in k.factor() if e == 2]) A4 = -3*t**2*j*k // f**2 @@ -312,7 +312,7 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): T = c4/(3*c6) jt = Fricke_module(l) kt = jt-1728 - from sage.misc.all import prod + from sage.misc.misc_c import prod psi = Psi(l) X = t f = R(prod( [p for p,e in jt.factor() if e==3] @@ -537,7 +537,7 @@ def _sporadic_Q_data(j): ....: assert g % f == 0 """ from sage.rings.all import RealField - from sage.misc.all import prod + from sage.misc.misc_c import prod ell = sporadic_j[j] E = EllipticCurve(j=j).short_weierstrass_model() a4a6 = list(E.ainvs())[3:] @@ -2204,7 +2204,7 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): # divisors of degree d, then their product is a kernel poly, which # we add to the list and remove the factors used. - from sage.misc.all import prod + from sage.misc.misc_c import prod for d in list(factors_by_degree): if d * len(factors_by_degree[d]) == l2: ker.append(prod(factors_by_degree.pop(d))) diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index 3ab88de7d68..43481b14a54 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -173,7 +173,7 @@ from sage.rings.real_mpfr cimport RealNumber, RealField from sage.rings.rational cimport Rational from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.arith.all import kronecker_symbol from sage.arith.misc import euler_phi diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index ab9fe7e3311..5239fd88203 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -58,7 +58,7 @@ from sage.schemes.generic.scheme import is_Scheme from sage.schemes.product_projective.space import is_ProductProjectiveSpaces from sage.misc.mrange import xmrange -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import next_prime, previous_prime, crt from sage.rings.all import ZZ, RR from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index 8e0ac579eab..a7eb86ce43f 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -41,7 +41,7 @@ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import (PolynomialRing, QQ, Integer, CommutativeRing) from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.categories.fields import Fields diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 7d00e1eb24d..1ac8018f8ab 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -15,7 +15,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.rings.fraction_field import FractionField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 060025bef9d..cd833ed79b0 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -66,7 +66,7 @@ from sage.interfaces.all import singular -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 81e7bfc8a03..724bf0ac40b 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -37,7 +37,7 @@ import itertools from copy import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.arith.all import gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 78a31099445..3011e0a0727 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -310,7 +310,7 @@ def affine_algebraic_patch(self, cone=None, names=None): z1 + z3 + 1 """ from sage.modules.all import vector - from sage.misc.all import prod + from sage.misc.misc_c import prod ambient = self.ambient_space() fan = ambient.fan() if cone is None: diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 45ba7fe3216..9c9e6720d12 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -137,7 +137,7 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.infinity import Infinity from sage.modules.all import vector from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 0278d035255..cf4dfd61a55 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -13410,7 +13410,7 @@ cpdef Expression new_Expression(parent, x): raise TypeError('positive characteristic not allowed in symbolic computations') exp = x elif isinstance(x, Factorization): - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([SR(p)**e for p,e in x], SR(x.unit())) elif x in Sets(): from sage.rings.all import NN, ZZ, QQ, AA From 79551117309d81eef7f5f632fbe2ba5fa70dcbdf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:05:17 -0700 Subject: [PATCH 197/355] git grep -l 'all import latex' src/sage | xargs sed -i.bak 's/sage[.]misc[.]all import latex *$/sage.misc.latex import latex/' --- src/sage/categories/group_algebras.py | 2 +- src/sage/combinat/cluster_algebra_quiver/interact.py | 2 +- src/sage/geometry/point_collection.pyx | 2 +- src/sage/geometry/toric_lattice.py | 2 +- src/sage/schemes/curves/curve.py | 2 +- src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py | 2 +- src/sage/schemes/toric/divisor_class.pyx | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 3a9ff84ce44..742ba8d9393 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -156,7 +156,7 @@ def _latex_(self): sage: latex(A) # indirect doctest \Bold{Z}[\langle (3,4), (1,2) \rangle] """ - from sage.misc.all import latex + from sage.misc.latex import latex return "%s[%s]" % (latex(self.base_ring()), latex(self.group())) def group(self): diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index ec34a97aabe..4e54c64e179 100644 --- a/src/sage/combinat/cluster_algebra_quiver/interact.py +++ b/src/sage/combinat/cluster_algebra_quiver/interact.py @@ -1,5 +1,5 @@ import ipywidgets as widgets -from sage.misc.all import latex +from sage.misc.latex import latex from sage.repl.rich_output.pretty_print import pretty_print from IPython.display import clear_output diff --git a/src/sage/geometry/point_collection.pyx b/src/sage/geometry/point_collection.pyx index 3fb6955ead3..2172b4d7291 100644 --- a/src/sage/geometry/point_collection.pyx +++ b/src/sage/geometry/point_collection.pyx @@ -81,7 +81,7 @@ from sage.structure.richcmp cimport richcmp_not_equal, richcmp from sage.geometry.toric_lattice import ToricLattice from sage.matrix.all import matrix -from sage.misc.all import latex +from sage.misc.latex import latex def is_PointCollection(x): diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index 4d8ef3fba62..5e82dcec7c3 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -148,7 +148,7 @@ from sage.geometry.toric_lattice_element import (ToricLatticeElement, is_ToricLatticeElement) from sage.geometry.toric_plotter import ToricPlotter -from sage.misc.all import latex +from sage.misc.latex import latex from sage.structure.all import parent from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, richcmp_not_equal) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 35eff517c38..2e4c41d961d 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -29,7 +29,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import latex +from sage.misc.latex import latex from sage.categories.finite_fields import FiniteFields from sage.categories.fields import Fields diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index cc4fe5f198d..a40a69398c2 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -112,7 +112,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import latex +from sage.misc.latex import latex from sage.structure.element import AdditiveGroupElement from sage.structure.richcmp import richcmp, op_NE diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index dd13fac0235..780a0843f56 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -57,7 +57,7 @@ divisor representing a divisor class:: from sage.libs.gmp.mpq cimport * -from sage.misc.all import latex +from sage.misc.latex import latex from sage.modules.all import vector from sage.modules.vector_rational_dense cimport Vector_rational_dense from sage.rings.rational_field import QQ From b693d89df6b66ecc013564a42207ceb30dc94cd8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:08:11 -0700 Subject: [PATCH 198/355] git grep -l 'all import vector' src/sage | xargs sed -i.bak 's/sage[.]modules[.]all import vector *$/sage.modules.free_module_element import vector/' --- src/sage/calculus/all.py | 2 +- src/sage/combinat/symmetric_group_algebra.py | 2 +- src/sage/crypto/boolean_function.pyx | 2 +- src/sage/finance/fractal.pyx | 2 +- src/sage/geometry/lattice_polytope.py | 2 +- .../geometry/polyhedron/double_description_inhomogeneous.py | 2 +- .../geometry/polyhedron/lattice_euclidean_group_element.py | 2 +- src/sage/geometry/polyhedron/ppl_lattice_polytope.py | 2 +- src/sage/geometry/toric_plotter.py | 2 +- src/sage/geometry/triangulation/element.py | 2 +- src/sage/geometry/triangulation/point_configuration.py | 2 +- src/sage/geometry/voronoi_diagram.py | 2 +- src/sage/groups/affine_gps/group_element.py | 2 +- src/sage/interfaces/chomp.py | 2 +- src/sage/libs/gap/element.pyx | 2 +- src/sage/modular/abvar/abvar.py | 2 +- src/sage/numerical/backends/generic_backend.pyx | 2 +- src/sage/numerical/backends/interactivelp_backend.pyx | 2 +- src/sage/rings/finite_rings/finite_field_base.pyx | 2 +- src/sage/rings/invariants/invariant_theory.py | 2 +- src/sage/schemes/affine/affine_subscheme.py | 2 +- src/sage/schemes/elliptic_curves/ell_number_field.py | 2 +- src/sage/schemes/elliptic_curves/period_lattice.py | 2 +- src/sage/schemes/elliptic_curves/saturation.py | 2 +- .../schemes/hyperelliptic_curves/hyperelliptic_padic_field.py | 2 +- src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py | 2 +- src/sage/schemes/toric/divisor.py | 2 +- src/sage/schemes/toric/divisor_class.pyx | 2 +- src/sage/schemes/toric/toric_subscheme.py | 2 +- src/sage/schemes/toric/weierstrass.py | 2 +- src/sage/schemes/toric/weierstrass_covering.py | 2 +- src/sage/symbolic/relation.py | 4 ++-- 32 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index 1f89c3f7ffe..a6671492076 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -30,7 +30,7 @@ lazy_import("sage.calculus.riemann",["Riemann_Map"]) lazy_import("sage.calculus.interpolators",["polygon_spline","complex_cubic_spline"]) -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 10a69e02a8c..ee60bb1e255 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -22,7 +22,7 @@ from sage.rings.all import QQ, PolynomialRing from sage.arith.all import factorial from sage.matrix.all import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.misc.persist import register_unpickle_override diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index 7225596517b..b519b2f7af9 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -996,7 +996,7 @@ cdef class BooleanFunction(SageObject): G = R.gens() r = [R(1)] - from sage.modules.all import vector + from sage.modules.free_module_element import vector s = vector(self.truth_table()).support() from sage.combinat.combination import Combinations diff --git a/src/sage/finance/fractal.pyx b/src/sage/finance/fractal.pyx index a553e8dbc93..a71efd67fb0 100644 --- a/src/sage/finance/fractal.pyx +++ b/src/sage/finance/fractal.pyx @@ -22,7 +22,7 @@ AUTHOR: """ from sage.rings.all import RDF, CDF, Integer -from sage.modules.all import vector +from sage.modules.free_module_element import vector I = CDF.gen() from .time_series cimport TimeSeries diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index d054e88ab6b..a05dbb474d7 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -126,7 +126,7 @@ from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method from sage.misc.all import flatten, tmp_filename -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.numerical.mip import MixedIntegerLinearProgram from sage.plot.plot3d.index_face_set import IndexFaceSet from sage.plot.plot3d.all import line3d, point3d diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index e23d6f03e77..b94be057249 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -53,7 +53,7 @@ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.geometry.polyhedron.double_description import StandardAlgorithm as Algorithm # Compare with PPL if the base ring is QQ. Can be left enabled since diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index 4309d09a1e0..79331133960 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -15,7 +15,7 @@ from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 1a97bd6c33c..207160401c8 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -69,7 +69,7 @@ from sage.rings.integer import GCD_list, Integer from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from ppl import ( C_Polyhedron, Linear_Expression, Variable, diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 2814060a271..568fae8d8da 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -51,7 +51,7 @@ from sage.functions.all import arccos, arctan2, ceil, floor from sage.geometry.polyhedron.constructor import Polyhedron -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.plot.all import (Color, Graphics, arrow, disk, line, point, polygon, rainbow, text) from sage.plot.plot3d.all import text3d diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index b19b9170258..736bccd1721 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -42,7 +42,7 @@ from sage.structure.richcmp import richcmp from sage.structure.element import Element from sage.rings.all import QQ, ZZ -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.misc.cachefunc import cached_method from sage.sets.set import Set from sage.graphs.graph import Graph diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index b074c114e52..b9bc8c48036 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -186,7 +186,7 @@ from sage.combinat.combination import Combinations from sage.rings.all import QQ, ZZ from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from copy import copy import sys diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 58aff796910..1c26764323e 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -18,7 +18,7 @@ from sage.all import RDF, QQ, AA from sage.rings.real_mpfr import RealField_class from sage.geometry.triangulation.point_configuration import PointConfiguration -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.plot.all import line, point, rainbow, plot diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index 9b158d22720..ab02e07f097 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -422,7 +422,7 @@ def __call__(self, v): from sage.rings.polynomial.multi_polynomial import is_MPolynomial if is_MPolynomial(v) and parent.degree() == v.parent().ngens(): ring = v.parent() - from sage.modules.all import vector + from sage.modules.free_module_element import vector image_coords = self._A * vector(ring, ring.gens()) + self._b return v(*image_coords) diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index cd1fc546b97..4d5f1ba4570 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -833,7 +833,7 @@ def process_generators_chain(gen_string, dim, base_ring=None): sage: process_generators_chain(s, 1, base_ring=GF(2)) [(1, 1), (0, 0, 1)] """ - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ if base_ring is None: base_ring = ZZ diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 591e67c5aef..f6db43ccf2a 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -3004,7 +3004,7 @@ cdef class GapElement_List(GapElement): """ if not self.IsVector(): raise ValueError('not a GAP vector') - from sage.modules.all import vector + from sage.modules.free_module_element import vector entries = self.Flat() n = self.Length().sage() if ring is None: diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 36ab3162839..c0834b3b804 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -57,7 +57,7 @@ from sage.modular.modsym.space import ModularSymbolsSpace from sage.modular.modform.constructor import Newform from sage.matrix.all import matrix, block_diagonal_matrix, identity_matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.misc.misc_c import prod from sage.arith.misc import is_prime from sage.schemes.elliptic_curves.constructor import EllipticCurve diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index 75d98d60b95..f386a97a6ad 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -532,7 +532,7 @@ cdef class GenericBackend: p = cls() # fresh instance of the backend if tester is None: tester = p._tester(**options) - from sage.modules.all import vector + from sage.modules.free_module_element import vector # Ensure there are at least 2 variables p.add_variables(2) coeffs = ([0, vector([1, 2])], [1, vector([2, 3])]) diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 91308598355..6b26a21f1e2 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -21,7 +21,7 @@ AUTHORS: from sage.numerical.mip import MIPSolverException from sage.numerical.interactive_simplex_method import InteractiveLPProblem, default_variable_name -from sage.modules.all import vector +from sage.modules.free_module_element import vector from copy import copy diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 91f69730fee..35da225308b 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1256,7 +1256,7 @@ cdef class FiniteField(Field): if inclusion_map is None: inclusion_map = self.coerce_map_from(base) - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.matrix.all import matrix from .maps_finite_field import ( MorphismVectorSpaceToFiniteField, MorphismFiniteFieldToVectorSpace) diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 059a774025b..dddd27f784e 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -928,7 +928,7 @@ def transformed(self, g): if isinstance(g, dict): transform = g else: - from sage.modules.all import vector + from sage.modules.free_module_element import vector v = vector(self._ring, self._variables) g_v = vector(self._ring, g*v) transform = dict( (v[i], g_v[i]) for i in range(self._n) ) diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index f6a2171bfca..d2938dc1dcb 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -22,7 +22,7 @@ from sage.categories.fields import Fields from sage.interfaces.all import singular -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from .affine_morphism import SchemeMorphism_polynomial_affine_subscheme_field diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 821d2e96639..76929fef275 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -984,7 +984,7 @@ def _scale_by_units(self): c4, c6 = self.c_invariants() c4s = [e(c4) for e in embs] c6s = [e(c6) for e in embs] - from sage.modules.all import vector + from sage.modules.free_module_element import vector v = vector([(x4.abs().nth_root(4)+x6.abs().nth_root(6)).log()*d for x4,x6,d in zip(c4s,c6s,degs)]) es = [e.round() for e in -Ainv*U*v] u = prod([uj**ej for uj,ej in zip(fu,es)]) diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index fe1899f647c..1fcb6a3e1a4 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -1183,7 +1183,7 @@ def coordinates(self, z, rounding=None): raise TypeError("%s is not a complex number"%z) prec = C.precision() from sage.matrix.all import Matrix - from sage.modules.all import vector + from sage.modules.free_module_element import vector if self.real_flag: w1,w2 = self.basis(prec) M = Matrix([[w1,0], list(w2)])**(-1) diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index aacb40350a2..d8037db8877 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -667,7 +667,7 @@ def p_projections(Eq, Plist, p, debug=False): print("gens for {}-primary part of G: {}".format(p, gens)) print("{}*points: {}".format(m,pts)) from sage.groups.generic import discrete_log as dlog - from sage.modules.all import vector + from sage.modules.free_module_element import vector Fp = GF(p) # If the p-primary part is cyclic we use elliptic discrete logs directly: diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index 67b1e79a436..f69234cdc04 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -17,7 +17,7 @@ from sage.functions.log import log from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index b09c0884be8..8bf87c92827 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -54,7 +54,7 @@ from sage.misc.misc import newton_method_sizes from sage.misc.profiler import Profiler from sage.misc.repr import repr_lincomb -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.modules.free_module import FreeModule from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.module import Module diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 576845ac1e8..c9ba1d4edf9 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -173,7 +173,7 @@ from sage.topology.simplicial_complex import SimplicialComplex from sage.matrix.constructor import matrix from sage.misc.all import cached_method, flatten, latex, prod -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.modules.free_module import (FreeModule_ambient_field, FreeModule_ambient_pid) from sage.rings.all import QQ, ZZ diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index 780a0843f56..dfbd518e951 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -58,7 +58,7 @@ divisor representing a divisor class:: from sage.libs.gmp.mpq cimport * from sage.misc.latex import latex -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.modules.vector_rational_dense cimport Vector_rational_dense from sage.rings.rational_field import QQ from sage.rings.rational cimport Rational diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 3011e0a0727..728063064cb 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -309,7 +309,7 @@ def affine_algebraic_patch(self, cone=None, names=None): z0*z2 - z1*z3, z1 + z3 + 1 """ - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.misc.misc_c import prod ambient = self.ambient_space() fan = ambient.fan() diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 9c9e6720d12..e3bdd0cb311 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -139,7 +139,7 @@ from sage.misc.misc_c import prod from sage.rings.infinity import Infinity -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL from sage.rings.invariants.all import invariant_theory diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 4689d47f789..7e141ebfbd9 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -105,7 +105,7 @@ ######################################################################## from sage.rings.integer_ring import ZZ -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.rings.all import invariant_theory from sage.schemes.toric.weierstrass import ( _partial_discriminant, diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 28b1bce0301..7c767901baf 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1571,7 +1571,7 @@ def solve_mod(eqns, modulus, solution_dict=False): from sage.rings.all import Integer, Integers, crt_basis from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.matrix.all import matrix if not isinstance(eqns, (list, tuple)): @@ -1685,7 +1685,7 @@ def _solve_mod_prime_power(eqns, p, m, vars): """ from sage.rings.all import Integers, PolynomialRing - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.misc.all import cartesian_product_iterator mrunning = 1 From 8e357e18c02c6a859721354130726c97f87d4f3b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:08:24 -0700 Subject: [PATCH 199/355] git grep -l 'all import matrix' src/sage | xargs sed -i.bak 's/sage[.]matrix[.]all import matrix *$/sage.matrix.constructor import matrix/' --- src/sage/algebras/quatalg/quaternion_algebra_element.pyx | 2 +- src/sage/arith/misc.py | 2 +- src/sage/calculus/functions.py | 2 +- src/sage/coding/self_dual_codes.py | 2 +- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 4 ++-- .../cluster_algebra_quiver/quiver_mutation_type.py | 2 +- src/sage/combinat/matrices/latin.py | 2 +- src/sage/combinat/rsk.py | 2 +- src/sage/combinat/sf/dual.py | 2 +- src/sage/combinat/sf/hall_littlewood.py | 2 +- src/sage/combinat/sf/witt.py | 2 +- src/sage/combinat/subword_complex.py | 2 +- src/sage/combinat/symmetric_group_algebra.py | 2 +- src/sage/geometry/fan.py | 2 +- src/sage/geometry/point_collection.pyx | 2 +- .../geometry/polyhedron/combinatorial_polyhedron/base.pyx | 4 ++-- src/sage/groups/fqf_orthogonal.py | 2 +- src/sage/groups/matrix_gps/finitely_generated.py | 2 +- src/sage/interfaces/kenzo.py | 2 +- src/sage/interfaces/macaulay2.py | 2 +- src/sage/interfaces/matlab.py | 2 +- src/sage/libs/linkages/padics/fmpz_poly_unram.pxi | 2 +- src/sage/matrix/strassen.pyx | 2 +- src/sage/modular/modsym/heilbronn.pyx | 8 ++++---- src/sage/modular/pollack_stevens/dist.pyx | 2 +- src/sage/plot/plot3d/list_plot3d.py | 2 +- src/sage/rings/finite_rings/finite_field_base.pyx | 2 +- src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx | 2 +- src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx | 2 +- src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx | 2 +- src/sage/rings/padics/qadic_flint_CR.pyx | 2 +- src/sage/rings/padics/qadic_flint_FP.pyx | 2 +- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/elliptic_curves/saturation.py | 2 +- .../schemes/hyperelliptic_curves/monsky_washnitzer.py | 2 +- src/sage/stats/hmm/hmm.pyx | 2 +- src/sage/symbolic/relation.py | 2 +- 38 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 5aea58d06bf..e97dd879375 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -40,7 +40,7 @@ from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint from sage.rings.number_field.number_field_element cimport NumberFieldElement from sage.rings.all import PolynomialRing -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.libs.gmp.mpz cimport * diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 83f3a957d17..72b609c1b94 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -223,7 +223,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, is_complex = isinstance(z, ComplexNumber) n = degree+1 - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix M = matrix(ZZ, n, n+1+int(is_complex)) r = ZZ.one() << prec M[0, 0] = 1 diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 0b8668f8521..6a06f755101 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,7 +1,7 @@ r""" Calculus functions """ -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.structure.element import is_Vector from sage.symbolic.ring import is_SymbolicVariable diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index ca7f80cfc4f..199db9257a7 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -87,7 +87,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.matrix.constructor import block_diagonal_matrix from sage.rings.integer_ring import ZZ from sage.groups.perm_gps.permgroup import PermutationGroup diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index ec28a9887ef..59abf94470f 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -1545,7 +1545,7 @@ def g_matrix(self, show_warnings=True): ValueError: Unable to calculate g-vectors. Need to use g vectors. """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix if self._use_g_vec: return copy(self._G) elif self._use_fpolys and self._cluster: # This only calls g_vector when it will not create a loop. @@ -3036,7 +3036,7 @@ def universal_extension(self): "for finite type cluster algebras at a " "bipartite initial cluster") - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.combinat.root_system.cartan_matrix import CartanMatrix A = 2 - self.b_matrix().apply_map(abs).transpose() 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 b819aed8966..ef3eb1e6d5d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -27,7 +27,7 @@ from sage.graphs.all import Graph, DiGraph from sage.arith.all import binomial, euler_phi from sage.all import prod -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix class QuiverMutationTypeFactory(SageObject): diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 45be6c01400..367facaa301 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -129,7 +129,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ from sage.rings.all import Integer from sage.matrix.matrix_integer_dense import Matrix_integer_dense diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 9bc3f1d8720..9298575d580 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -170,7 +170,7 @@ from bisect import bisect_left, bisect_right from sage.structure.element import is_Matrix -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 83f3564c246..c98d02324d8 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -18,7 +18,7 @@ #***************************************************************************** from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix import sage.combinat.partition import sage.data_structures.blas_dict as blas from . import classical diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index e2a2f18f775..4fd478c8f94 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -22,7 +22,7 @@ from sage.libs.symmetrica.all import hall_littlewood from . import sfa import sage.combinat.partition -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom from sage.rings.rational_field import QQ diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 625f76e8521..fbc7979936b 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -18,7 +18,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from . import multiplicative -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix class SymmetricFunctionAlgebra_witt(multiplicative.SymmetricFunctionAlgebra_multiplicative): r""" diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index eb3a06fb6b4..f59113ef04f 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -1529,7 +1529,7 @@ def is_root_independent(self): sage: SC.is_root_independent() True """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix M = matrix(self.greedy_facet(side="negative").root_configuration()) return M.rank() == max(M.ncols(), M.nrows()) diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index ee60bb1e255..6263dfea7cb 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -21,7 +21,7 @@ from sage.categories.weyl_groups import WeylGroups from sage.rings.all import QQ, PolynomialRing from sage.arith.all import factorial -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.misc.persist import register_unpickle_override diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 164371a1c8a..04a0a73400d 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -251,7 +251,7 @@ from sage.geometry.toric_lattice import ToricLattice, is_ToricLattice from sage.geometry.toric_plotter import ToricPlotter from sage.graphs.digraph import DiGraph -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.all import walltime, prod from sage.modules.all import vector, span diff --git a/src/sage/geometry/point_collection.pyx b/src/sage/geometry/point_collection.pyx index 2172b4d7291..8b2f7e26828 100644 --- a/src/sage/geometry/point_collection.pyx +++ b/src/sage/geometry/point_collection.pyx @@ -80,7 +80,7 @@ from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport richcmp_not_equal, richcmp from sage.geometry.toric_lattice import ToricLattice -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.latex import latex diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index d4eac87cee0..de1037ebe99 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -391,7 +391,7 @@ cdef class CombinatorialPolyhedron(SageObject): self._n_Hrepresentation = len(facets) far_face = tuple(i for i in range(len(Vrep) - 1)) self._dimension = data.dim() - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.rings.all import ZZ data = matrix(ZZ, data.incidence_matrix().rows() + [[ZZ.one() for _ in range(len(facets))]]) @@ -442,7 +442,7 @@ cdef class CombinatorialPolyhedron(SageObject): if not isinstance(data, Matrix_integer_dense): from sage.rings.all import ZZ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix data = matrix(ZZ, data, sparse=False) assert isinstance(data, Matrix_integer_dense), "conversion to ``Matrix_integer_dense`` didn't work" diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index b4ac8242f96..184efa9be0b 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -52,7 +52,7 @@ from sage.groups.abelian_gps.abelian_aut import AbelianGroupAutomorphismGroup_subgroup, AbelianGroupAutomorphism, AbelianGroupAutomorphismGroup_gap from sage.modules.torsion_quadratic_module import TorsionQuadraticModule from sage.rings.integer_ring import ZZ -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.categories.action import Action diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index d4d9849684d..cef211ea07c 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -66,7 +66,7 @@ from sage.rings.all import QQbar from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.structure.sequence import Sequence from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 767d7525bd5..7fc8ce6c537 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -33,7 +33,7 @@ from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 3b33827969e..1d942d497d7 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1713,7 +1713,7 @@ def _matrix_(self, R): sage: matrix(ZZ, m.transpose()).dimensions() # optional - macaulay2 (0, 2) """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix m = matrix(R, self.entries()._sage_()) if not m.nrows(): return matrix(R, 0, self.numcols()._sage_()) diff --git a/src/sage/interfaces/matlab.py b/src/sage/interfaces/matlab.py index 5f72363b520..986dc665b39 100644 --- a/src/sage/interfaces/matlab.py +++ b/src/sage/interfaces/matlab.py @@ -343,7 +343,7 @@ def _matrix_(self, R): 50 x 50 dense matrix over Real Field with 53 bits of precision """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix matlab = self.parent() entries = matlab.strip_answer(matlab.eval("mat2str({0})".format(self.name()))) entries = entries.strip()[1:-1].replace(';', ' ') diff --git a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi index 81b47988b39..b797782c657 100644 --- a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi +++ b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi @@ -864,5 +864,5 @@ cdef cmatrix_mod_pn(celement a, long aprec, long valshift, PowComputer_ prime_po L[-1].append(zero) fmpz_poly_shift_left(prime_pow.poly_matmod, prime_pow.poly_matmod, 1) creduce(prime_pow.poly_matmod, prime_pow.poly_matmod, aprec, prime_pow) - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(R, deg, deg, L) diff --git a/src/sage/matrix/strassen.pyx b/src/sage/matrix/strassen.pyx index c5c53c32640..c42f131cfa0 100644 --- a/src/sage/matrix/strassen.pyx +++ b/src/sage/matrix/strassen.pyx @@ -801,7 +801,7 @@ def test(n, m, R, c=2): 3 True 4 True """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix A = matrix(R,n,m,range(n*m)) B = A.__copy__(); B._echelon_in_place_classical() C = A.__copy__(); C._echelon_strassen(c) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 5995ef1bb1b..1c27f95d868 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -551,7 +551,7 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): # Create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1), sparse=False) original_base_ring = R.base_ring() @@ -684,7 +684,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) # Create a zero dense matrix over K with len(indices) rows # and #P^1(N) columns. cdef Matrix_cyclo_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix T = matrix(K, len(indices), len(P1), sparse=False) cdef Py_ssize_t i, j @@ -778,7 +778,7 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): # Create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix T = matrix(QQ, len(indices), len(P1), sparse=False) if R.base_ring() != QQ: @@ -868,7 +868,7 @@ def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): # So we create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) * (k-1) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1)*(k-1), sparse=False) diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index dd3e154b59b..65942454937 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -37,7 +37,7 @@ from sage.arith.all import binomial, bernoulli from sage.modules.free_module_element import vector, zero_vector from sage.matrix.matrix cimport Matrix from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.prandom import random from sage.functions.other import floor from sage.structure.element cimport RingElement, Element diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 875165ee972..ba6ce73a0bd 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -3,7 +3,7 @@ """ from sage.structure.element import is_Matrix -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.all import RDF from sage.misc.superseded import deprecation diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 35da225308b..39e73253dcd 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1257,7 +1257,7 @@ cdef class FiniteField(Field): inclusion_map = self.coerce_map_from(base) from sage.modules.free_module_element import vector - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from .maps_finite_field import ( MorphismVectorSpaceToFiniteField, MorphismFiniteFieldToVectorSpace) diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index 225c52efa83..2055d4d46c2 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -1972,7 +1972,7 @@ cdef class pAdicZZpXCAElement(pAdicZZpXElement): [1590 1375 1695 1032 2358] [2415 590 2370 2970 1032] """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix # this may be the wrong precision when ram_prec_cap is not divisible by e. R = IntegerModRing(self.prime_pow.pow_Integer(self.prime_pow.capdiv(self.absprec))) n = self.prime_pow.deg diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index db39fab2b60..8d44034b121 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -2859,7 +2859,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): if self.valuation_c() < 0: raise ValueError("self must be integral") n = self.prime_pow.deg - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix if self._is_exact_zero(): from sage.rings.integer_ring import IntegerRing return matrix(IntegerRing(), n, n) diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index 9c0bcff4f69..c58954582ea 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -1032,7 +1032,7 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): [1590 1375 1695 1032 2358] [2415 590 2370 2970 1032] """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix R = IntegerModRing(self.prime_pow.pow_Integer(self.prime_pow.prec_cap)) n = self.prime_pow.deg L = [] diff --git a/src/sage/rings/padics/qadic_flint_CR.pyx b/src/sage/rings/padics/qadic_flint_CR.pyx index 2568578a780..eaedb7a6c12 100644 --- a/src/sage/rings/padics/qadic_flint_CR.pyx +++ b/src/sage/rings/padics/qadic_flint_CR.pyx @@ -64,7 +64,7 @@ cdef class qAdicCappedRelativeElement(CRElement): if self.ordp < 0: raise ValueError("self must be integral") if exactzero(self.ordp): - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(ZZ, self.prime_pow.deg, self.prime_pow.deg) else: return cmatrix_mod_pn(self.unit, self.ordp + self.relprec, self.ordp, self.prime_pow) diff --git a/src/sage/rings/padics/qadic_flint_FP.pyx b/src/sage/rings/padics/qadic_flint_FP.pyx index 2b6730c7770..949e132199c 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pyx +++ b/src/sage/rings/padics/qadic_flint_FP.pyx @@ -66,7 +66,7 @@ cdef class qAdicFloatingPointElement(FPElement): if self.ordp < 0: raise ValueError("self must be integral") if very_pos_val(self.ordp): - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(ZZ, self.prime_pow.deg, self.prime_pow.deg) else: return cmatrix_mod_pn(self.unit, self.ordp + self.prime_pow.prec_cap, self.ordp, self.prime_pow) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 9fd99a3b3fc..d0d24f4419b 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -135,7 +135,7 @@ from sage.categories.homset import Hom, End, hom from sage.categories.number_fields import NumberFields -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.all import degree_lowest_rational_function from sage.rings.number_field.number_field import NumberField diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 0e6ba6a1e4b..291369dab8d 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -145,7 +145,7 @@ from sage.categories.homset import Hom, End from sage.interfaces.all import singular -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.all import add, sage_eval from sage.rings.all import degree_lowest_rational_function, IntegerRing diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index d8037db8877..14b172cacbb 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -463,7 +463,7 @@ def p_saturation(self, Plist, p, sieve=True): if verbose: print("Using sieve method to saturate...") - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.sets.primes import Primes A = matrix(GF(p), 0, n) diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 8bf87c92827..af3f5e625d5 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -49,7 +49,7 @@ from sage.arith.all import binomial, integer_ceil as ceil from sage.functions.log import log from sage.functions.other import floor -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.misc import newton_method_sizes from sage.misc.profiler import Profiler diff --git a/src/sage/stats/hmm/hmm.pyx b/src/sage/stats/hmm/hmm.pyx index cb3810dc3fe..568b601ac30 100644 --- a/src/sage/stats/hmm/hmm.pyx +++ b/src/sage/stats/hmm/hmm.pyx @@ -36,7 +36,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.finance.time_series cimport TimeSeries from sage.structure.element import is_Matrix -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.randstate cimport current_randstate, randstate from cpython.object cimport PyObject_RichCompare diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 7c767901baf..da9dcc0a8b1 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1572,7 +1572,7 @@ def solve_mod(eqns, modulus, solution_dict=False): from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator from sage.modules.free_module_element import vector - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] From d070bffec5f17bf6a945fe5fbe35042b2a05a27b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:12:40 -0700 Subject: [PATCH 200/355] git grep -l 'all import RDF' src/sage | xargs sed -i.bak 's/sage[.]rings[.]all import RDF *$/sage.rings.real_double import RDF/' --- src/sage/functions/spike_function.py | 2 +- src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py | 2 +- src/sage/geometry/hyperplane_arrangement/hyperplane.py | 2 +- src/sage/geometry/polyhedron/backend_normaliz.py | 2 +- src/sage/geometry/polyhedron/base_RDF.py | 2 +- src/sage/geometry/polyhedron/cdd_file_format.py | 4 ++-- src/sage/geometry/polyhedron/plot.py | 2 +- src/sage/geometry/toric_plotter.py | 2 +- src/sage/groups/perm_gps/cubegroup.py | 2 +- src/sage/interfaces/axiom.py | 4 ++-- src/sage/interfaces/polymake.py | 2 +- src/sage/media/wav.py | 2 +- src/sage/numerical/backends/cvxopt_sdp_backend.pyx | 4 ++-- src/sage/numerical/backends/generic_backend.pyx | 2 +- src/sage/numerical/backends/generic_sdp_backend.pyx | 2 +- src/sage/plot/matrix_plot.py | 2 +- src/sage/plot/plot.py | 4 ++-- src/sage/plot/plot3d/implicit_surface.pyx | 2 +- src/sage/plot/plot3d/list_plot3d.py | 2 +- src/sage/plot/plot3d/parametric_surface.pyx | 2 +- src/sage/plot/plot3d/platonic.py | 2 +- src/sage/stats/hmm/chmm.pyx | 2 +- src/sage/stats/hmm/hmm.pyx | 4 ++-- src/sage/symbolic/ring.pyx | 2 +- 24 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 2ea29f292d2..4e6b43d86c6 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -21,7 +21,7 @@ from sage.plot.all import line from sage.modules.free_module_element import vector -from sage.rings.all import RDF +from sage.rings.real_double import RDF class SpikeFunction: diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 08beb8fc76a..896dc71be58 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -50,7 +50,7 @@ from sage.modules.free_module_element import vector from sage.rings.infinity import infinity from sage.misc.latex import latex -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.functions.other import imag, sqrt from sage.functions.all import arccosh, sign diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 1f125bca8f4..fd5bb34da7f 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -247,7 +247,7 @@ def _normal_pivot(self): try: values = [abs(x) for x in self.A()] except ArithmeticError: - from sage.rings.all import RDF + from sage.rings.real_double import RDF values = [abs(RDF(x)) for x in self.A()] max_pos = 0 max_value = values[max_pos] diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index ce7bede84a8..1a3d53eef31 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -955,7 +955,7 @@ def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ from sage.categories.number_fields import NumberFields - from sage.rings.all import RDF + from sage.rings.real_double import RDF if self.base_ring() in (QQ, ZZ): normaliz_field = QQ diff --git a/src/sage/geometry/polyhedron/base_RDF.py b/src/sage/geometry/polyhedron/base_RDF.py index 7f4fc7334ad..38485ed396a 100644 --- a/src/sage/geometry/polyhedron/base_RDF.py +++ b/src/sage/geometry/polyhedron/base_RDF.py @@ -2,7 +2,7 @@ Base class for polyhedra over ``RDF`` """ -from sage.rings.all import RDF +from sage.rings.real_double import RDF from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/cdd_file_format.py b/src/sage/geometry/polyhedron/cdd_file_format.py index e08c7eccad4..78fd01787b7 100644 --- a/src/sage/geometry/polyhedron/cdd_file_format.py +++ b/src/sage/geometry/polyhedron/cdd_file_format.py @@ -61,7 +61,7 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): num += 1 if cdd_type == 'real': - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF else: base_ring = None @@ -121,7 +121,7 @@ def cdd_Hrepresentation(cdd_type, ieqs, eqns, file_output=None): ambient_dim -= 1 if cdd_type == 'real': - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF else: base_ring = None diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 7b4eace75ef..099ca77eb1f 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -11,7 +11,7 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.structure.sage_object import SageObject from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 568fae8d8da..5afd455ed20 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -55,7 +55,7 @@ from sage.plot.all import (Color, Graphics, arrow, disk, line, point, polygon, rainbow, text) from sage.plot.plot3d.all import text3d -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.structure.sage_object import SageObject diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 1e32c439688..dfdd6d52e74 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -98,7 +98,7 @@ from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp, richcmp_method -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.interfaces.all import gap from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.plot.polygon import polygon diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 09016ab1f67..50991843902 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -841,7 +841,7 @@ def _sage_(self): x,e,b = self.unparsed_input_form().lstrip('float(').rstrip(')').split(',') return R(ZZ(x)*ZZ(b)**ZZ(e)) elif type == "DoubleFloat": - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF(repr(self)) elif type in ["PositiveInteger", "Integer"]: from sage.rings.integer_ring import ZZ @@ -889,7 +889,7 @@ def _sage_domain(self): from sage.rings.integer_ring import ZZ return ZZ elif name == 'DoubleFloat': - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF elif name.startswith('Fraction '): return P(name.lstrip('Fraction '))._sage_domain().fraction_field() diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 48282c7158a..5e0e481ba54 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -1561,7 +1561,7 @@ def _sage_(self): r = self._repr_() if 'Float' in T1: - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF str_to_base_ring = lambda s: RDF(s) elif 'QuadraticExtension' in T1 and 'r' in r: diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index cef295e7e94..e1ec4f6b21c 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -42,7 +42,7 @@ from sage.structure.sage_object import SageObject from sage.arith.srange import srange from sage.misc.html import html -from sage.rings.all import RDF +from sage.rings.real_double import RDF class Wave(SageObject): diff --git a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx index ced0da89b05..c654f7f21a2 100644 --- a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx @@ -40,7 +40,7 @@ cdef class CVXOPTSDPBackend(MatrixSDPBackend): """ - from sage.rings.all import RDF + from sage.rings.real_double import RDF if base_ring is None: base_ring = RDF if base_ring is not RDF: @@ -101,7 +101,7 @@ cdef class CVXOPTSDPBackend(MatrixSDPBackend): """ from cvxopt import matrix as c_matrix, solvers - from sage.rings.all import RDF + from sage.rings.real_double import RDF G_matrix = [] h_matrix = [] debug_g = [] diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index f386a97a6ad..bc4cc83741b 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -34,7 +34,7 @@ from copy import copy cdef class GenericBackend: cpdef base_ring(self): - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF cpdef zero(self): diff --git a/src/sage/numerical/backends/generic_sdp_backend.pyx b/src/sage/numerical/backends/generic_sdp_backend.pyx index 1ad7bddc186..bff1e940b8f 100644 --- a/src/sage/numerical/backends/generic_sdp_backend.pyx +++ b/src/sage/numerical/backends/generic_sdp_backend.pyx @@ -39,7 +39,7 @@ cdef class GenericSDPBackend: sage: GenericSDPBackend().base_ring() Real Double Field """ - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF cpdef zero(self): diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index 4b92b3a16c1..041405f2171 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -562,7 +562,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): import scipy.sparse as scipysparse from sage.plot.all import Graphics from sage.structure.element import is_Matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF orig_mat=mat if is_Matrix(mat): sparse = mat.is_sparse() diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 7b0e33ed489..2f08cb2b994 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2390,7 +2390,7 @@ def golden_rainbow(i,lightness=0.4): if excluded_points or detect_poles: start_index = 0 # setup for pole detection - from sage.rings.all import RDF + from sage.rings.real_double import RDF epsilon = 0.0001 pole_options = {} pole_options['linestyle'] = '--' @@ -3023,7 +3023,7 @@ def list_plot(data, plotjoined=False, **kwargs): list_data = list(data.items()) return list_plot(list_data, plotjoined=plotjoined, **kwargs) try: - from sage.rings.all import RDF + from sage.rings.real_double import RDF RDF(data[0]) data = list(enumerate(data)) except TypeError: # we can get this TypeError if the element is a list diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index c9828cbd195..6efc85eb10f 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -84,7 +84,7 @@ from sage.plot.plot3d.transform cimport point_c, face_c, color_c, Transformation from sage.plot.plot3d.base cimport PrimitiveObject from sage.plot.plot3d.base import RenderParams, default_texture from sage.plot.plot3d.index_face_set cimport IndexFaceSet -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.plot.misc import setup_for_eval_on_grid from sage.plot.colors import check_color_data diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index ba6ce73a0bd..62894bef1a0 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -4,7 +4,7 @@ from sage.structure.element import is_Matrix from sage.matrix.constructor import matrix -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.misc.superseded import deprecation diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 42d3cb37430..201f3a21634 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -87,7 +87,7 @@ from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_check from math import cos, sin -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.plot.colors import check_color_data from .base import RenderParams diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index 5e6019d4989..8fdb45f5a54 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -65,7 +65,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.matrix.constructor import matrix from sage.misc.decorators import rename_keyword from .shapes import Box, ColorCube diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 94fb8b6e31e..d9ef328da92 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -315,7 +315,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): [(1.0, 0.5), (-1.0, 3.0)] """ cdef Py_ssize_t i - from sage.rings.all import RDF + from sage.rings.real_double import RDF return [(RDF(self.B[2*i]),RDF(self.B[2*i+1])) for i in range(self.N)] def __repr__(self): diff --git a/src/sage/stats/hmm/hmm.pyx b/src/sage/stats/hmm/hmm.pyx index 568b601ac30..7f89eeb1c89 100644 --- a/src/sage/stats/hmm/hmm.pyx +++ b/src/sage/stats/hmm/hmm.pyx @@ -112,7 +112,7 @@ cdef class HiddenMarkovModel: [0.4 0.6] """ from sage.matrix.constructor import matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF return matrix(RDF, self.N, self.A.list()) def graph(self, eps=1e-3): @@ -409,7 +409,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): [0.5 0.5] """ from sage.matrix.constructor import matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF return matrix(RDF, self.N, self.n_out, self.B.list()) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 3047fce842e..c3eaf32a538 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1195,7 +1195,7 @@ cdef class NumpyToSRMorphism(Morphism): from sage.rings.integer_ring import ZZ self._intermediate_ring = ZZ elif issubclass(numpy_type, numpy.floating): - from sage.rings.all import RDF + from sage.rings.real_double import RDF self._intermediate_ring = RDF elif issubclass(numpy_type, numpy.complexfloating): from sage.rings.all import CDF From 234451425cb5aeac659ddf25dbbab78cc5ba05a0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 20:15:14 -0700 Subject: [PATCH 201/355] git grep -l 'all import SR' src/sage | xargs sed -i.bak 's/sage.*[.]all import SR *$/sage.symbolic.ring import SR/' --- src/sage/functions/orthogonal_polys.py | 2 +- src/sage/functions/other.py | 2 +- src/sage/geometry/hyperbolic_space/hyperbolic_model.py | 2 +- src/sage/geometry/hyperplane_arrangement/plot.py | 2 +- src/sage/interfaces/maple.py | 2 +- src/sage/numerical/interactive_simplex_method.py | 2 +- src/sage/rings/integer.pyx | 2 +- src/sage/rings/rational.pyx | 4 ++-- src/sage/schemes/elliptic_curves/height.py | 2 +- src/sage/symbolic/expression.pyx | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 9b5636f3fdc..9bb670ff510 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -309,7 +309,7 @@ from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.symbolic.expression import Expression -from sage.symbolic.all import SR +from sage.symbolic.ring import SR from sage.functions.other import factorial, binomial from sage.structure.all import parent diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 68287710987..238945aad2b 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -21,7 +21,7 @@ from sage.symbolic.function import GinacFunction, BuiltinFunction from sage.symbolic.expression import Expression from sage.libs.pynac.pynac import (register_symbol, symbol_table, I) -from sage.symbolic.all import SR +from sage.symbolic.ring import SR from sage.rings.all import Integer, Rational, RealField, ZZ, ComplexField from sage.misc.latex import latex from sage.structure.element import Element diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 9ccbb7caa63..3bb58fafd78 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -1479,7 +1479,7 @@ def get_background_graphic(self, **bdry_options): sage: H = HyperbolicPlane().HM().get_background_graphic() """ from sage.plot.plot3d.all import plot3d - from sage.all import SR + from sage.symbolic.ring import SR hyperboloid_opacity = bdry_options.get('hyperboloid_opacity', .1) z_height = bdry_options.get('z_height', 7.0) x_max = sqrt((z_height ** 2 - 1) / 2.0) diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index a85923eee94..a8750290fb8 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -113,7 +113,7 @@ from sage.plot.text import text from sage.plot.point import point from sage.plot.plot import parametric_plot -from sage.symbolic.all import SR +from sage.symbolic.ring import SR def plot(hyperplane_arrangement, **kwds): diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index 4ddb8424cf4..ff201d48fec 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -1222,7 +1222,7 @@ def _sage_(self): elif maple_type == '`=`': # (1, 1) = 2 return (self.op(1)._sage_() == self.op(2)._sage()) try: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(result) except Exception: raise NotImplementedError("Unable to parse Maple output: %s" % result) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 8edecb5ed5c..4386e6f2e9e 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -199,7 +199,7 @@ from sage.plot.all import Graphics, arrow, line, point, rainbow, text from sage.rings.all import Infinity, PolynomialRing, QQ, RDF, ZZ from sage.structure.all import SageObject -from sage.symbolic.all import SR +from sage.symbolic.ring import SR # We produce rather complicated LaTeX code which needs some tweaks to be diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 4e79c64fca6..c6598c3149a 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2807,7 +2807,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise ValueError("log base must be positive") self_sgn = mpz_sgn(self.value) if self_sgn < 0 and prec is None: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).log(m) if prec: if self_sgn >= 0: diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 58e7be8dedd..0a6c018fd07 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -3163,7 +3163,7 @@ cdef class Rational(sage.structure.element.FieldElement): raise ValueError("log base must be positive") self_sgn = mpz_sgn(mpq_numref(self.value)) if self_sgn < 0 and prec is None: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).log(m) if prec: if self_sgn >= 0: @@ -3261,7 +3261,7 @@ cdef class Rational(sage.structure.element.FieldElement): from sage.functions.all import sqrt return sqrt(pi) * rat_part else: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).gamma() def floor(self): diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 599f69ba1eb..b717369aac8 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -36,7 +36,7 @@ from sage.arith.all import lcm, factorial from sage.ext.fast_callable import fast_callable from sage.functions.log import log, exp -from sage.symbolic.all import SR +from sage.symbolic.ring import SR class UnionOfIntervals: diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index cf4dfd61a55..c2d9a68d5bd 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -7425,7 +7425,7 @@ cdef class Expression(CommutativeRingElement): ... TypeError: y is not a variable of Multivariate Polynomial Ring in x over Ring of integers modulo 4 """ - from sage.symbolic.all import SR + from sage.symbolic.ring import SR from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing base_ring = R.base_ring() if base_ring == SR: From b552ee8aac1acb5d2e05bacf25586b6916ed9b46 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 23:31:05 -0700 Subject: [PATCH 202/355] src/sage/geometry: Remove remaining imports from sage.all, sage.{rings,modules,misc,categories,matrix}.all --- src/sage/geometry/cone.py | 18 ++++++++++++------ src/sage/geometry/fan.py | 9 ++++++--- src/sage/geometry/fan_morphism.py | 12 ++++++++---- .../hyperbolic_space/hyperbolic_geodesic.py | 3 ++- .../hyperbolic_space/hyperbolic_model.py | 4 +++- .../hyperbolic_space/hyperbolic_point.py | 3 ++- .../hyperplane_arrangement/affine_subspace.py | 2 +- .../hyperplane_arrangement/arrangement.py | 7 ++++--- .../geometry/hyperplane_arrangement/library.py | 4 +++- src/sage/geometry/integral_points.pyx | 4 +++- src/sage/geometry/lattice_polytope.py | 7 +++++-- src/sage/geometry/linear_expression.py | 4 ++-- .../geometry/polyhedron/backend_normaliz.py | 3 ++- src/sage/geometry/polyhedron/base.py | 9 +++++---- src/sage/geometry/polyhedron/base_ZZ.py | 3 ++- src/sage/geometry/polyhedron/constructor.py | 7 +++++-- src/sage/geometry/polyhedron/library.py | 8 ++++++-- src/sage/geometry/polyhedron/parent.py | 5 ++++- .../geometry/polyhedron/ppl_lattice_polygon.py | 2 +- src/sage/geometry/toric_lattice.py | 3 ++- src/sage/geometry/triangulation/element.py | 3 ++- .../triangulation/point_configuration.py | 3 ++- src/sage/geometry/voronoi_diagram.py | 4 +++- 23 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 39a2f902c50..b9458595ad8 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -216,11 +216,16 @@ from sage.geometry.toric_plotter import ToricPlotter, label_list from sage.geometry.relative_interior import RelativeInterior from sage.graphs.digraph import DiGraph -from sage.matrix.all import column_matrix, matrix, MatrixSpace +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.special import column_matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import flatten, latex -from sage.modules.all import span, vector, VectorSpace -from sage.rings.all import QQ, ZZ +from sage.misc.flatten import flatten +from sage.misc.latex import latex +from sage.modules.free_module import span, VectorSpace +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.all import SageObject, parent from sage.structure.richcmp import richcmp_method, richcmp from sage.geometry.integral_points import parallelotope_points @@ -591,8 +596,6 @@ def _ambient_space_point(body, data): (1.00000000000000, 3.14159265358979) """ - from sage.rings.all import AA, RR - L = body.lattice() def try_base_extend(ring): @@ -617,6 +620,9 @@ def try_base_extend(ring): # If we don't have a lattice element, try successively # less-desirable ambient spaces until (as a last resort) we # attempt a numerical representation. + from sage.rings.qqbar import AA + from sage.rings.real_mpfr import RR + for ring in [QQ, AA, RR]: p = try_base_extend(ring) if p is not None: diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 04a0a73400d..5f8754941d4 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -253,9 +253,12 @@ from sage.graphs.digraph import DiGraph from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import walltime, prod -from sage.modules.all import vector, span -from sage.rings.all import QQ, ZZ +from sage.misc.misc import walltime +from sage.misc.misc_c import prod +from sage.modules.free_module import span +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ def is_Fan(x): diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index e17b155ed6c..5b3cff567be 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -77,16 +77,20 @@ import operator -from sage.categories.all import Hom +from sage.categories.homset import Hom from sage.geometry.cone import Cone from sage.geometry.fan import Fan, is_Fan -from sage.matrix.all import identity_matrix, matrix +from sage.matrix.constructor import matrix +from sage.matrix.special import identity_matrix from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import latex, prod, walltime +from sage.misc.latex import latex +from sage.misc.misc import walltime +from sage.misc.misc_c import prod from sage.modules.free_module_morphism import (FreeModuleMorphism, is_FreeModuleMorphism) -from sage.rings.all import Infinity, ZZ +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ from sage.rings.infinity import is_Infinite from functools import reduce diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 9ec022099d0..1cb2ac069c4 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -86,7 +86,8 @@ from sage.symbolic.constants import I from sage.misc.lazy_attribute import lazy_attribute from sage.rings.infinity import infinity -from sage.rings.all import CC, RR +from sage.rings.all import CC +from sage.rings.real_mpfr import RR from sage.plot.arc import arc from sage.plot.line import line from sage.symbolic.constants import pi diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 3bb58fafd78..6a891b88046 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -83,7 +83,9 @@ from sage.misc.lazy_import import lazy_import from sage.functions.other import imag, real, sqrt from sage.functions.all import arccosh -from sage.rings.all import CC, RR, RDF +from sage.rings.all import CC +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from sage.rings.infinity import infinity from sage.symbolic.constants import I from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index 570a1cd7310..2fba9b50df9 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -68,7 +68,8 @@ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.rings.infinity import infinity -from sage.rings.all import RR, CC +from sage.rings.all import CC +from sage.rings.real_mpfr import RR from sage.functions.other import real, imag from sage.geometry.hyperbolic_space.hyperbolic_isometry import HyperbolicIsometry diff --git a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py index 7ce7a70e7b5..cc7314f2505 100644 --- a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py +++ b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py @@ -108,7 +108,7 @@ def __init__(self, p, V): (0, 0, 0, 0) """ R = V.base_ring() - from sage.categories.all import Fields + from sage.categories.fields import Fields if R not in Fields(): R = R.fraction_field() V = V.change_ring(R) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index ed2a048d38a..1914442251c 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -348,7 +348,8 @@ from sage.structure.element import Element from sage.structure.richcmp import richcmp from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix, vector from sage.modules.free_module import VectorSpace @@ -1240,7 +1241,7 @@ def has_good_reduction(self, p): raise TypeError('arrangement must be defined over QQ') if not p.is_prime(): raise TypeError('must reduce modulo a prime number') - from sage.rings.all import GF + from sage.rings.finite_rings.finite_field_constructor import GF a = self.change_ring(GF(p)) p = self.intersection_poset() q = a.intersection_poset() @@ -3402,7 +3403,7 @@ def __init__(self, base_ring, names=tuple()): sage: K = HyperplaneArrangements(QQ) sage: TestSuite(K).run() """ - from sage.categories.all import Sets + from sage.categories.sets_cat import Sets from sage.rings.ring import _Fields if base_ring not in _Fields: raise ValueError('base ring must be a field') diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 55fb1e056f0..cd66827debb 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -14,7 +14,9 @@ from sage.graphs.all import graphs from sage.matrix.constructor import matrix, random_matrix -from sage.rings.all import QQ, ZZ, NN +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.misc.misc_c import prod from sage.combinat.combinat import stirling_number2 diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index 7ba6d62e03f..8db5599877f 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -18,7 +18,9 @@ import copy import itertools from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix -from sage.rings.all import QQ, RR, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RR from sage.rings.integer cimport Integer from sage.arith.all import gcd, lcm from sage.combinat.permutation import Permutation diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index a05dbb474d7..8181a910e6e 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -125,13 +125,16 @@ from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import flatten, tmp_filename +from sage.misc.flatten import flatten +from sage.misc.temporary_file import tmp_filename from sage.modules.free_module_element import vector from sage.numerical.mip import MixedIntegerLinearProgram from sage.plot.plot3d.index_face_set import IndexFaceSet from sage.plot.plot3d.all import line3d, point3d from sage.plot.plot3d.shapes2 import text3d -from sage.rings.all import Integer, ZZ, QQ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.sets.set import Set_generic from sage.structure.all import Sequence from sage.structure.sage_object import SageObject diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index be20596ca50..dbe09170c4c 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -685,7 +685,7 @@ def ambient_module(self): sage: M.ambient_vector_space() Vector space of dimension 2 over Rational Field """ - from sage.modules.all import FreeModule + from sage.modules.free_module import FreeModule return FreeModule(self.base_ring(), self.ngens()) @cached_method @@ -714,7 +714,7 @@ def ambient_vector_space(self): sage: M.ambient_vector_space() Vector space of dimension 2 over Rational Field """ - from sage.modules.all import VectorSpace + from sage.modules.free_module import VectorSpace field = self.base_ring().fraction_field() return VectorSpace(field, self.ngens()) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 1a3d53eef31..cb2568b751f 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -31,7 +31,8 @@ lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], feature=PythonModule("PyNormaliz", spkg="pynormaliz")) -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.functions import LCM_list from sage.misc.functional import denominator from sage.matrix.constructor import vector diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 183d862978a..ee8e73abd9b 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -41,7 +41,9 @@ from sage.misc.randstate import current_randstate from sage.misc.superseded import deprecated_function_alias -from sage.rings.all import QQ, ZZ, AA +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import AA +from sage.rings.rational_field import QQ from sage.rings.real_double import RDF from sage.modules.free_module_element import vector from sage.modules.vector_space_morphism import linear_transformation @@ -671,9 +673,8 @@ def change_ring(self, base_ring, backend=None): A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex sage: P.n_vertices() == Q.n_vertices() False - """ - - from sage.categories.all import Rings + """ + from sage.categories.rings import Rings if base_ring not in Rings: raise ValueError("invalid base ring") diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index aabb5806504..8015f360560 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -12,7 +12,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector from .base_QQ import Polyhedron_QQ diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 7f68ca41ce0..0accb54847f 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -292,7 +292,9 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import ZZ, RDF, RR +from sage.rings.integer_ring import ZZ +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from .misc import _make_listlist, _common_length_of @@ -615,7 +617,8 @@ def Polyhedron(vertices=None, rays=None, lines=None, # figure out base_ring from sage.misc.flatten import flatten from sage.structure.element import parent - from sage.categories.all import Rings, Fields + from sage.categories.fields import Fields + from sage.categories.rings import Rings values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index f522df556b3..103ad0374f3 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -81,7 +81,11 @@ import itertools -from sage.rings.all import ZZ, QQ, RDF, RR, AA, QQbar +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import AA, QQbar +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from sage.combinat.permutation import Permutations from sage.groups.perm_gps.permgroup_named import AlternatingGroup from .constructor import Polyhedron @@ -440,7 +444,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): ValueError: input vectors not totally cyclic """ from sage.modules.free_module_element import vector - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix if base_ring: vectors = tuple(vector(base_ring, x) for x in vectors) else: diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 7f14eb0766e..140a4925d0c 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -14,7 +14,10 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.modules.free_module import FreeModule, is_FreeModule from sage.misc.cachefunc import cached_method, cached_function -from sage.rings.all import ZZ, QQ, RDF, CommutativeRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.rings.ring import CommutativeRing from sage.categories.fields import Fields from sage.categories.rings import Rings from sage.categories.modules import Modules diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index 75135c37d1a..03343dc6f9f 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -20,7 +20,7 @@ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method, cached_function -from sage.modules.all import (vector, zero_vector) +from sage.modules.free_module_element import vector, zero_vector from sage.matrix.constructor import (matrix, zero_matrix, block_matrix) from ppl import C_Polyhedron, Poly_Con_Relation from sage.geometry.polyhedron.lattice_euclidean_group_element import ( diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index 5e82dcec7c3..e8920bfb701 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -158,7 +158,8 @@ FreeModule_generic_pid, FreeModule_submodule_pid, FreeModule_submodule_with_basis_pid) -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.factory import UniqueFactory diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 736bccd1721..9aea06b7fb5 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -41,7 +41,8 @@ from sage.structure.richcmp import richcmp from sage.structure.element import Element -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.modules.free_module_element import vector from sage.misc.cachefunc import cached_method from sage.sets.set import Set diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index b9bc8c48036..0346c9cdac4 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -184,7 +184,8 @@ from sage.misc.cachefunc import cached_method from sage.combinat.combination import Combinations -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1c26764323e..1859a5e0c1a 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -15,7 +15,9 @@ from sage.structure.sage_object import SageObject from sage.geometry.polyhedron.constructor import Polyhedron -from sage.all import RDF, QQ, AA +from sage.rings.qqbar import AA +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF from sage.rings.real_mpfr import RealField_class from sage.geometry.triangulation.point_configuration import PointConfiguration from sage.modules.free_module_element import vector From b75c975b7bf9c2e4ce75119cf06bb6668ef6618a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 10:59:54 +0200 Subject: [PATCH 203/355] trac #32535: avoid some rounding --- src/sage/graphs/digraph.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 04bf4293815..bcf919c4a7d 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1685,14 +1685,13 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, # Variables are binary, and their coefficient in the objective is # the number of occurrences of the corresponding edge, so 1 if the # graph is simple - p.set_objective( p.sum(b[u,v] for u,v in self.edge_iterator(labels=False))) - - p.solve(log=verbose) + p.set_objective( p.sum(b[e] for e in self.edge_iterator(labels=False))) # For as long as we do not break because the digraph is acyclic.... while True: # Building the graph without the edges removed by the MILP + p.solve(log=verbose) val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) h = DiGraph([e for e in self.edge_iterator(labels=False) if not val[e]], format='list_of_edges') @@ -1702,7 +1701,11 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, # If so, we are done ! if isok: - break + if value_only: + return sum(1 for e in self.edge_iterator(labels=False) if val[e]) + else: + # listing the edges contained in the MFAS + return [e for e in self.edge_iterator(labels=False) if val[e]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -1712,7 +1715,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, print("Adding a constraint on circuit : {}".format(certificate)) edges = zip(certificate, certificate[1:] + [certificate[0]]) - p.add_constraint(p.sum(b[u, v] for u, v in edges), min=1) + p.add_constraint(p.sum(b[e] for e in edges), min=1) # Is there another edge disjoint circuit ? # for python3, we need to recreate the zip iterator @@ -1720,16 +1723,6 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, h.delete_edges(edges) isok, certificate = h.is_directed_acyclic(certificate=True) - obj = p.solve(log=verbose) - - if value_only: - return Integer(round(obj)) - - else: - # listing the edges contained in the MFAS - val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [e for e in self.edge_iterator(labels=False) if val[e]] - ###################################### # Ordering-based MILP Implementation # ###################################### @@ -1747,16 +1740,16 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, for v in self: p.add_constraint(d[v] <= n) - p.set_objective(p.sum(b[u,v] for u,v in self.edge_iterator(labels=None))) + p.set_objective(p.sum(b[e] for e in self.edge_iterator(labels=False))) - if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) - else: - p.solve(log=verbose) + p.solve(log=verbose) - b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [e for e in self.edge_iterator(labels=None) if b_sol[e]] + if value_only: + return sum(1 for e in self.edge_iterator(labels=False) if b_sol[e]) + else: + return [e for e in self.edge_iterator(labels=False) if b_sol[e]] ### Construction From 24388517cdebde5fc13b3ddae735d476847a2016 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 11:23:53 +0200 Subject: [PATCH 204/355] trac #32536: avoid some rounding --- src/sage/graphs/graph_coloring.pyx | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 24ee5fa5b92..98529763aef 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -1004,18 +1004,18 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, p.set_objective(p.sum(is_used[i] for i in range(k))) try: - obj = p.solve(log=verbose, objective_only=value_only) - from sage.rings.integer import Integer - obj = Integer(obj) - + p.solve(log=verbose) except MIPSolverException: raise ValueError("this graph cannot be colored with k colors") + from sage.rings.integer import Integer + is_used = p.get_values(is_used, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for i in range(k) if is_used[i])) + if value_only: return obj # Building the dictionary associating its color to every vertex - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) cdef dict coloring = {} @@ -1197,19 +1197,18 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, try: - obj = p.solve(log=verbose, objective_only=value_only) - from sage.rings.integer import Integer - obj = Integer(obj) - + p.solve(log=verbose) except MIPSolverException: raise ValueError("this graph cannot be colored with k colors") + from sage.rings.integer import Integer + is_used = p.get_values(is_used, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for i in range(k) if is_used[i])) + if value_only: return obj - # Building the dictionary associating its color to every vertex - c = p.get_values(color, convert=bool, tolerance=integrality_tolerance) cdef dict coloring = {} From f6fd741ed556989a15ebfa2b3470a1079e8c0c04 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 11:46:10 +0200 Subject: [PATCH 205/355] trac #32537: safer way to get the solution of MILP --- src/sage/graphs/graph.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 4a3e1b3c2dd..825df816cfa 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4200,14 +4200,15 @@ def weight(x): 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(objective_only=value_only, log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: if use_edge_labels: - return p.solve(objective_only=True, log=verbose) + return sum(w for fe, w in W.items() if b[fe]) else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + return Integer(sum(1 for fe in L if b[fe])) else: - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) return [(u, v, L[frozenset((u, v))]) for u, v in L if b[frozenset((u, v))]] else: @@ -4318,7 +4319,7 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, p.set_objective(p.sum(m[vh] for vh in H)) try: - p.solve(log = verbose) + p.solve(log=verbose) except MIPSolverException: return False @@ -6787,11 +6788,11 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, for u,v in g.edge_iterator(labels=None): p.add_constraint(b[u] + b[v], min=1) + p.solve(objective_only=value_only, log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: - size_cover_g = p.solve(objective_only=True, log=verbose) + size_cover_g = sum(1 for v in g if b[v]) else: - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) cover_g = set(v for v in g if b[v]) else: raise ValueError('the algorithm must be "Cliquer", "MILP" or "mcqd"') From 2b7730a902f272cf803569be07cc41ef9dcc4db0 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 13:01:48 +0200 Subject: [PATCH 206/355] trac #32538: safer way to get the solution of MILP in generic_graph.py - part 1 --- src/sage/graphs/generic_graph.py | 220 ++++++++++++++++--------------- 1 file changed, 111 insertions(+), 109 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee9191b90a6..5e66a4c8574 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6520,16 +6520,18 @@ 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') - (1.0, [(2, 1)]) + (1, [(2, 1)]) """ self._scream_if_not_simple(allow_loops=True) if vertices: value_only = False if use_edge_labels: - weight = lambda x: x if (x != {} and x is not None) else 1 + def weight(x): + return x if (x != {} and x is not None) else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 if algorithm in ["FF", "igraph", None]: if value_only: @@ -6567,6 +6569,15 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, b = p.new_variable(binary=True) v = p.new_variable(binary=True) + # Helper function to ensure that we use arcs when g is directed and + # frozensets otherwise + if g.is_directed(): + def good_edge(e): + return e + else: + def good_edge(e): + return frozenset(e) + # Some vertices belong to part 1, others to part 0 p.add_constraint(v[s], min=0, max=0) p.add_constraint(v[t], min=1, max=1) @@ -6574,51 +6585,46 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, if g.is_directed(): # we minimize the number of edges - p.set_objective(p.sum(weight(w) * b[x,y] for x,y,w in g.edge_iterator())) + 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): - p.add_constraint(v[x] + b[x,y] - v[y], min=0) + p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) else: # we minimize the number of edges - p.set_objective(p.sum(weight(w) * b[frozenset((x,y))] for x,y,w in g.edge_iterator())) + 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): - p.add_constraint(v[x] + b[frozenset((x,y))] - v[y], min=0) - p.add_constraint(v[y] + b[frozenset((x,y))] - v[x], min=0) + 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) - if value_only: - if use_edge_labels: - return p.solve(objective_only=True, log=verbose) - else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + if use_edge_labels: + obj = sum(weight(w) for x, y, w in g.edge_iterator() if b[good_edge((x,y))]) else: - obj = p.solve(log=verbose) + obj = Integer(sum(1 for e in g.edge_iterator(labels=False) if b[good_edge(e)])) - if use_edge_labels is False: - obj = Integer(round(obj)) + if value_only: + return obj - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - answer = [obj] - if g.is_directed(): - answer.append([(x,y) for (x,y) in g.edge_iterator(labels=None) if b[x,y]]) - else: - answer.append([(x,y) for (x,y) in g.edge_iterator(labels=None) if b[frozenset((x,y))]]) + answer = [obj] + answer.append([e for e in g.edge_iterator(labels=False) if b[good_edge(e)]]) - if vertices: - v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) - l0 = [] - l1 = [] - for x in g: - if v.get(x, False): - l1.append(x) - else: - l0.append(x) - answer.append([l0, l1]) - return tuple(answer) + if vertices: + v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) + l0 = [] + l1 = [] + for x in g: + if v.get(x, False): + l1.append(x) + else: + l0.append(x) + answer.append([l0, l1]) + return tuple(answer) def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -6707,42 +6713,42 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose p.add_constraint(b[s] == 0) p.add_constraint(b[t] == 0) - if g.is_directed(): - - p.set_objective(p.sum(b[x] for x in g)) + p.set_objective(p.sum(b[x] for x in g)) + if g.is_directed(): # adjacent vertices belong to the same part except if one of them # belongs to the cut for x,y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] - v[y], min=0) else: - p.set_objective(p.sum(b[x] for x in g)) # adjacent vertices belong to the same part except if one of them # belongs to the cut for x,y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] >= v[y]) p.add_constraint(v[y] + b[x] >= v[x]) + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for x in g if b[x])) + if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) - else: - obj = Integer(round(p.solve(log=verbose))) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - answer = [obj, [x for x in g if b[x]]] - if vertices: - v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) - l0 = [] - l1 = [] - for x in g: - # if the vertex is not in the cut - if not b.get(x, False): - if v.get(x, False): - l1.append(x) - else: - l0.append(x) - answer.append([l0, l1]) - return tuple(answer) + return obj + + answer = [obj, [x for x in g if b[x]]] + if vertices: + v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) + l0 = [] + l1 = [] + for x in g: + # if the vertex is not in the cut + if not b.get(x, False): + if v.get(x, False): + l1.append(x) + else: + l0.append(x) + answer.append([l0, l1]) + return tuple(answer) def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, @@ -6835,17 +6841,26 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # cut[e] represents whether e is in the cut cut = p.new_variable(binary=True) + # Helper function to correctly index variables cut + if self.is_directed(): + def good_edge(e): + return e + else: + def good_edge(e): + return frozenset(e) + # Weight function if use_edge_labels: - w = lambda l: l if l is not None else 1 + def weight(l): + return l if l is not None else 1 else: - w = lambda l: 1 - - if self.is_directed(): + def weight(l): + return 1 - p.set_objective(p.sum(w(l) * cut[u,v] for u,v,l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * cut[good_edge((u, v))] for u, v, l in self.edge_iterator())) - for s,t in chain(combinations(vertices, 2), [(x_y[1], x_y[0]) for x_y in combinations(vertices, 2)]): + if self.is_directed(): + for s,t in chain(combinations(vertices, 2), [(y, x) for x, y in combinations(vertices, 2)]): # For each commodity, the source is at height 0 # and the destination is at height 1 p.add_constraint(height[(s,t),s], min=0, max=0) @@ -6854,12 +6869,9 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[u,v], max=0) + p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u, v))], max=0) else: - - p.set_objective(p.sum(w(l) * cut[frozenset((u,v))] for u,v,l in self.edge_iterator())) - for s,t in combinations(vertices, 2): # For each commodity, the source is at height 0 # and the destination is at height 1 @@ -6869,23 +6881,19 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[frozenset((u,v))], max=0) - p.add_constraint(height[(s,t),v] - height[(s,t),u] - cut[frozenset((u,v))], max=0) - - if value_only: - if use_edge_labels: - return p.solve(objective_only=True, log=verbose) - else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u,v))], max=0) + p.add_constraint(height[(s,t),v] - height[(s,t),u] - cut[good_edge((u,v))], max=0) p.solve(log=verbose) - cut = p.get_values(cut, convert=bool, tolerance=integrality_tolerance) - if self.is_directed(): - return [x for x in self.edge_iterator() if cut[x[0], x[1]]] + if value_only: + if use_edge_labels: + return sum(weight(l) for u, v, l in self.edge_iterator() if cut[good_edge((u, v))]) + else: + return Integer(sum(1 for e in self.edge_iterator(labels=False) if cut[good_edge(e)])) - return [x for x in self.edge_iterator() if cut[frozenset((x[0], x[1]))]] + return [e for e in self.edge_iterator() if cut[good_edge((e[0], e[1]))]] def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, @@ -6962,9 +6970,18 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, if use_edge_labels: from sage.rings.real_mpfr import RR - weight = lambda x: x if x in RR else 1 + def weight(x): + return x if x in RR else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 + + if g.is_directed(): + def good_edge(e): + return e + else: + def good_edge(e): + return frozenset(e) from sage.numerical.mip import MixedIntegerLinearProgram @@ -6982,8 +6999,7 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, p.add_constraint(p.sum(in_set[0,v] for v in g), min=1) if g.is_directed(): - # There is no edge from set 0 to set 1 which - # is not in the cut + # There is no edge from set 0 to set 1 which is not in the cut. # Besides, an edge can only be in the cut if its vertices # belong to different sets for u,v in g.edge_iterator(labels=None): @@ -6991,48 +7007,34 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[u,v], max=2) p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[u,v], max=2) - p.set_objective(p.sum(weight(l) * in_cut[u,v] for u,v,l in g.edge_iterator())) - else: - # Two adjacent vertices are in different sets if and only if # the edge between them is in the cut for u,v in g.edge_iterator(labels=None): - fuv = frozenset((u,v)) + fuv = good_edge((u, v)) p.add_constraint(in_set[0,u] + in_set[1,v] - in_cut[fuv], max=1) p.add_constraint(in_set[1,u] + in_set[0,v] - in_cut[fuv], max=1) p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[fuv], max=2) p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[fuv], max=2) - p.set_objective(p.sum(weight(l) * in_cut[frozenset((u,v))] for u,v,l in g.edge_iterator())) - - if value_only: - obj = p.solve(objective_only=True, log=verbose) - return obj if use_edge_labels else Integer(round(obj)) - else: - obj = p.solve(log=verbose) - - if use_edge_labels: - obj = Integer(round(obj)) - - val = [obj] + p.set_objective(p.sum(weight(l) * in_cut[good_edge((u, v))] for u, v, l in g.edge_iterator())) - in_cut = p.get_values(in_cut, convert=bool, tolerance=integrality_tolerance) - in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) + p.solve(log=verbose) - edges = [] - if g.is_directed(): - for u,v,l in g.edge_iterator(): - if in_cut[u,v]: - edges.append((u,v,l)) - else: - for u,v,l in g.edge_iterator(): - if in_cut[frozenset((u,v))]: - edges.append((u,v,l)) + in_cut = p.get_values(in_cut, convert=bool, tolerance=integrality_tolerance) + if use_edge_labels: + obj = sum(weight(l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]) + else: + obj = Integer(sum(1 for e in g.edge_iterator(labels=False) if in_cut[good_edge(e)])) - val.append(edges) + if value_only: + return obj + else: + edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]] + val = [obj, edges] if vertices: + in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) a = [] b = [] for v in g: From efeaeadab9c68384d8799bfc327bcb26c318e9ba Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 13:43:21 +0200 Subject: [PATCH 207/355] trac #32539: safer way to get the solution of MILP in generic_graph.py - part 2 --- src/sage/graphs/generic_graph.py | 46 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee9191b90a6..bbabf2aa4b3 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8503,11 +8503,11 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, # Variables are binary, and their coefficient in the objective is 1 p.set_objective(p.sum(b[v] for v in self)) - p.solve(log=verbose) - # For as long as we do not break because the digraph is acyclic.... while True: + p.solve(log=verbose) + # Building the graph without the vertices removed by the LP b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) h = self.subgraph([v for v in self if not b_val[v]]) @@ -8520,7 +8520,10 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, # If so, we are done ! if isok: - break + if value_only: + return Integer(self.order() - h.order()) + else: + return [v for v in self if b_val[v]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -8537,17 +8540,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, else: isok, certificate = h.is_forest(certificate=True) - obj = p.solve(log=verbose) - - if value_only: - return obj - - else: - - # Listing the vertices contained in the MFVS - b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [v for v in self if b_val[v]] - else: ###################################### @@ -8569,12 +8561,11 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, p.set_objective(p.sum(b[v] for v in self)) + p.solve(log=verbose) + b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) + return Integer(sum(1 for v in self if b_sol[v])) else: - p.solve(log=verbose) - b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [v for v in self if b_sol[v]] def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, @@ -8855,18 +8846,23 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, if integer: p.set_integer(flow) + p.solve(log=verbose) - if value_only: - return p.solve(objective_only=True, log=verbose) + # If integer is True, flow variables will be converted to integers. + # Otherwise, the base ring of the MILP solver is used + flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) - obj = p.solve(log=verbose) + if g.is_directed(): + obj = sum(flow[x, v] for u, v in g.outgoing_edge_iterator([x], labels=False)) + obj -= sum(flow[u, x] for u, v in g.incoming_edge_iterator([x], labels=False)) + else: + obj = sum(flow[x, v] - flow[v, x] for v in g[x]) - if integer or use_edge_labels is False: + if not integer and use_edge_labels is False: obj = Integer(round(obj)) - # If integer is True, flow variables will be converted to integers. - # Otherwise, the base ring of the MILP solver is used - flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) + if value_only: + return obj # Builds a clean flow Draph flow_graph = g._build_flow_graph(flow, integer=integer) From 04537949acde2b84be64d49374afc383ad37eff9 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 14:02:34 +0200 Subject: [PATCH 208/355] trac #32539: remove round --- src/sage/graphs/generic_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index bbabf2aa4b3..c7dca5f9ad2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8859,7 +8859,7 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, obj = sum(flow[x, v] - flow[v, x] for v in g[x]) if not integer and use_edge_labels is False: - obj = Integer(round(obj)) + obj = Integer(obj) if value_only: return obj From 860fc1678a62b96deb89881445d0a0ca81c77ca9 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 17:37:41 +0200 Subject: [PATCH 209/355] trac 32537: fix doctest in matching for bipartite graphs --- src/sage/graphs/bipartite_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 415f1fa34d9..7c34008eb43 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -1555,7 +1555,7 @@ class :class:`MixedIntegerLinearProgram sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP') - 4.0 + 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Eppstein') Traceback (most recent call last): ... From 5d829d9630088bfeddf66e83ea2bfb1a7cecae2c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 19 Sep 2021 17:42:38 +0200 Subject: [PATCH 210/355] trac #32538: fix pyflakes --- src/sage/graphs/generic_graph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 5e66a4c8574..1b87de7554c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -9504,7 +9504,6 @@ def _build_flow_graph(self, flow, integer): sage: flow_graph.edges() [('000', '001', 1)] """ - from sage.misc.functional import round from sage.graphs.digraph import DiGraph g = DiGraph() From 71e63dfeb71fea4fa6dad05e98a31aec16eba058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 19 Sep 2021 17:45:51 +0200 Subject: [PATCH 211/355] fix doctests --- src/sage/schemes/product_projective/point.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index fecf560ba3c..c773e5f976e 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -442,14 +442,14 @@ def global_height(self, prec=None): sage: PP = ProductProjectiveSpaces(QQ, [2,2], 'x') sage: Q = PP([1, 7, 5, 18, 2, 3]) sage: Q.global_height() - 1.94591014905531 + 2.89037175789616 :: sage: PP = ProductProjectiveSpaces(ZZ, [1,1], 'x') sage: A = PP([-30, 2, 1, 6]) sage: A.global_height() - 3.40119738166216 + 2.70805020110221 :: @@ -458,7 +458,7 @@ def global_height(self, prec=None): sage: PP = ProductProjectiveSpaces(k, [1, 2], 'y') sage: Q = PP([3, 5*w+1, 1, 7*w, 10]) sage: Q.global_height() - 2.30258509299405 + 2.75062910527236 :: From c87148b86fe0de11be68a0f01917e45b705e4c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 20 Sep 2021 10:33:43 +0200 Subject: [PATCH 212/355] fixing logfile and warn-long handling --- src/bin/sage-runtests | 6 ++++-- src/sage/doctest/control.py | 15 ++++++++++----- src/sage/doctest/forker.py | 2 +- src/sage/doctest/reporting.py | 4 ++-- src/sage/doctest/test.py | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 674837e5c9b..4fc2062b152 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -121,13 +121,15 @@ if __name__ == "__main__": new_arguments = [] need_filenames = True in_filenames = False + afterlog = False for arg in sys.argv[1:]: - if arg in ['-n', '--new', '-a', '--all']: + if arg in ('-n', '--new', '-a', '--all'): need_filenames = False - elif need_filenames and not in_filenames and os.path.exists(arg): + elif need_filenames and not (afterlog or in_filenames) and os.path.exists(arg): in_filenames = True new_arguments.append('--') new_arguments.append(arg) + afterlog = bool(arg == '--logfile') args = parser.parse_args(new_arguments) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 5bee00bd992..06446de4e6a 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -382,11 +382,16 @@ def __init__(self, options, args): self.files = args if options.logfile: - try: + if not isinstance(options.logfile, str): + # file from sage-runtests self.logfile = options.logfile - except IOError: - print("Unable to open logfile {!r}\nProceeding without logging.".format(options.logfile)) - self.logfile = None + else: + # string from DocTestDefaults + try: + self.logfile = open(options.logfile, 'a') + except IOError: + print("Unable to open logfile {!r}\nProceeding without logging.".format(options.logfile)) + self.logfile = None else: self.logfile = None @@ -451,7 +456,7 @@ def _init_warn_long(self): 5.00000000000000 """ # default is -1.0 - if self.options.warn_long > 0: # Specified on the command line + if self.options.warn_long >= 0: # Specified on the command line return try: self.options.warn_long = 60.0 * self.second_on_modern_computer() diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 4772c4ed017..264d27adc09 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -776,7 +776,7 @@ def compiler(example): # Report the outcome. if outcome is SUCCESS: - if self.options.warn_long and example.walltime > self.options.warn_long: + if self.options.warn_long > 0 and example.walltime > self.options.warn_long: self.report_overtime(out, test, example, got) elif not quiet: self.report_success(out, test, example, got) diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index 3752213e50a..b15901cf54d 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -182,10 +182,10 @@ def report_head(self, source): cmd += " --long" warnlong = self.controller.options.warn_long - if warnlong is not None: + if warnlong >= 0: cmd += " --warn-long" if warnlong != 1.0: - cmd += " %.1f"%(warnlong) + cmd += " %.1f" % (warnlong) seed = self.controller.options.random_seed cmd += " --random-seed={}".format(seed) cmd += " " + source.printpath diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index 997cd5ce7ee..1d9c0ef182d 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -327,7 +327,7 @@ Test logfiles in serial and parallel mode (see :trac:`19271`):: sage: t = tmp_filename() - sage: subprocess.call(["sage", "-t", "--serial", "--warn-long", "0", "--random-seed=0", "simple_failure.rst", "--logfile", t], stdout=open(os.devnull, "w"), **kwds) # long time + sage: subprocess.call(["sage", "-t", "--serial", "--warn-long", "0", "--random-seed=0", "--logfile", t, "simple_failure.rst"], stdout=open(os.devnull, "w"), **kwds) # long time 1 sage: print(open(t).read()) # long time Running doctests... @@ -350,7 +350,7 @@ ---------------------------------------------------------------------- ... - sage: subprocess.call(["sage", "-t", "--warn-long", "0", "--random-seed=0", "simple_failure.rst", "--logfile", t], stdout=open(os.devnull, "w"), **kwds) # long time + sage: subprocess.call(["sage", "-t", "--warn-long", "0", "--random-seed=0", "--logfile", t, "simple_failure.rst"], stdout=open(os.devnull, "w"), **kwds) # long time 1 sage: print(open(t).read()) # long time Running doctests... From 6ec80c63a506f1a6aa67e20f3a9c8dbe3e76f7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 20 Sep 2021 22:46:51 -0300 Subject: [PATCH 213/355] Adjust package names for void linux (void.txt) --- build/pkgs/_bootstrap/distros/void.txt | 2 +- build/pkgs/_prereq/distros/void.txt | 1 + build/pkgs/arb/distros/void.txt | 1 + build/pkgs/cbc/distros/void.txt | 1 + build/pkgs/ccache/distros/void.txt | 1 + build/pkgs/ecl/distros/void.txt | 1 + build/pkgs/eclib/distros/void.txt | 1 + build/pkgs/flint/distros/void.txt | 2 +- build/pkgs/freetype/distros/void.txt | 2 -- build/pkgs/gc/distros/void.txt | 1 + build/pkgs/gcc/distros/void.txt | 1 + build/pkgs/gf2x/distros/void.txt | 1 + build/pkgs/giac/distros/void.txt | 1 - build/pkgs/git/distros/void.txt | 1 + build/pkgs/gp2c/distros/void.txt | 1 + build/pkgs/graphviz/distros/void.txt | 2 +- build/pkgs/iml/distros/void.txt | 1 - build/pkgs/isl/distros/void.txt | 2 +- build/pkgs/jmol/distros/void.txt | 1 + build/pkgs/libatomic_ops/distros/void.txt | 1 + build/pkgs/libgd/distros/void.txt | 1 + build/pkgs/mathjax/distros/void.txt | 1 + build/pkgs/maxima/distros/void.txt | 1 + build/pkgs/mpc/distros/void.txt | 1 - build/pkgs/mpfr/distros/void.txt | 2 +- build/pkgs/mpir/distros/void.txt | 1 + build/pkgs/ntl/distros/void.txt | 1 + build/pkgs/openssl/distros/void.txt | 2 +- build/pkgs/patch/distros/void.txt | 1 + build/pkgs/pcre/distros/void.txt | 1 - build/pkgs/pkgconf/distros/void.txt | 1 + build/pkgs/python3/distros/void.txt | 1 - build/pkgs/rw/distros/void.txt | 1 - build/pkgs/zlib/distros/void.txt | 1 + 34 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 build/pkgs/arb/distros/void.txt create mode 100644 build/pkgs/cbc/distros/void.txt create mode 100644 build/pkgs/ccache/distros/void.txt create mode 100644 build/pkgs/ecl/distros/void.txt create mode 100644 build/pkgs/eclib/distros/void.txt create mode 100644 build/pkgs/gc/distros/void.txt create mode 100644 build/pkgs/gcc/distros/void.txt create mode 100644 build/pkgs/gf2x/distros/void.txt create mode 100644 build/pkgs/git/distros/void.txt create mode 100644 build/pkgs/gp2c/distros/void.txt delete mode 100644 build/pkgs/iml/distros/void.txt create mode 100644 build/pkgs/jmol/distros/void.txt create mode 100644 build/pkgs/libatomic_ops/distros/void.txt create mode 100644 build/pkgs/libgd/distros/void.txt create mode 100644 build/pkgs/mathjax/distros/void.txt create mode 100644 build/pkgs/maxima/distros/void.txt create mode 100644 build/pkgs/mpir/distros/void.txt create mode 100644 build/pkgs/ntl/distros/void.txt create mode 100644 build/pkgs/patch/distros/void.txt create mode 100644 build/pkgs/pkgconf/distros/void.txt delete mode 100644 build/pkgs/rw/distros/void.txt create mode 100644 build/pkgs/zlib/distros/void.txt diff --git a/build/pkgs/_bootstrap/distros/void.txt b/build/pkgs/_bootstrap/distros/void.txt index 3b19fa50690..eefc9315cb5 100644 --- a/build/pkgs/_bootstrap/distros/void.txt +++ b/build/pkgs/_bootstrap/distros/void.txt @@ -1,4 +1,4 @@ # Packages needed for ./bootstrap -gettext autoconf automake libtool pkg-config +gettext autoconf automake libtool gettext-devel xtools mk-configure diff --git a/build/pkgs/_prereq/distros/void.txt b/build/pkgs/_prereq/distros/void.txt index 5f6fed81c71..a2e7644840f 100644 --- a/build/pkgs/_prereq/distros/void.txt +++ b/build/pkgs/_prereq/distros/void.txt @@ -2,6 +2,7 @@ binutils make m4 perl +pkg-config python3 tar bc diff --git a/build/pkgs/arb/distros/void.txt b/build/pkgs/arb/distros/void.txt new file mode 100644 index 00000000000..3319855150c --- /dev/null +++ b/build/pkgs/arb/distros/void.txt @@ -0,0 +1 @@ +arb-devel diff --git a/build/pkgs/cbc/distros/void.txt b/build/pkgs/cbc/distros/void.txt new file mode 100644 index 00000000000..1fbb928840a --- /dev/null +++ b/build/pkgs/cbc/distros/void.txt @@ -0,0 +1 @@ +CoinMP-devel diff --git a/build/pkgs/ccache/distros/void.txt b/build/pkgs/ccache/distros/void.txt new file mode 100644 index 00000000000..812b9efc0c5 --- /dev/null +++ b/build/pkgs/ccache/distros/void.txt @@ -0,0 +1 @@ +ccache diff --git a/build/pkgs/ecl/distros/void.txt b/build/pkgs/ecl/distros/void.txt new file mode 100644 index 00000000000..100aa2efb32 --- /dev/null +++ b/build/pkgs/ecl/distros/void.txt @@ -0,0 +1 @@ +ecl diff --git a/build/pkgs/eclib/distros/void.txt b/build/pkgs/eclib/distros/void.txt new file mode 100644 index 00000000000..0f514d35416 --- /dev/null +++ b/build/pkgs/eclib/distros/void.txt @@ -0,0 +1 @@ +eclib-devel diff --git a/build/pkgs/flint/distros/void.txt b/build/pkgs/flint/distros/void.txt index 61c2ffe155a..43e808a1904 100644 --- a/build/pkgs/flint/distros/void.txt +++ b/build/pkgs/flint/distros/void.txt @@ -1 +1 @@ -flint +flintlib-devel diff --git a/build/pkgs/freetype/distros/void.txt b/build/pkgs/freetype/distros/void.txt index 377935546a3..9d250f11947 100644 --- a/build/pkgs/freetype/distros/void.txt +++ b/build/pkgs/freetype/distros/void.txt @@ -1,3 +1 @@ freetype-devel -harfbuzz -glib diff --git a/build/pkgs/gc/distros/void.txt b/build/pkgs/gc/distros/void.txt new file mode 100644 index 00000000000..7a1f48d3ffd --- /dev/null +++ b/build/pkgs/gc/distros/void.txt @@ -0,0 +1 @@ +gc-devel diff --git a/build/pkgs/gcc/distros/void.txt b/build/pkgs/gcc/distros/void.txt new file mode 100644 index 00000000000..90584dda5b9 --- /dev/null +++ b/build/pkgs/gcc/distros/void.txt @@ -0,0 +1 @@ +gcc diff --git a/build/pkgs/gf2x/distros/void.txt b/build/pkgs/gf2x/distros/void.txt new file mode 100644 index 00000000000..971035e4030 --- /dev/null +++ b/build/pkgs/gf2x/distros/void.txt @@ -0,0 +1 @@ +gf2x-devel diff --git a/build/pkgs/giac/distros/void.txt b/build/pkgs/giac/distros/void.txt index daf8fd8679a..e603965872c 100644 --- a/build/pkgs/giac/distros/void.txt +++ b/build/pkgs/giac/distros/void.txt @@ -1,2 +1 @@ giac-devel -libgiac diff --git a/build/pkgs/git/distros/void.txt b/build/pkgs/git/distros/void.txt new file mode 100644 index 00000000000..5664e303b5d --- /dev/null +++ b/build/pkgs/git/distros/void.txt @@ -0,0 +1 @@ +git diff --git a/build/pkgs/gp2c/distros/void.txt b/build/pkgs/gp2c/distros/void.txt new file mode 100644 index 00000000000..f4ab6d425f1 --- /dev/null +++ b/build/pkgs/gp2c/distros/void.txt @@ -0,0 +1 @@ +gp2c diff --git a/build/pkgs/graphviz/distros/void.txt b/build/pkgs/graphviz/distros/void.txt index f137846bc26..4d95609306f 100644 --- a/build/pkgs/graphviz/distros/void.txt +++ b/build/pkgs/graphviz/distros/void.txt @@ -1 +1 @@ -graphviz-devel +graphviz diff --git a/build/pkgs/iml/distros/void.txt b/build/pkgs/iml/distros/void.txt deleted file mode 100644 index e1a62af8917..00000000000 --- a/build/pkgs/iml/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -imlib2-devel diff --git a/build/pkgs/isl/distros/void.txt b/build/pkgs/isl/distros/void.txt index 97c6659d351..d54c646d7a7 100644 --- a/build/pkgs/isl/distros/void.txt +++ b/build/pkgs/isl/distros/void.txt @@ -1 +1 @@ -isl15-devel +isl-devel diff --git a/build/pkgs/jmol/distros/void.txt b/build/pkgs/jmol/distros/void.txt new file mode 100644 index 00000000000..f07a1f4e035 --- /dev/null +++ b/build/pkgs/jmol/distros/void.txt @@ -0,0 +1 @@ +jmol diff --git a/build/pkgs/libatomic_ops/distros/void.txt b/build/pkgs/libatomic_ops/distros/void.txt new file mode 100644 index 00000000000..56dbd90c363 --- /dev/null +++ b/build/pkgs/libatomic_ops/distros/void.txt @@ -0,0 +1 @@ +libatomic_ops-devel diff --git a/build/pkgs/libgd/distros/void.txt b/build/pkgs/libgd/distros/void.txt new file mode 100644 index 00000000000..5d1b511668c --- /dev/null +++ b/build/pkgs/libgd/distros/void.txt @@ -0,0 +1 @@ +gd-devel diff --git a/build/pkgs/mathjax/distros/void.txt b/build/pkgs/mathjax/distros/void.txt new file mode 100644 index 00000000000..37aaaac759c --- /dev/null +++ b/build/pkgs/mathjax/distros/void.txt @@ -0,0 +1 @@ +mathjax diff --git a/build/pkgs/maxima/distros/void.txt b/build/pkgs/maxima/distros/void.txt new file mode 100644 index 00000000000..f5fe3fdc6cb --- /dev/null +++ b/build/pkgs/maxima/distros/void.txt @@ -0,0 +1 @@ +maxima diff --git a/build/pkgs/mpc/distros/void.txt b/build/pkgs/mpc/distros/void.txt index ec2f198bdd3..279a55fdb8b 100644 --- a/build/pkgs/mpc/distros/void.txt +++ b/build/pkgs/mpc/distros/void.txt @@ -1,2 +1 @@ -mpc libmpc-devel diff --git a/build/pkgs/mpfr/distros/void.txt b/build/pkgs/mpfr/distros/void.txt index 5bcf2cdfb19..2654a0c9ea0 100644 --- a/build/pkgs/mpfr/distros/void.txt +++ b/build/pkgs/mpfr/distros/void.txt @@ -1 +1 @@ -mpfr +mpfr-devel diff --git a/build/pkgs/mpir/distros/void.txt b/build/pkgs/mpir/distros/void.txt new file mode 100644 index 00000000000..c490ad530ef --- /dev/null +++ b/build/pkgs/mpir/distros/void.txt @@ -0,0 +1 @@ +mpir-devel diff --git a/build/pkgs/ntl/distros/void.txt b/build/pkgs/ntl/distros/void.txt new file mode 100644 index 00000000000..978728a7592 --- /dev/null +++ b/build/pkgs/ntl/distros/void.txt @@ -0,0 +1 @@ +ntl-devel diff --git a/build/pkgs/openssl/distros/void.txt b/build/pkgs/openssl/distros/void.txt index 1dbc44b98df..2192a62851a 100644 --- a/build/pkgs/openssl/distros/void.txt +++ b/build/pkgs/openssl/distros/void.txt @@ -1 +1 @@ -libressl-openssl +openssl-devel diff --git a/build/pkgs/patch/distros/void.txt b/build/pkgs/patch/distros/void.txt new file mode 100644 index 00000000000..9eb7b90ed50 --- /dev/null +++ b/build/pkgs/patch/distros/void.txt @@ -0,0 +1 @@ +patch diff --git a/build/pkgs/pcre/distros/void.txt b/build/pkgs/pcre/distros/void.txt index cfc6bffc3eb..cac6a31d037 100644 --- a/build/pkgs/pcre/distros/void.txt +++ b/build/pkgs/pcre/distros/void.txt @@ -1,2 +1 @@ pcre-devel -pcre2-devel diff --git a/build/pkgs/pkgconf/distros/void.txt b/build/pkgs/pkgconf/distros/void.txt new file mode 100644 index 00000000000..05a1a221b7d --- /dev/null +++ b/build/pkgs/pkgconf/distros/void.txt @@ -0,0 +1 @@ +pkgconf diff --git a/build/pkgs/python3/distros/void.txt b/build/pkgs/python3/distros/void.txt index 0a1b2134e3e..07358a92e89 100644 --- a/build/pkgs/python3/distros/void.txt +++ b/build/pkgs/python3/distros/void.txt @@ -1,2 +1 @@ -python3 python3-devel diff --git a/build/pkgs/rw/distros/void.txt b/build/pkgs/rw/distros/void.txt deleted file mode 100644 index 16feab0960b..00000000000 --- a/build/pkgs/rw/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -rw diff --git a/build/pkgs/zlib/distros/void.txt b/build/pkgs/zlib/distros/void.txt new file mode 100644 index 00000000000..f47c16b504b --- /dev/null +++ b/build/pkgs/zlib/distros/void.txt @@ -0,0 +1 @@ +zlib-devel From 30d3804fefa7deb5168a573f092feb6b5557a633 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 21 Sep 2021 16:12:01 +1000 Subject: [PATCH 214/355] Moving shift up and bug fixing. --- src/sage/rings/lazy_series.py | 154 +++++++++++++++-------------- src/sage/rings/lazy_series_ring.py | 23 ++++- 2 files changed, 101 insertions(+), 76 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index d739c6025cf..0b82c8670d8 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -348,6 +348,88 @@ def truncate(self, d): return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, order=v)) + def shift(self, n): + r""" + Return ``self`` with the indices shifted by ``n``. + + For example, a Laurent series is multiplied by the power `z^n`, + where `z` is the variable of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = 1 / (1 + 2*z) + sage: f + 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) + sage: f.shift(3) + z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) + sage: f << -3 # shorthand + z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) + sage: g = z^-3 + 3 + z^2 + sage: g.shift(5) + z^2 + 3*z^5 + z^7 + sage: L([2,0,3], valuation=2, degree=7, constant=1) << -2 + 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) + + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: f = D([0,1,2]); f + 1/(2^t) + 2/3^t + sage: f.shift(3) + 1/(5^t) + 2/6^t + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: zero = L.zero() + sage: zero.shift(10) is zero + True + + sage: f = 1 / (1 + 2*z + z^2) + sage: f.shift(5).shift(-5) - f + 0 + + """ + if isinstance(self._coeff_stream, Stream_zero): + return self + elif isinstance(self._coeff_stream, Stream_shift): + n += self._coeff_stream._shift + if n: + coeff_stream = Stream_shift(self._coeff_stream._series, n) + else: + coeff_stream = self._coeff_stream._series + elif isinstance(self._coeff_stream, Stream_exact): + init_coeff = self._coeff_stream._initial_coefficients + degree = self._coeff_stream._degree + n + valuation = self._coeff_stream._approximate_order + n + coeff_stream = Stream_exact(init_coeff, self._coeff_stream._is_sparse, + constant=self._coeff_stream._constant, + order=valuation, degree=degree) + else: + coeff_stream = Stream_shift(self._coeff_stream, n) + P = self.parent() + return P.element_class(P, coeff_stream) + + __lshift__ = shift + + def __rshift__(self, n): + r""" + Return ``self`` with the indices shifted right by ``n``. + + For example, a Laurent series is multiplied by the power `z^-n`, + where `z` is the variable of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = 1/(1 + 2*z); f + 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) + sage: f >> 3 + z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) + sage: f >> -3 + z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) + """ + return self.shift(-n) + def prec(self): """ Return the precision of the series, which is infinity. @@ -2282,78 +2364,6 @@ def polynomial(self, degree=None, name=None): R = PolynomialRing(S.base_ring(), name=name) return R([self[i] for i in range(m)]) - def shift(self, n): - r""" - Return ``self`` multiplied by the power `z^n`, where `z` is the - variable of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1 / (1 + 2*z) - sage: f - 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) - sage: f.shift(3) - z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) - sage: f << -3 # shorthand - z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) - sage: g = z^-3 + 3 + z^2 - sage: g.shift(5) - z^2 + 3*z^5 + z^7 - sage: L([2,0,3], valuation=2, degree=7, constant=1) << -2 - 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: zero = L.zero() - sage: zero.shift(10) is zero - True - - sage: f = 1 / (1 + 2*z + z^2) - sage: f.shift(5).shift(-5) - f - 0 - - """ - if isinstance(self._coeff_stream, Stream_zero): - return self - elif isinstance(self._coeff_stream, Stream_shift): - n += self._coeff_stream._shift - if n: - coeff_stream = Stream_shift(self._coeff_stream._series, n) - else: - coeff_stream = self._coeff_stream._series - elif isinstance(self._coeff_stream, Stream_exact): - init_coeff = self._coeff_stream._initial_coefficients - degree = self._coeff_stream._degree + n - valuation = self._coeff_stream._approximate_order + n - coeff_stream = Stream_exact(init_coeff, self._coeff_stream._is_sparse, - constant=self._coeff_stream._constant, - order=valuation, degree=degree) - else: - coeff_stream = Stream_shift(self._coeff_stream, n) - P = self.parent() - return P.element_class(P, coeff_stream) - - __lshift__ = shift - - def __rshift__(self, n): - r""" - Return ``self`` multiplied by the power `z^-n`, where `z` is the - variable of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1/(1 + 2*z); f - 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) - sage: f >> 3 - z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) - sage: f >> -3 - z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) - """ - return self.shift(-n) - def _format_series(self, formatter, format_strings=False): """ Return ``self`` formatted by ``formatter``. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 75337c3a279..7f7aaa0beaa 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -299,7 +299,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No except (TypeError, ValueError): pass - # If x has been converted to the Laurent polynomial ring + # If x has been converted to the internal polynomial ring if parent(x) is R: if not x and not constant: return self.zero() @@ -326,7 +326,9 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No # If x is known to be 0 if isinstance(x._coeff_stream, Stream_zero): if not constant: - return x + if self is parent(x): + return x + return self.element_class(self, x._coeff_stream) if degree is None: if valuation is None: raise ValueError("you must specify the degree for the polynomial 0") @@ -356,7 +358,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No ret = self.element_class(self, x._coeff_stream) if valuation is None: return ret - return x.shift(valuation - x._coeff_stream.order()) + return ret.shift(valuation - x._coeff_stream.order()) else: x = coefficients @@ -1108,6 +1110,16 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No ... ValueError: positive characteristic not allowed for Dirichlet series + sage: L. = LazyLaurentSeriesRing(QQ) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(z+z^2) + 1 + 1/(2^t) + + sage: R. = LaurentPolynomialRing(QQ) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(coefficients=z+z^2) + 2 + 6/2^t + 12/3^t + 20/4^t + 30/5^t + 42/6^t + 56/7^t + O(1/(8^t)) + .. TODO:: Add a method to make a copy of ``self._sparse``. @@ -1120,12 +1132,15 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No x = p else: x = p.shift(1) - elif valuation is None: + elif not isinstance(x, LazyModuleElement) and valuation is None: valuation = 1 if valuation is not None and (valuation not in ZZ or valuation <= 0): raise ValueError("the valuation must be a positive integer") + if coefficients is not None: + return super()._element_constructor_(x, valuation, degree, constant, coefficients) + BR = self.base_ring() if x in BR: x = BR(x) From 082859918c439e197fc8e35de996d70944f2d438 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 21 Sep 2021 08:30:40 +0200 Subject: [PATCH 215/355] mark unstable tests due to 29956 --- src/sage/schemes/toric/sheaf/klyachko.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 1ed3ac290b4..9119f240532 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -24,9 +24,9 @@ sage: V_sum = G_sum.wedge(2) * K # long time sage: V_sum.cohomology(dim=True, weight=(0,0,0,0)) # long time (0, 0, 18, 16, 1) - sage: Gtilde = G_sum.random_deformation() - sage: V = Gtilde.wedge(2) * K # long time - sage: V.cohomology(dim=True, weight=(0,0,0,0)) # long time + sage: Gtilde = G_sum.random_deformation() # not tested, known bug (see :trac:`29956`) + sage: V = Gtilde.wedge(2) * K # long time # not tested, known bug (see :trac:`29956`) + sage: V.cohomology(dim=True, weight=(0,0,0,0)) # long time # not tested, known bug (see :trac:`29956`) (0, 0, 3, 0, 0) REFERENCES: @@ -947,8 +947,8 @@ def random_deformation(self, epsilon=None): sage: V = P1.sheaves.line_bundle(H) + P1.sheaves.line_bundle(-H) sage: V.cohomology(dim=True, weight=(0,)) (1, 0) - sage: Vtilde = V.random_deformation() # not tested, known bug - sage: Vtilde.cohomology(dim=True, weight=(0,)) # not tested, known bug + sage: Vtilde = V.random_deformation() # not tested, known bug (see :trac:`29956`) + sage: Vtilde.cohomology(dim=True, weight=(0,)) # not tested, known bug (see :trac:`29956`) (1, 0) """ filt = self._filt.random_deformation(epsilon) From 3cea7f1b55315c848934c4b2dc2047d5aaf8b82a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 21 Sep 2021 17:38:09 +1000 Subject: [PATCH 216/355] Make the Dirichlet series input only convert Dirichlet series. --- src/sage/rings/lazy_series.py | 6 ++++-- src/sage/rings/lazy_series_ring.py | 30 ++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0b82c8670d8..b47f122ec4a 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -88,7 +88,7 @@ from sage.rings.infinity import infinity -from sage.structure.element import Element +from sage.structure.element import Element, parent from sage.rings.integer_ring import ZZ from sage.structure.richcmp import op_EQ, op_NE from sage.arith.power import generic_power @@ -1782,6 +1782,8 @@ def __call__(self, g): z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) sage: g^2 + 1 + g z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) + sage: f(int(2)) + 7 sage: f = z^-2 + z + 4*z^3 sage: f(f) @@ -2027,7 +2029,7 @@ def __call__(self, g): # f = self and compute f(g) from sage.structure.element import get_coercion_model cm = get_coercion_model() - P = cm.common_parent(self.base_ring(), g.parent()) + P = cm.common_parent(self.base_ring(), parent(g)) # f = 0 if isinstance(self._coeff_stream, Stream_zero): diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 7f7aaa0beaa..f68dbecac83 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -280,7 +280,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError("the valuation must be specified") return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) - if coefficients is not None and (not isinstance(x, int) or x): + if coefficients is not None and (x is not None and (not isinstance(x, int) or x)): raise ValueError("coefficients must be None if x is provided") BR = self.base_ring() @@ -1112,8 +1112,8 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L. = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(z+z^2) - 1 + 1/(2^t) + sage: D(L.one()) + 1 + 1/(2^t) + 1/(3^t) + 1/(4^t) + 1/(5^t) + 1/(6^t) + 1/(7^t) + O(1/(8^t)) sage: R. = LaurentPolynomialRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') @@ -1132,18 +1132,24 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No x = p else: x = p.shift(1) - elif not isinstance(x, LazyModuleElement) and valuation is None: - valuation = 1 + else: + if valuation is None: + valuation = 1 - if valuation is not None and (valuation not in ZZ or valuation <= 0): - raise ValueError("the valuation must be a positive integer") + if coefficients is not None: + return super()._element_constructor_(x, valuation, degree, constant, coefficients) - if coefficients is not None: - return super()._element_constructor_(x, valuation, degree, constant, coefficients) + BR = self.base_ring() + if x in BR: + x = BR(x) + if (isinstance(x, LazyModuleElement) and not isinstance(x, LazyDirichletSeries)) or callable(x): + if coefficients is not None: + raise ValueError("coefficients must be None if x is provided") + coefficients = x + x = None - BR = self.base_ring() - if x in BR: - x = BR(x) + if valuation is not None and (valuation not in ZZ or valuation <= 0): + raise ValueError("the valuation must be a positive integer") return super()._element_constructor_(x, valuation, degree, constant, coefficients) From 683bd3cf567403712d2b191045a6999c1c3029ce Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 21 Sep 2021 17:40:59 +1000 Subject: [PATCH 217/355] Fixing pyflakes warnings. --- src/sage/rings/lazy_series.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index b47f122ec4a..1baceeca501 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2588,7 +2588,6 @@ def _format_series(self, formatter, format_strings=False): m = v + P.options.display_length atomic_repr = P._coeff_ring._repr_option('element_is_atomic') - varname = P.variable_name() mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] if not isinstance(cs, Stream_exact) or cs._constant: if P._coeff_ring is P.base_ring(): @@ -2603,9 +2602,9 @@ def _format_series(self, formatter, format_strings=False): from sage.typeset.ascii_art import ascii_art from sage.misc.repr import repr_lincomb if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + poly = repr_lincomb([(1, mo) for mo in mons + bigO], strip_one=True) elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + poly = repr_lincomb([(1, mo) for mo in mons + bigO], is_latex=True, strip_one=True) elif formatter in [ascii_art, unicode_art]: if formatter == ascii_art: from sage.typeset.symbols import ascii_left_parenthesis as left_paren @@ -2621,7 +2620,7 @@ def parenthesize(m): h = a.height() return formatter(left_paren.character_art(h), a, right_paren.character_art(h)) - poly = formatter(*([parenthesize(m) for m in mons] + bigO), sep=" + ") + poly = formatter(*([parenthesize(mo) for mo in mons] + bigO), sep=" + ") return poly From ccd779a45403565f83636bbafc2b92a33f0bc509 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Tue, 21 Sep 2021 15:24:33 +0200 Subject: [PATCH 218/355] #32547 : replace nonexistent llvm-toolchain with clang as Debian alternative to llvm spkg --- build/pkgs/llvm/distros/debian.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/llvm/distros/debian.txt b/build/pkgs/llvm/distros/debian.txt index d9c90515cfc..e671fa21003 100644 --- a/build/pkgs/llvm/distros/debian.txt +++ b/build/pkgs/llvm/distros/debian.txt @@ -1 +1 @@ -llvm-toolchain +clang From 380b63a4257b8fdc9723c70a03677280d1fe0aca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 21 Sep 2021 08:43:36 -0700 Subject: [PATCH 219/355] build/pkgs/cvxopt: Update to 1.2.7 for Python 3.10 compatibility --- build/pkgs/cvxopt/checksums.ini | 6 +++--- build/pkgs/cvxopt/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cvxopt/checksums.ini b/build/pkgs/cvxopt/checksums.ini index 68a7862becf..6c90f288444 100644 --- a/build/pkgs/cvxopt/checksums.ini +++ b/build/pkgs/cvxopt/checksums.ini @@ -1,5 +1,5 @@ tarball=cvxopt-VERSION.tar.gz -sha1=d44cec6d4ea8738de94dc7dc4888ddb25914a11e -md5=b35d010b57bdd4fd78458bc764d2b013 -cksum=1219983379 +sha1=18cd006e45f8b10c8724d835a30cf1210bd685b1 +md5=af758ea38fcdd5cc1c102df4d378ffc3 +cksum=876134541 upstream_url=https://pypi.io/packages/source/c/cvxopt/cvxopt-VERSION.tar.gz diff --git a/build/pkgs/cvxopt/package-version.txt b/build/pkgs/cvxopt/package-version.txt index 3c43790f5d8..c04c650a7ad 100644 --- a/build/pkgs/cvxopt/package-version.txt +++ b/build/pkgs/cvxopt/package-version.txt @@ -1 +1 @@ -1.2.6 +1.2.7 From 8ba1d79f84e6030c01ede985e813e35a3d180feb Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 30 Jan 2021 11:10:05 -0800 Subject: [PATCH 220/355] trac 30350: remove the ATLAS package --- COPYING.txt | 1 - README.md | 10 +- build/bin/sage-package | 1 - build/pkgs/atlas/SPKG.rst | 107 --- build/pkgs/atlas/checksums.ini | 4 - build/pkgs/atlas/configuration.py | 249 ------- build/pkgs/atlas/dependencies | 5 - build/pkgs/atlas/enums.py | 202 ------ build/pkgs/atlas/package-version.txt | 1 - .../pkgs/atlas/patches/ATLAS-lib/Makefile.am | 118 --- build/pkgs/atlas/patches/ATLAS-lib/README | 3 - .../pkgs/atlas/patches/ATLAS-lib/configure.ac | 51 -- build/pkgs/atlas/patches/Makefile.patch | 10 - .../pkgs/atlas/patches/arm_hard_floats.patch | 21 - build/pkgs/atlas/patches/atlas-config | 176 ----- build/pkgs/atlas/patches/cygwin_threads.patch | 30 - build/pkgs/atlas/patches/detect.patch | 38 - .../atlas/patches/do_not_force_mutex.patch | 18 - .../patches/glibc_scanf_workaround.patch | 29 - build/pkgs/atlas/spkg-check.in | 47 -- build/pkgs/atlas/spkg-configure.m4 | 8 - build/pkgs/atlas/spkg-install.in | 1 - build/pkgs/atlas/spkg-install.py | 681 ------------------ build/pkgs/atlas/spkg-src | 68 -- build/pkgs/atlas/type | 1 - build/pkgs/cbc/spkg-configure.m4 | 2 +- build/pkgs/fflas_ffpack/SPKG.rst | 3 +- build/pkgs/fflas_ffpack/spkg-configure.m4 | 2 +- build/pkgs/gsl/spkg-configure.m4 | 2 +- build/pkgs/igraph/spkg-configure.m4 | 2 +- build/pkgs/iml/SPKG.rst | 2 +- build/pkgs/linbox/SPKG.rst | 4 +- build/pkgs/r/spkg-configure.m4 | 2 +- build/sage_bootstrap/app.py | 1 - build/sage_bootstrap/cmdline.py | 2 - src/doc/en/faq/faq-general.rst | 2 - src/doc/en/faq/faq-usage.rst | 22 +- src/doc/en/installation/source.rst | 73 +- src/doc/it/faq/faq-general.rst | 3 - src/doc/it/faq/faq-usage.rst | 41 -- src/sage/matrix/matrix_double_dense.pyx | 2 +- 41 files changed, 22 insertions(+), 2023 deletions(-) delete mode 100644 build/pkgs/atlas/SPKG.rst delete mode 100644 build/pkgs/atlas/checksums.ini delete mode 100644 build/pkgs/atlas/configuration.py delete mode 100644 build/pkgs/atlas/dependencies delete mode 100644 build/pkgs/atlas/enums.py delete mode 100644 build/pkgs/atlas/package-version.txt delete mode 100644 build/pkgs/atlas/patches/ATLAS-lib/Makefile.am delete mode 100644 build/pkgs/atlas/patches/ATLAS-lib/README delete mode 100644 build/pkgs/atlas/patches/ATLAS-lib/configure.ac delete mode 100644 build/pkgs/atlas/patches/Makefile.patch delete mode 100644 build/pkgs/atlas/patches/arm_hard_floats.patch delete mode 100755 build/pkgs/atlas/patches/atlas-config delete mode 100644 build/pkgs/atlas/patches/cygwin_threads.patch delete mode 100644 build/pkgs/atlas/patches/detect.patch delete mode 100644 build/pkgs/atlas/patches/do_not_force_mutex.patch delete mode 100644 build/pkgs/atlas/patches/glibc_scanf_workaround.patch delete mode 100644 build/pkgs/atlas/spkg-check.in delete mode 100644 build/pkgs/atlas/spkg-configure.m4 delete mode 100644 build/pkgs/atlas/spkg-install.in delete mode 100644 build/pkgs/atlas/spkg-install.py delete mode 100755 build/pkgs/atlas/spkg-src delete mode 100644 build/pkgs/atlas/type diff --git a/COPYING.txt b/COPYING.txt index 2da3a8e492c..1ddd77c21a1 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -32,7 +32,6 @@ the licenses of the components of Sage are included below as well. SOFTWARE LICENSE ----------------------------------------------------------------------- arb GPLv2+ -atlas Modified BSD boehm_gc MIT-like license (see below) backports_ssl_match_hostname Python License boost_cropped Boost Software License (see below) diff --git a/README.md b/README.md index 6b9350c1fba..f4d21b555c1 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ Simplified directory layout (only essential files/directories): SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) ├── build │ └── pkgs Every package is a subdirectory here -│ ├── atlas +│ ├── 4ti2 │ … │ └── zn_poly ├── configure Top-level configure script @@ -381,9 +381,9 @@ SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) │ ├── dochtml.log Log of the documentation build │ ├── install.log Full install log │ └── pkgs Build logs of individual packages -│ ├── atlas-3.10.1.p7.log +│ ├── alabaster-0.7.12.log │ … -│ └── zn_poly-0.9.p11.log +│ └── zn_poly-0.9.2.log ├── m4 M4 macros for configure │ └── *.m4 ├── Makefile Running "make" uses this file @@ -394,9 +394,9 @@ SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) │ ├── doc Sage documentation sources │ └── sage The Sage library source code ├── upstream Source tarballs of packages -│ ├── atlas-3.10.1.tar.bz2 +│ ├── Babel-2.9.1.tar.gz │ … -│ └── zn_poly-0.9.tar.bz2 +│ └── zn_poly-0.9.2.tar.gz └── VERSION.txt ``` For more details see [our Developer's Guide](https://doc.sagemath.org/html/en/developer/coding_basics.html#files-and-directory-structure). diff --git a/build/bin/sage-package b/build/bin/sage-package index ed72756bf26..eeebbcd2c2e 100755 --- a/build/bin/sage-package +++ b/build/bin/sage-package @@ -16,7 +16,6 @@ # $ sage-package list | sort # 4ti2 # arb -# atlas # autotools # [...] # zn_poly diff --git a/build/pkgs/atlas/SPKG.rst b/build/pkgs/atlas/SPKG.rst deleted file mode 100644 index f024ff2c753..00000000000 --- a/build/pkgs/atlas/SPKG.rst +++ /dev/null @@ -1,107 +0,0 @@ -atlas: Automatically Tuned Linear Algebra Software (BLAS implementation) -======================================================================== - -Description ------------ - -Automatically Tuned Linear Algebra Software - -License -------- - -3-clause BSD - - -Upstream Contact ----------------- - -- http://math-atlas.sourceforge.net -- Atlas devel mailing list. -- Clint Whaley has frequently answered questions from the Sage project - -Dependencies ------------- - -- Python - - -Special Update/Build Instructions ---------------------------------- - -- src/lapack-x.y.z.tgz: The netlib lapack tarball. If you update this, - make sure you also update the LAPACK_TARBALL variable in - spkg-install. - -- src/ATLAS-lib: We are using a dummy autotools/libtools project - to repack the static ATLAS libraries into shared libraries. - -- src/ARCHS: We ship some archdef tarballs to speed ATLAS build. -- spkg-install: If you update atlas to a new version make sure that the - ATLAS_OSTYPE, ATLAS_MACHTYPE, and ATLAS_ISAEXT variables in - spkg-install remain in sync with atlas' CONFIG/include/atlconf.h - -- The package is never installed on OS X, unless you set - SAGE_ATLAS_ARCH. - -Patches -~~~~~~~ - -- patches/detect.patch: Fix Itanium2 support on modern - RHEL 5 and SLES 10 systems, work around -m64 issue on Itanium2, - and correctly detect number and speed of CPUs on a bunch of systems. - -- patches/arm_hard_floats.patch: make sure soft floats are not enforced - on ARM. -- patches/Makefile.patch: fix clean target. -- patches/do_not_force_mutex.patch: always use assembly over mutex - since the mutex version fails to build a shared library. See #15045 - for details. - -- patches/glibc_scanf_workaround.patch: Workaround for the scanf bug - in glibc-2.18 that breaks the atlas auto-tuning system. - -Configuration -~~~~~~~~~~~~~ - -The package can be configured via three environment variables: - -- SAGE_ATLAS_LIB=path - - If this environment variable is set, the libraries libatlas, - libcblas, liblapack, and libf77blas from the direcory "path" are - used and ATLAS is not compiled from source. The libraries can be - either static (endin in .a) or shared libraries (ending in .so or - .dylib). - -- SAGE_ATLAS_ARCH=arch[,isaext1][,isaext2]...[,isaextN] - - The given architectural default and instruction set extensions are - used instead of the empirical tuning. Available architectures are - - POWER3, POWER4, POWER5, PPCG4, PPCG5, POWER6, POWER7, IBMz9, - IBMz10, IBMz196, x86x87, x86SSE1, x86SSE2, x86SSE3, P5, P5MMX, - PPRO, PII, PIII, PM, CoreSolo, CoreDuo, Core2Solo, Core2, Corei1, - Corei2, Atom, P4, P4E, Efficeon, K7, HAMMER, AMD64K10h, AMDDOZER, - UNKNOWNx86, IA64Itan, IA64Itan2, USI, USII, USIII, USIV, UST1, UST2, - UnknownUS, MIPSR1xK, MIPSICE9, ARMv6, ARMv7 - - and instruction set extensions are - - VSX, AltiVec, AVXMAC, AVXFMA4, AVX, SSE3, SSE2, SSE1, 3DNow, NEON - - In addition, you can also set - -- SAGE_ATLAS_ARCH=fast picks defaults for a modern (2-3 year old) - CPU of your processor line, and - -- SAGE_ATLAS_ARCH=base picks defaults that should work for a ~10 - year old CPU. - - For example, - - SAGE_ATLAS_ARCH=Corei2,AVX,SSE3,SSE2,SSE1 - - would be appropriate for a Core i7 CPU. - -- If SAGE_ATLAS_SAVE_ARCHDEF = is given, then a new archdef - file is created and saved to the given path. diff --git a/build/pkgs/atlas/checksums.ini b/build/pkgs/atlas/checksums.ini deleted file mode 100644 index 76fce8ca4cd..00000000000 --- a/build/pkgs/atlas/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=atlas-VERSION.tar.bz2 -sha1=7d24b5f5213479bd55d997d03d187731be4013b6 -md5=d9ca580b85e165a9870db6187542582e -cksum=1184071458 diff --git a/build/pkgs/atlas/configuration.py b/build/pkgs/atlas/configuration.py deleted file mode 100644 index cea295d1906..00000000000 --- a/build/pkgs/atlas/configuration.py +++ /dev/null @@ -1,249 +0,0 @@ -###################################################################### -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -###################################################################### - -from __future__ import print_function - -import platform -import os -import sys -import shutil -import glob -import subprocess - - -# this dictionary will hold all configuration information -conf = dict() - -# Here is a list of keys and (some of) their possible values. First, -# strings: -# -# system: Linux, SunOS, Darwin, FreeBSD, CYGWIN -# release: (Version number of the operating system, output of uname -r) -# machine: i386, x86_64, # Linux, Darwin, *BSD -# sun4u, i86pc # SunOS -# processor: i386, x86_64, powerpc, sparc -# bits: 32bit, 64bit -# fortran: g95, gfortran -# ld: GNU, Solaris, Darwin - -# The following pre-defined boolean values are determined from the -# strings. The keys are distinguished by a question mark at the -# end. If possible use these keys as they guard against typos. -# -# Linux?, Solaris?, Darwin?, FreeBSD?, CYGWIN? # system -# OS_X_Lion? # release -# Intel?, PPC?, SPARC? ARM? # processor -# 64bit?, 32bit? # bits -# fortran_g95?, fortran_GNU? # fortran -# linker_GNU?, linker_Solaris?, linker_Darwin? # ld - - -###################################################################### -### Functions -###################################################################### - -def try_run(command, ignore=False): - """ - Try to execute ``command`` and return its output as string. - - Return ``None`` if command not found. Return ``None`` if execution - fails and ``ignore=False`` (default). Otherwise, return output of - ``command`` as string. Here, output always means the concatenation - of stdout and stderr. - """ - f = subprocess.Popen(command, shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - result = f.communicate() - rc = f.wait() - if (not ignore) and (rc!=0): - return None - # concatenate stdout and stderr - return (result[0].strip() + result[1].strip()).decode('utf8') - - -def cp(source_pattern, destination): - """ - Portable implementation of "cp -p" - """ - for filename in glob.iglob(source_pattern): - print('Copying', filename, 'to', destination) - shutil.copy2(filename, destination) - - -def ln(source, destination): - """ - Portable implementation of "ln -sf" - """ - if os.path.exists(destination): - os.remove(destination) - print('Linking', source, 'to', destination) - os.symlink(source, destination) - - -def is_executable_file(fpath): - """ - Check that `fpath` is a file and executable (ie not a directory with +x set) - """ - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - -def which(program): - """ - Portable implementation of "which" - """ - fpath, fname = os.path.split(program) - if fpath != '': - return program - for path in os.environ['PATH'].split(os.pathsep): - f = os.path.join(path, program) - if is_executable_file(f): - return f - raise ValueError('The program '+program+' is not in the $PATH.') - -class edit_in_place(object): - """ - Edit a file in-place by search/replacing regular expressions. - """ - def __init__(self, filename): - self.filename = filename - f = open(filename, 'r') - self.data = f.read() - f.close() - - def replace(self, find_regex, subs, count=0): - self.data = glob.re.sub(find_regex, subs, self.data, count) - return self - - def close(self): - f = open(self.filename, 'w') - f.write(self.data) - f.close() - - -###################################################################### -### uname -###################################################################### - -try: - conf['system'] = os.environ['UNAME'] -except KeyError: - conf['system'] = platform.system() - -try: - conf['release'] = subprocess.check_output(['uname', '-r']).decode('utf8').strip() -except subprocess.CalledProcessError: - conf['release'] = "" - -conf['Linux?' ] = (conf['system'] == 'Linux') -conf['Solaris?'] = (conf['system'] == 'SunOS') -conf['Darwin?' ] = (conf['system'] == 'Darwin') -conf['OS_X_Lion?'] = (conf['Darwin?'] and conf['release'].startswith('11.')) -conf['FreeBSD?'] = (conf['system'] == 'FreeBSD') -conf['CYGWIN?' ] = (conf['system'] == 'CYGWIN') - -conf['machine'] = platform.machine() - -conf['processor'] = platform.processor() - -conf['ARM?'] = (platform.machine().startswith('arm')) -conf['Intel?'] = (platform.machine() in ('i386', 'i486', 'i586', 'i686', 'x86_64', - 'AMD64', 'i86pc')) -conf['IA64?'] = ((platform.processor() == 'ia64') - or (platform.machine() == 'ia64')) -conf['PPC?'] = (platform.processor() == 'powerpc') -conf['SPARC?'] = (platform.processor() == 'sparc') - -conf['generic_binary?'] = (os.environ.get('SAGE_FAT_BINARY', 'no') == 'yes') - -conf['user'] = os.environ.get('ATLAS_CONFIGURE', '') - -###################################################################### -### bit width -###################################################################### - -conf['bits'] = platform.architecture()[0] - -conf['64bit?'] = (conf['bits'] == '64bit') -conf['32bit?'] = (conf['bits'] != '64bit') - - -###################################################################### -### fortran compiler -###################################################################### - -fortran_version = try_run('$FC --version') -if fortran_version is None: - print('Cannot execute fortran compiler ($FC)!') - sys.exit(3) -if 'G95' in fortran_version: - conf['fortran'] = 'g95' -elif 'GNU Fortran' in fortran_version: - conf['fortran'] = 'gfortran' -else: - print('Unknown fortran compiler version: '+fortran_version) - conf['fortran'] = None - - -conf['fortran_g95?'] = (conf['fortran'] == 'g95') -conf['fortran_GNU?'] = (conf['fortran'] == 'gfortran') - - -if conf['fortran_g95?']: - g95_dir = glob.glob(os.environ['SAGE_LOCAL']+'/lib/gcc-lib/*/*') - assert len(g95_dir)==1, 'Could not find G95 dir: '+str(g95_dir) - conf['fortran_g95_dir'] = g95_dir[0] - -###################################################################### -### linker -###################################################################### - -if conf['Solaris?']: - # Note: Solaris linker does not accept --version - # ignore error code as 'ld -V' likes to error on some Solaris versions - ld_version = try_run('ld -V', ignore=True) -else: - ld_version = try_run('ld -v') - -if ld_version is None: - print('Cannot execute ld!') - sys.exit(3) -if 'GNU' in ld_version: - conf['ld'] = 'GNU' -elif 'Solaris' in ld_version: - conf['ld'] = 'Solaris' -elif 'Apple' in ld_version: - conf['ld'] = 'Darwin' -else: - print('Unknown linker: '+ld_version) - conf['ld'] = None - -conf['linker_GNU?'] = (conf['ld'] == 'GNU') -conf['linker_Solaris?'] = (conf['ld'] == 'Solaris') -conf['linker_Darwin?'] = (conf['ld'] == 'Darwin') - - -if conf['Solaris?'] and conf['linker_GNU?']: - print("WARNING: You are using the GNU linker from 'binutils'") - print("Generally it is considered better to use the Sun linker") - print("but Sage has been built on Solaris using the GNU linker") - print("although that was a very old version of Sage, which") - print("never passes all the Sage test-suite.") - - - -###################################################################### -### paths, files, and environment variables -###################################################################### - -conf['SPKG_DIR'] = os.getcwd() -conf['SAGE_LOCAL'] = os.environ['SAGE_LOCAL'] - - -###################################################################### -### The end: print configuration -###################################################################### - -print("Configuration:") -for k in sorted(conf, key=str.lower): - print(' {}: {}'.format(k, conf[k])) diff --git a/build/pkgs/atlas/dependencies b/build/pkgs/atlas/dependencies deleted file mode 100644 index 46757bc2b61..00000000000 --- a/build/pkgs/atlas/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -gfortran | $(PYTHON) - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/atlas/enums.py b/build/pkgs/atlas/enums.py deleted file mode 100644 index 29a2ca787ba..00000000000 --- a/build/pkgs/atlas/enums.py +++ /dev/null @@ -1,202 +0,0 @@ -""" -Verify that the ATLAS enums are in sync with the spkg-install enums - -TESTS:: - - sage: check_enums(sample_print_enums_output) -""" - -from __future__ import print_function - -# constants from src/ATLAS/CONFIG/include/atlconf.h -# Note: must be lists, not tuples, for Python-2.4 support - -ATLAS_OSTYPE = ( # static char *osnam - 'UNKNOWN', 'Linux', 'SunOS', 'SunOS4', 'OSF1', 'IRIX', 'AIX', - 'Win9x', 'WinNT', 'Win64', 'HPUX', 'FreeBSD', 'OSX') - -ATLAS_MACHTYPE = ( # static char *machnam - 'UNKNOWN', 'POWER3', 'POWER4', 'POWER5', 'PPCG4', 'PPCG5', - 'POWER6', 'POWER7', 'POWERe6500', 'IBMz9', 'IBMz10', 'IBMz196', - 'x86x87', 'x86SSE1', 'x86SSE2', 'x86SSE3', - 'P5', 'P5MMX', 'PPRO', 'PII', 'PIII', 'PM', 'CoreSolo', - 'CoreDuo', 'Core2Solo', 'Core2', 'Corei1', 'Corei2', 'Corei3', - 'Atom', 'P4', 'P4E', - 'Efficeon', 'K7', 'HAMMER', 'AMD64K10h', 'AMDLLANO', 'AMDDOZER','AMDDRIVER', - 'UNKNOWNx86', 'IA64Itan', 'IA64Itan2', - 'USI', 'USII', 'USIII', 'USIV', 'UST1', 'UST2', 'UnknownUS', - 'MIPSR1xK', 'MIPSICE9', 'ARMv6', 'ARMv7') - -ATLAS_ISAEXT = ( # static char *ISAXNAM - 'None', 'VSX', 'AltiVec', 'AVXMAC', 'AVXFMA4', 'AVX', 'SSE3', 'SSE2', 'SSE1', - '3DNow', 'NEON') - - - -# for doctesting purposes -sample_print_enums_output = \ -""" -Architectural enums (Config's enum MACHTYPE): - 0 = 'UNKNOWN' - 1 = 'POWER3' - 2 = 'POWER4' - 3 = 'POWER5' - 4 = 'PPCG4' - 5 = 'PPCG5' - 6 = 'POWER6' - 7 = 'POWER7' - 8 = 'POWERe6500' - 9 = 'IBMz9' - 10 = 'IBMz10' - 11 = 'IBMz196' - 12 = 'x86x87' - 13 = 'x86SSE1' - 14 = 'x86SSE2' - 15 = 'x86SSE3' - 16 = 'P5' - 17 = 'P5MMX' - 18 = 'PPRO' - 19 = 'PII' - 20 = 'PIII' - 21 = 'PM' - 22 = 'CoreSolo' - 23 = 'CoreDuo' - 24 = 'Core2Solo' - 25 = 'Core2' - 26 = 'Corei1' - 27 = 'Corei2' - 28 = 'Corei3' - 29 = 'Atom' - 30 = 'P4' - 31 = 'P4E' - 32 = 'Efficeon' - 33 = 'K7' - 34 = 'HAMMER' - 35 = 'AMD64K10h' - 36 = 'AMDLLANO' - 37 = 'AMDDOZER' - 38 = 'AMDDRIVER' - 39 = 'UNKNOWNx86' - 40 = 'IA64Itan' - 41 = 'IA64Itan2' - 42 = 'USI' - 43 = 'USII' - 44 = 'USIII' - 45 = 'USIV' - 46 = 'UST1' - 47 = 'UST2' - 48 = 'UnknownUS' - 49 = 'MIPSR1xK' - 50 = 'MIPSICE9' - 51 = 'ARMv6' - 52 = 'ARMv7' - -Operating System enums (Config's enum OSTYPE): - 0 = 'UNKNOWN' - 1 = 'Linux' - 2 = 'SunOS' - 3 = 'SunOS4' - 4 = 'OSF1' - 5 = 'IRIX' - 6 = 'AIX' - 7 = 'Win9x' - 8 = 'WinNT' - 9 = 'Win64' - 10 = 'HPUX' - 11 = 'FreeBSD' - 12 = 'OSX' - -Compiler integer defines: - 0 = 'ICC' - 1 = 'SMC' - 2 = 'DMC' - 3 = 'SKC' - 4 = 'DKC' - 5 = 'XCC' - 6 = 'GCC' - 7 = 'F77' - - -ISA extensions are combined by adding their values together (bitvector): - none: 1 - VSX: 2 - AltiVec: 4 - AVXMAC: 8 - AVXFMA4: 16 - AVX: 32 - SSE3: 64 - SSE2: 128 - SSE1: 256 - 3DNow: 512 - NEON: 1024 - -""" - - -def check_enums(print_enums_output): - """ - Verify that the output of ATLAS print_enums matches our enums - - INPUT: - - - ``print_enums_output`` -- string. The output of the ATLAS - print_enums utility. - """ - lines = print_enums_output.splitlines() - found_MACHTYPE = found_OSTYPE = found_ISAEXT = False - while len(lines) > 0: - line = lines.pop(0) - if line.startswith('Architectural enums'): - check_enums_ATLAS_MACHTYPE(lines) - found_MACHTYPE = True - if line.startswith('Operating System enums'): - check_enums_ATLAS_OSTYPE(lines) - found_OSTYPE = True - if line.startswith('ISA extensions'): - check_enums_ATLAS_ISAEXT(lines) - found_ISAEXT = True - if not (found_MACHTYPE and found_OSTYPE and found_ISAEXT): - raise RuntimeError('failed to parse the output of print_enums') - - -def check_enums_ATLAS_MACHTYPE(lines): - for i, mach_type in enumerate(ATLAS_MACHTYPE): - got = lines.pop(0).strip() - expect = "{0} = '{1}'".format(i, mach_type) - if got != expect: - raise RuntimeError('ATLAS_MACHTYPE mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - -def check_enums_ATLAS_OSTYPE(lines): - for i, os_type in enumerate(ATLAS_OSTYPE): - got = lines.pop(0).strip() - expect = "{0} = '{1}'".format(i, os_type) - if got != expect: - raise RuntimeError('ATLAS_OSTYPE mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - -def check_enums_ATLAS_ISAEXT(lines): - for i, isaext in enumerate(ATLAS_ISAEXT): - got = lines.pop(0).strip() - if i == 0: - expect = 'none: 1' - else: - expect = "{0}: {1}".format(isaext, 1 << i) - if got != expect: - raise RuntimeError('ATLAS_ISAEXT mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - - -def make_check_enums(): - """ - Build the print_enums utility and check its output against our - enums - - You can only call this function when you are in the atlas build - directory, and only after configuring atlas. - """ - from subprocess import check_output - output = check_output('make xprint_enums ; ./xprint_enums', shell=True) - print(output) - check_enums(output.decode('ascii')) - diff --git a/build/pkgs/atlas/package-version.txt b/build/pkgs/atlas/package-version.txt deleted file mode 100644 index d7150972a41..00000000000 --- a/build/pkgs/atlas/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -3.10.2.p3 diff --git a/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am b/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am deleted file mode 100644 index 46abdb9e6e4..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am +++ /dev/null @@ -1,118 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -# Upstream doesn't version libraries, so this is kind of arbitrary -SO_VERSION=3:0 - -# You shouldn't have to customize anything from here on - -ATLAS_SERIAL_LIBS=atlas cblas f77blas lapack - -ATLAS_PARALLEL_LIBS=ptcblas ptf77blas ptlapack - -all: all_parallel - -all_serial: $(ATLAS_SERIAL_LIBS) - -all_parallel: all_serial $(ATLAS_PARALLEL_LIBS) - -clean: - $(RM) -r -f .libs *.la *.dll *.dll.a *-obj - -install: install_parallel - -install_serial: $(ATLAS_SERIAL_LIBS) - $(MKDIR_P) @libdir@ - $(MKDIR_P) @bindir@ - for module in $(ATLAS_SERIAL_LIBS); do \ - @LTINSTALL@; \ - done; - @LIBTOOL@ --finish @libdir@ - @LIBTOOL@ --finish @bindir@ - -install_parallel: install_serial $(ATLAS_PARALLEL_LIBS) - $(MKDIR_P) @libdir@ - $(MKDIR_P) @bindir@ - for module in $(ATLAS_PARALLEL_LIBS); do \ - @LTINSTALL@; \ - done; - @LIBTOOL@ --finish @libdir@ - @LIBTOOL@ --finish @bindir@ - -# In presence of multiple definitions of thread related functions, use the ones from *_mut.o -# Works with all nm output formats (BSD/POSIX/System V) -atlas: libatlas.a - -$(RM) -r -f libatlas-obj - $(MKDIR) libatlas-obj - cd libatlas-obj && $(AR) x ../$< && cd .. - if [ `$(NM) -g $< | $(EGREP) -w 'ATL_(Set|Reset|Free|Dec)AtomicCount' | $(GREP) -w T | wc -l` -gt 4 ]; then \ - $(RM) `ls -1 libatlas-obj/ATL_{Set,Reset,Free,Dec}AtomicCount_*.o | $(GREP) -v '_mut.o$$'`; \ - fi - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libatlas-obj/*.o \ - @PTHREAD_LIB@ -lm \ - @LTLINKFLAGS@ - -cblas: libcblas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libcblas-obj - $(MKDIR) libcblas-obj - cd libcblas-obj && $(AR) x ../$< && cd .. - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libcblas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -ptcblas: libptcblas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libptcblas-obj - $(MKDIR) libptcblas-obj - cd libptcblas-obj && $(AR) x ../$< && cd .. - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptcblas-obj/*.o \ - @PTHREAD_LIB@ -latlas \ - @LTLINKFLAGS@ - -f77blas: libf77blas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libf77blas-obj - $(MKDIR) libf77blas-obj - cd libf77blas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libf77blas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -ptf77blas: libptf77blas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libptf77blas-obj - $(MKDIR) libptf77blas-obj - cd libptf77blas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptf77blas-obj/*.o \ - @PTHREAD_LIB@ -latlas \ - @LTLINKFLAGS@ - -f77refblas: libf77refblas.a - -$(RM) -r -f libf77refblas-obj - $(MKDIR) libf77refblas-obj - cd libf77refblas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libf77refblas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -lapack: liblapack.a @LTPREFIX@atlas@LTSUFFIX@ @LTPREFIX@cblas@LTSUFFIX@ @LTPREFIX@f77blas@LTSUFFIX@ - -$(RM) -r -f liblapack-obj - $(MKDIR) liblapack-obj - cd liblapack-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ liblapack-obj/*.o \ - -lcblas -lf77blas -latlas -lm \ - @LTLINKFLAGS@ - -ptlapack: libptlapack.a @LTPREFIX@atlas@LTSUFFIX@ @LTPREFIX@ptcblas@LTSUFFIX@ @LTPREFIX@ptf77blas@LTSUFFIX@ - -$(RM) -r -f libptlapack-obj - $(MKDIR) libptlapack-obj - cd libptlapack-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptlapack-obj/*.o \ - @PTHREAD_LIB@ -lptcblas -lptf77blas -latlas -lm \ - @LTLINKFLAGS@ - -.PHONY: all all_serial all_parallel build install install_serial install_parallel clean $(ATLAS_SERIAL_LIBS) $(ATLAS_PARALLEL_LIBS) diff --git a/build/pkgs/atlas/patches/ATLAS-lib/README b/build/pkgs/atlas/patches/ATLAS-lib/README deleted file mode 100644 index 461f03e8ebb..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/README +++ /dev/null @@ -1,3 +0,0 @@ -This is a stub autotools project to generate the system-dependent -libtool script. Nothing is compiled here. The Makefile.am unpacks the -atlas static libraries and repacks them into shared libraries. diff --git a/build/pkgs/atlas/patches/ATLAS-lib/configure.ac b/build/pkgs/atlas/patches/ATLAS-lib/configure.ac deleted file mode 100644 index 0ce6a0f44b9..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/configure.ac +++ /dev/null @@ -1,51 +0,0 @@ -AC_INIT([ATLAS],[3.10.1]) -AM_INIT_AUTOMAKE(foreign) - -AC_CANONICAL_HOST - -LT_INIT - -AC_PROG_CC -AC_PROG_F77 - -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_MACRO_DIR([m4]) - -AC_CHECK_LIB(pthread, pthread_create, [PTHREAD_LIB="-lpthread"]) -AC_SUBST(PTHREAD_LIB) - -AC_ARG_ENABLE([static], - [AS_HELP_STRING([--enable-static], - [also install static libtool library (default: no)])]) -AS_IF([test "x$enable_static" = "xyes"], - [libtool_type=""], - [libtool_type=-shared]) -AC_SUBST(LIBTOOL_TYPE, [$libtool_type]) - -case $host in - *-*-cygwin*) - LTPREFIX=cyg - LTSUFFIX=.dll - LTCLINK="\$(CC) -L. -shared" - LTF77LINK="\$(F77) -L. -shared" - LTLINKFLAGS="-Wl,--out-implib=lib\$@.dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import" - LTINSTALL="\$(CP) \$(LTPREFIX)\$\${module}\$(LTSUFFIX) \$(bindir)/\$(LTPREFIX)\$\${module}\$(LTSUFFIX); \$(CP) lib\$\${module}.dll.a \$(libdir)/lib\$\${module}.dll.a" - ;; - *) - LTPREFIX=lib - LTSUFFIX=.la - LTCLINK="\$(LIBTOOL) --tag=CC --mode=link \$(CC) \$(LIBTOOL_FLAG)" - LTF77LINK="\$(LIBTOOL) --tag=F77 --mode=link \$(F77) \$(LIBTOOL_FLAG)" - LTLINKFLAGS="-rpath \$(libdir) -version-info \$(SO_VERSION)" - LTINSTALL="\$(LIBTOOL) --mode=install \$(INSTALL) -c \$(LTPREFIX)\$\${module}\$(LTSUFFIX) \$(libdir)/\$(LTPREFIX)\$\${module}\$(LTSUFFIX)" - ;; -esac - -AC_SUBST(LTPREFIX) -AC_SUBST(LTSUFFIX) -AC_SUBST(LTCLINK) -AC_SUBST(LTF77LINK) -AC_SUBST(LTLINKFLAGS) -AC_SUBST(LTINSTALL) - -AC_OUTPUT diff --git a/build/pkgs/atlas/patches/Makefile.patch b/build/pkgs/atlas/patches/Makefile.patch deleted file mode 100644 index 69662626b49..00000000000 --- a/build/pkgs/atlas/patches/Makefile.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- src/ATLAS/CONFIG/src/Makefile 2012-06-23 17:27:27.000000000 +0100 -+++ new/ATLAS/CONFIG/src/Makefile 2012-06-24 03:05:52.043151077 +0100 -@@ -580,6 +580,6 @@ - confclean: $(CLEANdep) - rm -f *core* *.o config?.out - clean : $(CLEANdep) -- rm -f *.o x* config?.out *core* -+ rm -rf *.o x* config?.out *core* - cleanall: clean - $(MAKE) -f Make.top clean diff --git a/build/pkgs/atlas/patches/arm_hard_floats.patch b/build/pkgs/atlas/patches/arm_hard_floats.patch deleted file mode 100644 index 64cadd1f404..00000000000 --- a/build/pkgs/atlas/patches/arm_hard_floats.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -druN ATLAS.detect/ATLAS/CONFIG/src/atlcomp.txt ATLAS/ATLAS/CONFIG/src/atlcomp.txt ---- ATLAS.detect/ATLAS/CONFIG/src/atlcomp.txt 2013-01-08 10:15:42.000000000 -0800 -+++ ATLAS/ATLAS/CONFIG/src/atlcomp.txt 2014-02-10 04:36:26.113011794 -0800 -@@ -255,13 +255,13 @@ - # ARM defaults - # - MACH=ARMv7 OS=ALL LVL=1000 COMPS=xcc -- 'gcc' '-mcpu=cortex-a8 -O1 -mfpu=vfpv3 -mfloat-abi=softfp ' -+ 'gcc' '-mcpu=cortex-a8 -O1 -mfpu=vfpv3 -mfloat-abi=hard ' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=smc,skc,gcc,icc -- 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -fno-expensive-optimizations' -+ 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -fno-expensive-optimizations' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=dmc,dkc -- 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -fno-schedule-insns2' -+ 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -fno-schedule-insns2' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=f77 -- 'gfortran' '-mcpu=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -O' -+ 'gfortran' '-mcpu=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -O' - # - # Generic defaults - # diff --git a/build/pkgs/atlas/patches/atlas-config b/build/pkgs/atlas/patches/atlas-config deleted file mode 100755 index 1f92bb43e62..00000000000 --- a/build/pkgs/atlas/patches/atlas-config +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env sage-bootstrap-python - -import sys, errno, os, platform, time, glob, subprocess, signal, argparse - -parser = argparse.ArgumentParser( - description='(Re-)Build ATLAS (http://math-atlas.sourceforge.net) ' - 'according to the SAGE_ATLAS_ARCH environment variable') - -parser.add_argument('--unthrottle', nargs=1, type=int, - help='switch CPU throttling off until PID finishes', - metavar='PID') - -parser.add_argument('--archdef', action='store_const', const=True, - help='build archdef tarball and save it to the current directory') - - -def pid_exists(pid): - """ - Check whether pid exists in the current process table. - """ - if pid < 0: - return False - try: - os.kill(pid, 0) - except OSError as e: - return e.errno == errno.EPERM - else: - return True - - -def unthrottle_posix(pid): - cpus = list(glob.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor')) - scaling_governor = [] - for cpu in cpus: - with open(cpu, 'r') as f: - scaling_governor.append(f.readline()) - for cpu in cpus: - with open(cpu, 'w') as f: - f.write('performance') - - def signal_handler(signum, frame): - print('Signal handler called with signal', signum) - for cpu, governor in zip(cpus, scaling_governor): - with open(cpu, 'w') as f: - f.write(governor) - print('Reverted throttling to the previous behaviour.') - sys.exit(0) - - signal.signal(signal.SIGPIPE, signal_handler) - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - try: - while pid_exists(pid): - time.sleep(1) - except KeyboardInterrupt: - pass - - signal_handler(None, None) - - -def unthrottle(pid): - if os.name == 'posix': - unthrottle_posix(pid) - else: - print('I don\'t know how to unthrottle your system (' + - platform.system() + ')') - sys.exit(3) - - - -def is_throttled_posix(): - cpus = list(glob.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor')) - for cpu in cpus: - with open(cpu, 'r') as f: - if f.readline().strip() != 'performance': - return True - return False - - -def is_throttled(): - if os.name == 'posix': - return is_throttled_posix() - else: - print('I don\'t know how to unthrottle your system (' + - platform.system() + ')') - sys.exit(3) - - -def check_root(): - if os.name == 'posix': - if os.getuid() == 0: - return - print('\nError: You need to be root to (un)throttle the CPU.\n') - sys.exit(1) - else: - print('I don\'t know how to probe administrator rights on your system ('+platform.system()+')') - sys.exit(3) - - -def check_nonroot(): - if os.name == 'posix': - if os.getuid() > 0: - return - print('\nError: You are crazy to run this as root, exiting.\n') - sys.exit(2) - else: - print('I don\'t know how to probe administrator rights on your system ('+platform.system()+')') - sys.exit(3) - - -command = None - -def wait_for_command(): - global command - if command is None: - return - else: - command.send_signal(signal.SIGTERM) - -import atexit -atexit.register(wait_for_command) - - -def unthrottle_self(): - if os.name == 'posix': - global command - print('Running sudo atlas-config --unthrottle to turn CPU throttling off.') - command = subprocess.Popen(['sudo', os.path.abspath( __file__ ), - '--unthrottle', str(os.getpid())]) - else: - print('I don\'t know how to unthrottle your system ('+platform.system()+')') - sys.exit(2) - - print('Waiting for CPU throttling to be turned off...') - while is_throttled(): - time.sleep(1) - - - -if __name__ == '__main__': - args = parser.parse_args() - - if args.unthrottle: - check_root() - unthrottle(args.unthrottle[0]) - - check_nonroot() - unthrottle_self() - print - if os.environ.get('SAGE_FAT_BINARY', 'no') == 'yes': - print('Building ATLAS with SAGE_FAT_BINARY (generic archdefs).') - elif 'SAGE_ATLAS_ARCH' in os.environ: - print('Building ATLAS with SAGE_ATLAS_ARCH =', os.environ['SAGE_ATLAS_ARCH']) - else: - print('Building ATLAS without specifying architecture.') - print('This may take many hours during which you should leave the computer otherwise') - print('idle to obtain accurate timings.') - if args.archdef: - os.environ['SAGE_ATLAS_SAVE_ARCHDEF'] = os.getcwd() - print('The resulting .tar.bz2 will be saved in ' + os.getcwd()) - print() - print('You have 5 seconds to interrupt...') - time.sleep(1) - print('You have 4 seconds to interrupt...') - time.sleep(1) - print('You have 3 seconds to interrupt...') - time.sleep(1) - print('You have 2 seconds to interrupt...') - time.sleep(1) - print('You have 1 second to interrupt...') - time.sleep(1) - - sys.stdout.flush() - sys.stderr.flush() - os.system('sage -f atlas') diff --git a/build/pkgs/atlas/patches/cygwin_threads.patch b/build/pkgs/atlas/patches/cygwin_threads.patch deleted file mode 100644 index e2db2ec236c..00000000000 --- a/build/pkgs/atlas/patches/cygwin_threads.patch +++ /dev/null @@ -1,30 +0,0 @@ -Let ATLAS use Cygwin thread functions on Cygwin64. -diff -druN ATLAS.orig/ATLAS/src/threads/ATL_thread_start.c ATLAS.new/ATLAS/src/threads/ATL_thread_start.c ---- ATLAS.orig/ATLAS/src/threads/ATL_thread_start.c 2014-07-10 09:22:06.000000000 -0700 -+++ ATLAS.new/ATLAS/src/threads/ATL_thread_start.c 2014-11-18 07:17:39.207997205 -0800 -@@ -14,14 +14,14 @@ - */ - { - #ifdef ATL_WINTHREADS -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - DWORD thrID; - #else - unsigned thrID; - #endif - - #ifdef ATL_NOAFFINITY -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - thr->thrH = CreateThread(NULL, 0, rout, arg, 0, &thrID); - #else - thr->thrH = (HANDLE)_beginthreadex(NULL, 0, rout, arg, 0, &thrID); -@@ -29,7 +29,7 @@ - ATL_assert(thr->thrH); - #else - thr->rank = proc; -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - thr->thrH = CreateThread(NULL, 0, rout, arg, CREATE_SUSPENDED, &thrID); - #else - thr->thrH = (HANDLE)_beginthreadex(NULL, 0, rout, arg, diff --git a/build/pkgs/atlas/patches/detect.patch b/build/pkgs/atlas/patches/detect.patch deleted file mode 100644 index 7c997e387d2..00000000000 --- a/build/pkgs/atlas/patches/detect.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -druN ATLAS.orig/ATLAS/CONFIG/include/atlconf.h ATLAS/ATLAS/CONFIG/include/atlconf.h ---- ATLAS.orig/ATLAS/CONFIG/include/atlconf.h 2013-01-08 10:15:42.000000000 -0800 -+++ ATLAS/ATLAS/CONFIG/include/atlconf.h 2014-02-10 04:31:19.992981182 -0800 -@@ -18,7 +18,7 @@ - enum ARCHFAM {AFOther=0, AFPPC, AFSPARC, AFALPHA, AFX86, AFIA64, AFMIPS, - AFARM, AFS390}; - --#define NMACH 52 -+#define NMACH 53 - static char *machnam[NMACH] = - {"UNKNOWN", "POWER3", "POWER4", "POWER5", "PPCG4", "PPCG5", - "POWER6", "POWER7", "POWERe6500", "IBMz9", "IBMz10", "IBMz196", -@@ -29,7 +29,7 @@ - "Efficeon", "K7", "HAMMER", "AMD64K10h", "AMDLLANO", "AMDDOZER","AMDDRIVER", - "UNKNOWNx86", "IA64Itan", "IA64Itan2", - "USI", "USII", "USIII", "USIV", "UST1", "UST2", "UnknownUS", -- "MIPSR1xK", "MIPSICE9", "ARMv7"}; -+ "MIPSR1xK", "MIPSICE9", "ARMv6", "ARMv7"}; - enum MACHTYPE {MACHOther, IbmPwr3, IbmPwr4, IbmPwr5, PPCG4, PPCG5, - IbmPwr6, IbmPwr7, Pwre6500, - IbmZ9, IbmZ10, IbmZ196, /* s390(x) in Linux */ -@@ -42,6 +42,7 @@ - SunUSI, SunUSII, SunUSIII, SunUSIV, SunUST1, SunUST2, SunUSX, - MIPSR1xK, /* includes R10K, R12K, R14K, R16K */ - MIPSICE9, /* SiCortex ICE9 -- like MIPS5K */ -+ ARMv6, /* includes Raspberry Pi */ - ARMv7 /* includes Cortex A8, A9 */ - }; - #define MachIsX86(mach_) \ -@@ -60,7 +61,7 @@ - #define MachIsPPC(mach_) \ - ( (mach_) >= PPCG4 && (mach_) <= PPCG5 ) - #define MachIsARM(mach_) \ -- ( (mach_) == ARMv7 ) -+ ( (mach_) >= ARMv6 && (mach_) <= ARMv7 ) - #define MachIsS390(mach_) \ - ( (mach_) >= IbmZ9 && (mach_) <= IbmZ196 ) - diff --git a/build/pkgs/atlas/patches/do_not_force_mutex.patch b/build/pkgs/atlas/patches/do_not_force_mutex.patch deleted file mode 100644 index bd09ae08c12..00000000000 --- a/build/pkgs/atlas/patches/do_not_force_mutex.patch +++ /dev/null @@ -1,18 +0,0 @@ -Always use assembly over mutex since the mutex version fails to build -a shared library. See #15045 for details. - -diff --git a/ATLAS/tune/threads/tune_count.c b/ATLAS/tune/threads/tune_count.c -index f09717f..4dc3fde 100644 ---- a/ATLAS/tune/threads/tune_count.c -+++ b/ATLAS/tune/threads/tune_count.c -@@ -241,8 +241,8 @@ int main(int nargs, char **args) - */ - if (tmut < tldec*1.02) - { -- printf("\nNO REAL ADVANTAGE TO ASSEMBLY, FORCING USE OF MUTEX\n"); -- ATL_assert(!system("make iForceUseMutex")); -+ printf("\nNO REAL ADVANTAGE TO ASSEMBLY OVER MUTEX\n"); -+ printf("\nASSEMBLY/MUTEX ratio is %.2f, but we'll stick with assembly anyway\n", tldec/tmut); - } - } - free(timearr); diff --git a/build/pkgs/atlas/patches/glibc_scanf_workaround.patch b/build/pkgs/atlas/patches/glibc_scanf_workaround.patch deleted file mode 100644 index dba90a94677..00000000000 --- a/build/pkgs/atlas/patches/glibc_scanf_workaround.patch +++ /dev/null @@ -1,29 +0,0 @@ -Bug in glibc-2.18: https://sourceware.org/bugzilla/show_bug.cgi?id=15917 - - ---- a/ATLAS/tune/sysinfo/masrch.c -+++ b/ATLAS/tune/sysinfo/masrch.c -@@ -1,6 +1,7 @@ - #include - #include - #include -+#include - - #ifndef NTIM - #define NTIM 3 -@@ -113,7 +114,14 @@ - j = 0; - for (i=0; i != NTIM; i++) - { -- assert( fscanf(fp, "%lf", &mflop[i]) ); -+ /* FIXME: This assumes one float per line immediately followed by \n. */ -+ char buf[100]; /* enough to read a double */ -+ char *end; -+ -+ assert(fgets(buf, sizeof buf, fp)); -+ errno = 0; -+ mflop[i] = strtod(buf, &end); -+ assert(errno == 0 && end != buf && *end == '\n'); - } - fclose(fp); - /* diff --git a/build/pkgs/atlas/spkg-check.in b/build/pkgs/atlas/spkg-check.in deleted file mode 100644 index 506f8f7ad89..00000000000 --- a/build/pkgs/atlas/spkg-check.in +++ /dev/null @@ -1,47 +0,0 @@ -###################################################################### -### Skip building ATLAS on specific systems -###################################################################### - -if [ "$UNAME" = "Darwin" -a -z "$SAGE_ATLAS_ARCH" ]; then - echo "System-wide accelerate framework is used on Darwin; skipping ATLAS test suite." - exit 0 -fi - -if [ ! -z "$SAGE_ATLAS_LIB" ]; then - echo "SAGE_ATLAS_LIB is set to \"$SAGE_ATLAS_LIB\"; skipping ATLAS test suite." - exit 0 -fi - - -###################################################################### -### check and collect timings -###################################################################### - -make_check() -{ - # make sure everything builds correctly - $MAKE check - if [ $? -ne 0 ]; then - echo >&2 "The ATLAS self-tests failed." - exit 1 - else - echo "The ATLAS self-tests successfully passed." - fi -} - - -make_time() -{ - # collect some timings - $MAKE time - if [ $? -ne 0 ]; then - echo >&2 "The ATLAS timing data failed to be collected." - exit 1 - else - echo "The ATLAS timing data was successfully collected." - fi -} - -cd src/ATLAS-build -make_check -make_time diff --git a/build/pkgs/atlas/spkg-configure.m4 b/build/pkgs/atlas/spkg-configure.m4 deleted file mode 100644 index cbaaa21af17..00000000000 --- a/build/pkgs/atlas/spkg-configure.m4 +++ /dev/null @@ -1,8 +0,0 @@ -SAGE_SPKG_CONFIGURE([atlas], [dnl use old test/installation procedure with env. variables - sage_spkg_install_atlas=yes - ], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_OPENBLAS]) - AS_IF([test x"$with_blas" = xatlas], [ - sage_require_openblas=no - sage_require_atlas=yes]) -]) diff --git a/build/pkgs/atlas/spkg-install.in b/build/pkgs/atlas/spkg-install.in deleted file mode 100644 index 1a1fe5a9f78..00000000000 --- a/build/pkgs/atlas/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -exec sage-bootstrap-python spkg-install.py diff --git a/build/pkgs/atlas/spkg-install.py b/build/pkgs/atlas/spkg-install.py deleted file mode 100644 index f6dfb3e8a6c..00000000000 --- a/build/pkgs/atlas/spkg-install.py +++ /dev/null @@ -1,681 +0,0 @@ -###################################################################### -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -###################################################################### - -from __future__ import print_function - -###################################################################### -### Import stuff -###################################################################### - -import os, sys, shutil, time, glob -from configuration import conf, cp, ln, which, try_run, edit_in_place -from enums import ATLAS_OSTYPE, ATLAS_MACHTYPE, ATLAS_ISAEXT, make_check_enums - - -###################################################################### -### The following variables may need to be updated if you -### update ATLAS or LAPACK to a newer version -###################################################################### - -PATCH_DIR = os.path.join(conf['SPKG_DIR'], 'patches') - -# the current lapack source tarball -LAPACK_TARFILE = os.path.join(conf['SPKG_DIR'], 'src', 'lapack-3.5.0.tar') - -# temporary directory to build everything in -BUILD_DIR = os.path.join(conf['SPKG_DIR'], 'src', 'ATLAS-build') - -# the shared library autotools stub project -BUILD_LIB_DIR = os.path.join(conf['SPKG_DIR'], 'src', 'ATLAS-lib') - -# we need to disable parallel builds -os.environ['MAKE'] += ' -j1' -MAKE = os.environ['MAKE'] - -# SAGE_LOCAL -SAGE_LOCAL = os.environ['SAGE_LOCAL'] - -###################################################################### -### Some auxiliary functions to facilitate IO and error checking -###################################################################### - -# Run shell command "command", but flush stdout and stderr before doing -# this. Also echo commands which are executed. -def system_with_flush(command): - print('Running', command) - sys.stdout.flush() - sys.stderr.flush() - import subprocess - return subprocess.call(command, shell=True) - -def assert_success(rc, good=None, bad=None): - if rc == 0: - if good is not None: - print(good) - return - print('-'*60) - import traceback - traceback.print_stack(file=sys.stdout) - print('-'*60) - if bad is not None: - print('Error:', bad) - sys.exit(rc) - - -###################################################################### -### function to save ATLAS' configuration to .pc files -###################################################################### - -def write_pc_file(libs,target): - pkgconfigdir=os.path.join(SAGE_LOCAL, 'lib', 'pkgconfig') - if not os.path.isdir(pkgconfigdir): - os.makedirs(pkgconfigdir) - libflags='-l%s'%(' -l'.join(libs)) - pcfile ="""SAGE_LOCAL=%s -prefix=${SAGE_LOCAL} -libdir=${prefix}/lib -includedir=${prefix}/include -Name: %s -Version: 1.0 -Description: %s for sage, set up by the ATLAS spkg. -Libs: -L${libdir} %s -"""%(SAGE_LOCAL, target, target, libflags) - open(os.path.join(SAGE_LOCAL, 'lib/pkgconfig/%s.pc'%target), 'w').write(pcfile) - - -###################################################################### -### Skip building ATLAS on specific systems -###################################################################### - -if conf['Darwin?'] and 'SAGE_ATLAS_ARCH' not in os.environ: - print('Skipping build of ATLAS on OS X, using system library instead.') - print('You can try building your own ATLAS by setting SAGE_ATLAS_ARCH') - print('to something sensible although that is not officially supported.') - if conf['PPC?']: # OSX 10.4 PPC linker needs help to find the accelerate blas - veclib_dir = '/System/Library/Frameworks/Accelerate.framework/' + \ - 'Versions/A/Frameworks/vecLib.framework/Versions/A' - for lib in [ 'libBLAS.dylib', 'libLAPACK.dylib']: - ln(os.path.join(veclib_dir, lib), - os.path.join(conf['SAGE_LOCAL'], 'lib', lib)) - write_pc_file(['blas'], 'cblas') - write_pc_file(['blas'], 'blas') - write_pc_file(['lapack'], 'lapack') - sys.exit(0) - - -###################################################################### -### Use SAGE_ATLAS_LIB='directory' if provided -###################################################################### - -# On Cygwin, we used to require that the system-wide lapack packages were -# installed (this included the lapack-devel and lapack packages). -# These packages indeed include BLAS and LAPACK and are enough to build -# the rest of Sage, whereas building ATLAS was problematic. -# For the record, the corresponding files to symlink from the system-wide -# packages are: '/usr/lib/libblas.dll.a' and '/usr/lib/liblapack.dll.a'. - -if 'SAGE_ATLAS_LIB' in os.environ: - ATLAS_LIB = os.environ['SAGE_ATLAS_LIB'] - - prefix = 'lib' - - libraries_sets = [['lapack', 'cblas', 'f77blas', 'atlas'], ['lapack', 'blas']] - libraries_optional = ['ptcblas', 'ptf77blas'] - - def is_atlas_lib_path(path, libs): - if path is None: - return False - if not os.path.isdir(path): - return False - filenames = os.listdir(path) - for lib in libs: - if not any(fname.startswith(prefix+lib) for fname in filenames): - print('Cannot find '+prefix+lib+'.* in '+path) - break - else: - return True - return False - - paths = [ ATLAS_LIB, os.path.join(ATLAS_LIB, 'lib64'), os.path.join(ATLAS_LIB, 'lib') ] - ATLAS_LIB = None - libraries = [] - for libs in libraries_sets: - for path in paths: - if is_atlas_lib_path(path, libs): - ATLAS_LIB = path - libraries = libs - break - else: - continue - break - - if ATLAS_LIB is None: - print('Unable to find required libraries in the directory', ATLAS_LIB) - print('Set SAGE_ATLAS_LIB to the directory containing:') - print('- liblapack, libcblas, libf77blas and libatlas;') - print('- or liblapack and libblas;') - print('you wish to use existing ATLAS libraries.') - print('For more details, see:') - print('https://doc.sagemath.org/html/en/installation/source.html#environment-variables') - print('Unset SAGE_ATLAS_LIB to build ATLAS from source.') - print('Then type make.') - sys.exit(2) - - for fname in os.listdir(ATLAS_LIB): - if fname.startswith(prefix + 'f77blas'): - f77blas = os.path.join(ATLAS_LIB, fname) - break - else: - f77blas = None - if f77blas is not None: - symbol_table = try_run('readelf -s ' + f77blas) - else: - symbol_table = None - if symbol_table is not None: - sym_gfortran = 'gfortran' in symbol_table - sym_g95 = 'g95' in symbol_table - if sym_gfortran and conf['fortran'] != 'gfortran': - print("Symbols in lib77blas indicate it was built with gfortran.\n") - print("However, Sage is using a different fortran compiler.\n") - print("If you wish to use this blas library, make sure FC points\n") - print("to a fortran compiler compatible with this library.\n") - sys.exit(2) - if sym_g95 and conf['fortran'] != 'g95': - print("Symbols in lib77blas indicate it was built with g95 \n") - print("However, Sage is using a different fortran compiler.\n") - print("If you wish to use this blas library, make sure FC points\n") - print("to a fortran compiler compatible with this library.\n") - sys.exit(2) - - SAGE_LOCAL_LIB = os.path.join(conf['SAGE_LOCAL'], 'lib') - def symlinkOSlibrary(library_basename): - filenames = [ fname for fname in os.listdir(path) - if fname.startswith(library_basename) ] - for fname in filenames: - source = os.path.join(ATLAS_LIB, fname) - destination = os.path.join(SAGE_LOCAL_LIB, fname) - print('Symlinking '+destination+' -> '+source) - try: - os.remove(destination) - except OSError: - pass - try: - os.symlink(source, destination) - except OSError: - pass - for lib in libraries + libraries_optional: - symlinkOSlibrary(prefix+lib) - - if 'atlas' in libraries: - write_pc_file(['cblas', 'atlas'], 'cblas') - write_pc_file(['f77blas', 'atlas'], 'blas') - # The inclusion of cblas is not a mistake. ATLAS' lapack include - # a custom version of clapack which depends on cblas. - write_pc_file(['lapack', 'f77blas', 'cblas', 'atlas'], 'lapack') - else: - write_pc_file(['blas'], 'cblas') - write_pc_file(['blas'], 'blas') - write_pc_file(['lapack', 'blas'], 'lapack') - - - sys.exit(0) - -# Because blas, cblas and lapack libraries are properly linked -# with no unknown symbols, no extra libraries needs to be given. -write_pc_file(['cblas'], 'cblas') -write_pc_file(['f77blas'], 'blas') -write_pc_file(['lapack'], 'lapack') - -# add extra architectural defaults -cp('src/ARCHS/*.tar.bz2', 'src/ATLAS/CONFIG/ARCHS/') - -# hardcoded gcc in SpewMakeInc.c -edit_in_place('src/ATLAS/CONFIG/src/SpewMakeInc.c') \ - .replace(' goodgcc = .*', ' goodgcc = "' + os.environ['CC'] + '";') \ - .close() - - -# override throttling check if architecture is specified -edit_in_place('src/ATLAS/CONFIG/src/config.c') \ - .replace('if \(mach == MACHOther\)', 'if (mach != MACHOther) thrchk=0; else') \ - .close() - - - -###################################################################### -### configure functions -###################################################################### - -# For debug purposes one can install static libraries via SAGE_ATLAS_ARCH=static,... -INSTALL_STATIC_LIBRARIES = False - -def configure_options_from_environment(): - # Figure out architecture (see ATLAS_MACHTYPE) and isa extensions (see - # ATLAS_ISAEXT) from environment variables: - arch = None - isa_ext = None - thread_limit = None - if conf['generic_binary?']: - print('Sage "fat" binary mode set: Building "base" binary') - print('NOTE: This can result in a Sage that is significantly slower at certain numerical') - print('linear algebra since full FAT binary support has not been implemented yet.') - arch = 'generic' - if 'SAGE_ATLAS_ARCH' not in os.environ: - return (arch, isa_ext, thread_limit) - for opt in os.environ['SAGE_ATLAS_ARCH'].split(','): - if opt.startswith('thread'): - thread_limit = int(opt.split(':')[-1]) - elif opt == 'static': - global INSTALL_STATIC_LIBRARIES - INSTALL_STATIC_LIBRARIES = True - elif opt in ATLAS_MACHTYPE + ('fast', 'base'): - if arch is not None: - raise ValueError('multiple architectures specified: {0} and {1}'.format(arch, opt)) - arch = opt - elif opt in ATLAS_ISAEXT: - if isa_ext is None: - isa_ext = [opt] - else: - isa_ext.append(opt) - else: - print('unknown SAGE_ATLAS_ARCH option: '+opt) - print('SAGE_ATLAS_ARCH architecture must be "fast", "base", or one of '+ \ - ', '.join(ATLAS_MACHTYPE)) - print('SAGE_ATLAS_ARCH ISA extension must be one of '+ ', '.join(ATLAS_ISAEXT)) - sys.exit(1) - return (arch, isa_ext, thread_limit) - - -def configure(arch=None, isa_ext=None): - """ - Configure for ``arch``. - - INPUT: - - - ``arch`` -- ``None`` or one of ``ATLAS_MACHTYPE`` - - - ``isa_ext`` -- ``None`` or a sublist of ``ATLAS_ISAEXT`` - - OUTPUT: 0 if ``configure`` was successful, 1 if it failed. - """ - try: - if arch is None: - arch, isa_ext, thread_limit = configure_options_from_environment() - if arch == 'fast': - arch, isa_ext, thread_limit = configure_fast() - if arch == 'generic' or arch == 'base': - arch, isa_ext, thread_limit = configure_base() - except NotImplementedError: - return 1 - - print('Running configure with arch = '+str(arch)+ \ - ', isa extensions '+str(isa_ext), ' thread limit '+str(thread_limit)) - if os.path.isdir(BUILD_DIR): - os.chdir(conf['SPKG_DIR']) # Solaris/ZFS can't delete cwd - shutil.rmtree(BUILD_DIR) - os.mkdir(BUILD_DIR) - os.chdir(BUILD_DIR) - - # We need to provide full pathes to FC and CC to ATLAS configure script, - # so that it does not use 'find' and travel around the filesystem to find - # them. - # We first split the compiler executable names from potential options, e.g. - # as in 'gcc -m64', then use 'which' to locate them, and finally add the - # options back. - FC = os.environ['FC'] - FCsplit = FC.find(' ') - if FCsplit != -1: - FCbin, FCopt = FC[:FCsplit], FC[FCsplit:] - else: - FCbin, FCopt = FC, '' - - CC = os.environ['CC'] - CCsplit = CC.find(' ') - if CCsplit != -1: - CCbin, CCopt = CC[:CCsplit], CC[CCsplit:] - else: - CCbin, CCopt = CC, '' - - cmd = '../ATLAS/configure' - cmd += ' --prefix=' + conf['SAGE_LOCAL'] - cmd += ' --with-netlib-lapack-tarfile=' + LAPACK_TARFILE - cmd += ' --cc="' + CC + '"' - - ## -Si latune 1: enable lapack tuning - ## typically adds 3-4 hours of install time - cmd += ' -Si latune 0' - - # Set flags for all compilers so we can build dynamic libraries - ALLFLAGS = "-fPIC " + os.environ["LDFLAGS"] - cmd += ' -Fa alg "{}"'.format(ALLFLAGS) - - # set number of threads limit: 0 = off, -1 = unlimited - if thread_limit is not None: - cmd += ' -t ' + str(thread_limit) - - # set fortran compiler - cmd += ' -C if "' + which(FCbin) + FCopt + '"' - - # set C compiler - cmd += ' -C acg "' + which(CCbin) + CCopt + '"' - - # set bit width - cmd += ' -b ' + conf['bits'][0:2] - - # set OS type - try: - if conf['Darwin?']: - atlas_osnam = 'OSX' - elif conf['CYGWIN?']: -# Picking Win64 currently does not work on Cygwin though it might be a better -# choice in the future. -# Not that ATLAS does not seem to officialy support Cygwin64 anyway in 3.10.1. -# if conf['64bit?']: -# atlas_osnam = 'Win64' -# else: - atlas_osnam = 'WinNT' - else: - atlas_osnam = conf['system'] - atlas_system = ATLAS_OSTYPE.index(atlas_osnam) - cmd += ' -O '+str(atlas_system) - except ValueError: - pass - - # use hard floats on ARM - if conf['ARM?']: - cmd += ' -D c -DATL_ARM_HARDFP=1' - - # set machine architecture - if arch is not None: - cmd += ' -A '+str(ATLAS_MACHTYPE.index(arch)) - - # set cpu instruction set extensions - if isa_ext is not None: - isa_extension = sum(1 << ATLAS_ISAEXT.index(x) for x in isa_ext) - cmd += ' -V '+str(isa_extension) - - # Custom configure options - if conf['user']: - cmd += " " + conf['user'] - - rc = system_with_flush(cmd) - make_check_enums() - return rc - - -def configure_fast(): - isa_ext = ('None',) - thread_limit = None - if conf['Intel?'] and conf['64bit?']: - print('Fast configuration on Intel x86_64 compatible CPUs.') - arch = 'P4E' - if not conf['CYGWIN?']: # cannot use assembly on Cygwin64 - isa_ext = ('SSE3', 'SSE2', 'SSE1') - elif conf['Intel?'] and conf['32bit?']: - print('Fast configuration on Intel i386 compatible CPUs.') - arch = 'x86SSE2' - isa_ext = ('SSE2', 'SSE1') - elif conf['SPARC?']: - print('Fast configuration on SPARC.') - arch = 'USIV' - elif conf['PPC?']: - print('Fast configuration on PPC.') - arch = 'PPCG5' - isa_ext = ('AltiVec', ) - elif conf['IA64?']: - print('Fast configuration on Itanium.') - arch = 'IA64Itan2' - elif conf['ARM?']: - print('Fast configuration on ARM.') - arch='ARMv7' - else: - raise NotImplementedError('I don\'t know a "fast" configuration for your cpu.') - return (arch, isa_ext, thread_limit) - - -def configure_base(): - isa_ext = ('None',) - thread_limit = 0 # disable threading in "base" - if conf['Intel?'] and conf['64bit?']: - print('Generic configuration on Intel x86_64 compatible CPUs.') - arch = 'x86SSE2' - if not conf['CYGWIN?']: # cannot use assembly on Cygwin64 - isa_ext = ('SSE2', 'SSE1') - elif conf['Intel?'] and conf['32bit?']: - print('Generic configuration on Intel i386 compatible CPUs.') - arch = 'x86x87' - elif conf['SPARC?']: - print('Base configuration on SPARC.') - arch = 'USIII' - elif conf['PPC?']: - print('Base configuration on PPC.') - arch = 'PPCG4' - elif conf['IA64?']: - print('Base configuration on Itanium.') - arch = 'IA64Itan' - elif conf['ARM?']: - print('Base configuration on ARM.') - arch = 'ARMv6' - else: - raise NotImplementedError('I don\'t know a "base" configuration for your cpu.') - return (arch, isa_ext, thread_limit) - - -###################################################################### -### make function -###################################################################### - -def make_atlas(target=None): - os.chdir(BUILD_DIR) - if target is None: - return system_with_flush(MAKE) - else: - return system_with_flush(MAKE + ' ' + target) - - -def make_atlas_library(target=None): - os.chdir(os.path.join(BUILD_DIR, 'lib')) - cmd = (MAKE + ' ' + target) if target else MAKE - return system_with_flush(cmd) - - -###################################################################### -### make and save archdef function -###################################################################### - -def build_and_save_archdef(): - try: - ARCHDEF_SAVE_DIR = os.environ['SAGE_ATLAS_SAVE_ARCHDEF'] - except KeyError: - return - os.chdir(os.path.join(BUILD_DIR, 'ARCHS')) - rc = system_with_flush(MAKE + ' ArchNew') - assert_success(rc, bad='Making archdef failed.', - good='Finished building archdef.') - rc = system_with_flush(MAKE + ' tarfile') - assert_success(rc, bad='Making archdef tarfile failed.', - good='Finished building archdef tarfile.') - for tarfile in glob.glob('*.tar.bz2'): - cp(tarfile, ARCHDEF_SAVE_DIR) - - -###################################################################### -### static libraries functions -###################################################################### - -def build(arch=None, isa_ext=None): - """ - Configure/build with given architectural information. - - Return ``0`` if successfull. - """ - rc = configure(arch, isa_ext) - if rc: - print("Configure failed.") - return rc - print("Finished configuring ATLAS.") - return make_atlas() - -def build_tuning(): - """ - Configure/build by going through the full tuning process. - - Return ``0`` if successfull. - """ - rc = configure() - if rc!=0: - print('Configure failed, possibly because you have CPU throttling enabled.') - print('Skipping tuning attempts.') - return rc - print('First attempt: automatic tuning.') - rc = make_atlas() - if rc==0: - return rc - print('ATLAS failed to build, possibly because of throttling or a loaded system.') - print('Waiting 1 minute...') - sys.stdout.flush() - time.sleep(60) - print('Second attempt: Re-running make.') - return make_atlas() - - -###################################################################### -### shared library hack functions -###################################################################### - -def configure_shared_library(): - os.chdir(BUILD_LIB_DIR) - static_library_dir = os.path.join(BUILD_DIR, 'lib') - for static_lib in glob.glob(os.path.join(static_library_dir, 'lib*.a')): - shutil.copy(static_lib, BUILD_LIB_DIR) - cmd = './configure' - cmd += ' --prefix=' + conf['SAGE_LOCAL'] - cmd += ' --libdir=' + os.path.join(conf['SAGE_LOCAL'],'lib') - cmd += ' --disable-static' - return system_with_flush(cmd) - -def make_shared_library(target=None): - os.chdir(BUILD_LIB_DIR) - cmd = (MAKE + ' ' + target) if target else MAKE - return system_with_flush(cmd) - - -###################################################################### -### build atlas and lapack static libraries -###################################################################### - -# -# Workaround for specific platforms: Disable tuning and go straight to -# fast/base architectural defaults -# -skip_tuning = conf['IA64?'] # Itanium is dead and tuning is broken - - -rc = None -if 'SAGE_ATLAS_ARCH' in os.environ or conf['generic_binary?']: - print('Building using specific architecture.') - rc = build() -else: - print('Configuring ATLAS.') - if skip_tuning: - print('Skipping tuning attempts (skip_tuning = True).') - rc = 1 # Fake failed tuning attempts - else: - rc = build_tuning() - if rc!=0: - print('Third attempt: use "fast" options.') - rc = build(arch='fast') - if rc!=0: - print('Fourth attempt: use "base" options.') - rc = build(arch='base') - -assert_success(rc, bad='Failed to build ATLAS.', good='Finished building ATLAS core.') - -build_and_save_archdef() - - -###################################################################### -### build ATLAS shared libraries -###################################################################### - -rc = make_atlas_library('shared') -if rc!=0: - print('Failed to build shared library (using the ATLAS build system)') -else: - print('Installed ATLAS shared library (ATLAS build system)') - -rc = make_atlas_library('ptshared') -if rc!=0: - print('Failed to build threaded library (using the ATLAS build system)') -else: - print('Installed ATLAS multi-threaded shared library (ATLAS build system)') - - -###################################################################### -### configure and build atlas and lapack shared library hack -###################################################################### - -rc = configure_shared_library() -assert_success(rc, bad='Configuring shared ATLAS library failed (libtool).', - good='Finished configuring shared ATLAS library (libtool).') - -have_serial_libs = False -have_parallel_libs = False - -rc = make_shared_library() -if rc!=0: - print('Failed to build serial+parallel shared libraries, possibly because your') - print('system does not support both. Trying to build serial libraries only (libtool).') - rc = make_shared_library('all_serial') - if rc!=0: - print('Failed to build any shared library, installing static library as last resort (libtool).') - INSTALL_STATIC_LIBRARIES = True - else: - print('Finished building serial shared ATLAS library (libtool).') - have_serial_libs = True -else: - have_parallel_libs = True - - -###################################################################### -### install shared library hack -###################################################################### - -if have_parallel_libs: - rc = make_shared_library('install') - assert_success(rc, bad='Installing the parallel+serial shared ATLAS library failed (libtool).', - good='Finished installing parallel+serial shared ATLAS library (libtool).') - -if have_serial_libs: - rc = make_shared_library('install_serial') - assert_success(rc, bad='Installing the serial shared ATLAS library failed (libtool).', - good='Finished installing serial shared ATLAS library (libtool).') - - -###################################################################### -### install atlas and lapack headers and libraries -###################################################################### - -if not INSTALL_STATIC_LIBRARIES: - edit_in_place(os.path.join(BUILD_DIR, 'Make.top')) \ - .replace('.*/liblapack.a.*', '') \ - .replace('.*/libcblas.a.*', '') \ - .replace('.*/libf77blas.a.*', '') \ - .replace('.*/libptcblas.a.*', '') \ - .replace('.*/libptf77blas.a.*', '') \ - .replace('.*/libatlas.a.*', '') \ - .close() - -rc = make_atlas('install') -assert_success(rc, bad='Failed to install ATLAS headers', - good='Installed ATLAS headers') - - -###################################################################### -### install script to tune and build ATLAS -###################################################################### - -cp(os.path.join(PATCH_DIR, 'atlas-config'), - os.path.join(conf['SAGE_LOCAL'], 'bin')) diff --git a/build/pkgs/atlas/spkg-src b/build/pkgs/atlas/spkg-src deleted file mode 100755 index 2595f6a1d5a..00000000000 --- a/build/pkgs/atlas/spkg-src +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -ne 0 ]; then - UPSTREAM_SOURCE_DIRECTORY=$1 - echo "Using tarballs from $UPSTREAM_SOURCE_DIRECTORY instead of downloading" -fi - -SPKG_ROOT=`pwd` - -set -e -shopt -s extglob - -# Remove old sources and download new -rm -rf src -mkdir src -cd src - - -### ATLAS ### - -ATLAS=atlas3.10.1.tar.bz2 - -if [ -z "$UPSTREAM_SOURCE_DIRECTORY" ]; then - tar xjf <( curl -L "http://downloads.sourceforge.net/project/math-atlas/Stable/3.10.1/$ATLAS?r=&ts=1373163744&use_mirror=iweb" ) -else - tar xjf "$UPSTREAM_SOURCE_DIRECTORY/$ATLAS" -fi -if [ ! -d ATLAS ]; then - echo 'ATLAS directory not in atlas tarball, aborting' - exit 1 -fi - - -### Lapack ### - -LAPACK=lapack-3.4.2.tgz - -if [ -z "$UPSTREAM_SOURCE_DIRECTORY" ]; then - curl -O http://www.netlib.org/lapack/$LAPACK -else - cp "$UPSTREAM_SOURCE_DIRECTORY/$LAPACK" . -fi -gunzip $LAPACK - -### Our archdefs ### - -if [ -z "$SAGE_ATLAS_ARCHDEFS_DIR" ]; then - echo "SAGE_ATLAS_ARCHDEFS_DIR should point to a directory containing the archedef tarballs." - exit 1 -fi - -mkdir ARCHS -cp -p "$SAGE_ATLAS_ARCHDEFS_DIR"/*.tar.bz2 ARCHS/ - -### Our shared library hack ### - -cp -rp "$SPKG_ROOT"/patches/ATLAS-lib . -cd ATLAS-lib -mkdir m4 -autoreconf -fiv -rm -rf autom4te.cache - - -### Finished creating the src/ directory - -# Make everything writable -cd "$SPKG_ROOT" -chmod -R u+w src diff --git a/build/pkgs/atlas/type b/build/pkgs/atlas/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/atlas/type +++ /dev/null @@ -1 +0,0 @@ -optional diff --git a/build/pkgs/cbc/spkg-configure.m4 b/build/pkgs/cbc/spkg-configure.m4 index 999d4b7497b..56153c3b70b 100644 --- a/build/pkgs/cbc/spkg-configure.m4 +++ b/build/pkgs/cbc/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([cbc], [ - SAGE_SPKG_DEPCHECK([atlas openblas zlib bzip2], [ + SAGE_SPKG_DEPCHECK([openblas zlib bzip2], [ dnl checking with pkg-config PKG_CHECK_MODULES([CBC], [cbc >= 2.9.4], [], [sage_spkg_install_cbc=yes]) ]) diff --git a/build/pkgs/fflas_ffpack/SPKG.rst b/build/pkgs/fflas_ffpack/SPKG.rst index 4c512511265..26c7e6385a1 100644 --- a/build/pkgs/fflas_ffpack/SPKG.rst +++ b/build/pkgs/fflas_ffpack/SPKG.rst @@ -30,7 +30,8 @@ Dependencies ------------ - Givaro -- ATLAS (non-OSX)/The Accelerate FrameWork (on OSX) +- a BLAS implementation such as openblas + Patches ------- diff --git a/build/pkgs/fflas_ffpack/spkg-configure.m4 b/build/pkgs/fflas_ffpack/spkg-configure.m4 index f85295a7767..2d3a46a1a3e 100644 --- a/build/pkgs/fflas_ffpack/spkg-configure.m4 +++ b/build/pkgs/fflas_ffpack/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([fflas_ffpack], [ # fflas-lapack uses whatever multi-precision library givaro uses, # either gmp or mpir. - SAGE_SPKG_DEPCHECK([atlas givaro gmp mpir openblas], [ + SAGE_SPKG_DEPCHECK([givaro gmp mpir openblas], [ # If our dependencies come from the system, then we can use # the system fflas-ffpack, too. Use pkg-config to find a # recentish version, if there is one. diff --git a/build/pkgs/gsl/spkg-configure.m4 b/build/pkgs/gsl/spkg-configure.m4 index 81c5e35e6a9..4581bb688c9 100644 --- a/build/pkgs/gsl/spkg-configure.m4 +++ b/build/pkgs/gsl/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([gsl], [ m4_pushdef([SAGE_GSL_MINVER],["2.4"]) - SAGE_SPKG_DEPCHECK([atlas openblas], [ + SAGE_SPKG_DEPCHECK([openblas], [ PKG_CHECK_MODULES([GSL], [gsl >= $SAGE_GSL_MINVER], [ PKG_CHECK_VAR([GSLPCDIR], [gsl], [pcfiledir], [ GSL_PC="$GSLPCDIR"/gsl.pc diff --git a/build/pkgs/igraph/spkg-configure.m4 b/build/pkgs/igraph/spkg-configure.m4 index a292b33d8a7..c6c180b342e 100644 --- a/build/pkgs/igraph/spkg-configure.m4 +++ b/build/pkgs/igraph/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([igraph], [ -SAGE_SPKG_DEPCHECK([glpk atlas openblas gmp mpir], [ +SAGE_SPKG_DEPCHECK([glpk openblas gmp mpir], [ dnl check for igraph with pkg-config PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.8.3], [], [ sage_spkg_install_igraph=yes]) diff --git a/build/pkgs/iml/SPKG.rst b/build/pkgs/iml/SPKG.rst index 7228ae5d12d..ffb045c9113 100644 --- a/build/pkgs/iml/SPKG.rst +++ b/build/pkgs/iml/SPKG.rst @@ -30,7 +30,7 @@ Dependencies ------------ - GMP -- ATLAS +- a BLAS implementation such as openblas Special Update/Build Instructions diff --git a/build/pkgs/linbox/SPKG.rst b/build/pkgs/linbox/SPKG.rst index 1c2f0d2fbcc..be48c4dc8ca 100644 --- a/build/pkgs/linbox/SPKG.rst +++ b/build/pkgs/linbox/SPKG.rst @@ -40,9 +40,7 @@ Dependencies - M4RIE - Givaro - FFLAS/FFPACK -- ATLAS (non-OSX)/The Accelerate FrameWork (on OSX) -- ATLAS (non-MacOS X) / The Accelerate FrameWork (on MacOS X), or GSL's - CBLAS +- a BLAS implementation such as openblas Special Update/Build Instructions diff --git a/build/pkgs/r/spkg-configure.m4 b/build/pkgs/r/spkg-configure.m4 index e88f3393a91..b6f5e979c52 100644 --- a/build/pkgs/r/spkg-configure.m4 +++ b/build/pkgs/r/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([r], [ m4_pushdef([SAGE_R_MINVER],["3.4.4"]) - SAGE_SPKG_DEPCHECK([atlas openblas iconv readline bzip2 xz pcre curl], [ + SAGE_SPKG_DEPCHECK([openblas iconv readline bzip2 xz pcre curl], [ AS_CASE([$host], [*-*-cygwin*], [ dnl #29486: rpy2 2.8.x does not build against system R on cygwin. diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index 3514da9200c..ca1f8aa6078 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -50,7 +50,6 @@ def list_cls(self, *package_classes, **filters): $ sage --package list | sort 4ti2 arb - atlas autotools [...] zn_poly diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index b8e5f66f9d0..4408b00e9d7 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -66,14 +66,12 @@ $ sage --package list | sort 4ti2 arb - atlas autotools [...] zn_poly $ sage --package list :standard: | sort arb - atlas backports_ssl_match_hostname [...] zn_poly diff --git a/src/doc/en/faq/faq-general.rst b/src/doc/en/faq/faq-general.rst index 53fa60f5c96..ebc04f45144 100644 --- a/src/doc/en/faq/faq-general.rst +++ b/src/doc/en/faq/faq-general.rst @@ -181,8 +181,6 @@ Why did you write Sage from scratch, instead of using other existing software an Sage was not written from scratch. Most of its underlying mathematics functionalities are made possible through FOSS projects such as -* `ATLAS `_ --- Automatically Tuned - Linear Algebra Software. * `BLAS `_ --- Basic Linear Algebra Subprograms. * `ECL `_ --- Embeddable Common-Lisp system diff --git a/src/doc/en/faq/faq-usage.rst b/src/doc/en/faq/faq-usage.rst index 5da1732f538..7b3f38bea2d 100644 --- a/src/doc/en/faq/faq-usage.rst +++ b/src/doc/en/faq/faq-usage.rst @@ -176,28 +176,8 @@ Can I use SageMath with Python 3.x? Since release 9.0 from January 2020, SageMath is running on top of Python 3. - -I downloaded a Sage binary and it crashes on startup with "Illegal instruction". What can I do? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -One way to fix this is to build Sage entirely from source. Another -option is to fix your Sage installation by rebuilding MPIR and ATLAS -by typing the following from the ``SAGE_ROOT`` of your Sage -installation directory and wait about 15 to 20 minutes - -.. CODE-BLOCK:: shell-session - - $ rm spkg/installed/mpir* spkg/installed/atlas* - $ make - -It is possible that the binaries have been built for a newer -architecture than what you have. Nobody has yet figured out how to -build Sage in such a way that MPIR and ATLAS work on all -hardware. This will eventually get fixed. Any help is appreciated. - - I used XXX to install Sage X.Y and that version is giving lots of errors. What can I do? -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" The version of Sage, i.e. Sage version X.Y, that is available on your XXX system through its package manager, is very old. No one has yet diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 0b30005d755..5ccd5fc7a83 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -187,8 +187,7 @@ On Redhat-derived systems not all perl components are installed by default and you might have to install the ``perl-ExtUtils-MakeMaker`` package. -On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required to -provide ATLAS support as the Sage package for ATLAS is not built by default. +On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required. Installing prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1074,7 +1073,7 @@ Here are some of the more commonly used variables affecting the build process: - :envvar:`MAKE` - one useful setting for this variable when building Sage is ``MAKE='make -jNUM'`` to tell the ``make`` program to run ``NUM`` jobs in parallel when building. - Note that not all Sage packages (e.g. ATLAS) support this variable. + Note that some Sage packages may not support this variable. Some people advise using more jobs than there are CPU cores, at least if the system is not heavily loaded and has plenty of RAM; for example, a good @@ -1202,11 +1201,11 @@ Here are some of the more commonly used variables affecting the build process: - :envvar:`SAGE_BUILD_DIR` - the default behavior is to build each spkg in a subdirectory of :file:`$SAGE_ROOT/local/var/tmp/sage/build/`; for - example, build version 3.8.3.p12 of - :file:`atlas` in the directory - :file:`$SAGE_ROOT/local/var/tmp/sage/build/atlas-3.8.3.p12/`. + example, build version 7.27.0 of + :file:`ipython` in the directory + :file:`$SAGE_ROOT/local/var/tmp/sage/build/ipython-7.27.0/`. If this variable is set, then build in - :file:`$SAGE_BUILD_DIR/atlas-3.8.3.p12/` instead. + :file:`$SAGE_BUILD_DIR/ipython-7.27.0/` instead. If the directory :file:`$SAGE_BUILD_DIR` does not exist, it is created. As of this writing (Sage 4.8), when building the standard Sage packages, 1.5 gigabytes of free space are required in this directory (or more if @@ -1288,66 +1287,6 @@ Environment variables dealing with specific Sage packages: ``MPIR`` (default choice), ``GMP``. -- :envvar:`SAGE_ATLAS_ARCH` - if you are compiling ATLAS (in particular, - if :envvar:`SAGE_ATLAS_LIB` is not set), you can use this environment - variable to set a particular architecture and instruction set extension, - to control the maximum number of threads ATLAS can use, and to trigger the - installation of a static library (which is disabled by default unless - building our custom shared libraries fails). - The syntax is - - ``SAGE_ATLAS_ARCH=[threads:n,][static,]arch[,isaext1][,isaext2]...[,isaextN]``. - - While ATLAS comes with precomputed timings for a variety of CPUs, it only - uses them if it finds an exact match. - Otherwise, ATLAS runs through a lengthy automated tuning process in order - to optimize performance for your particular system, which can take several - days on slow and unusual systems. - You drastically reduce the total Sage compile time if you manually select a - suitable architecture. - It is recommended to specify a suitable architecture on laptops or other - systems with CPU throttling or if you want to distribute the binaries. - Available architectures are - - ``POWER3``, ``POWER4``, ``POWER5``, ``PPCG4``, ``PPCG5``, - ``POWER6``, ``POWER7``, ``IBMz9``, ``IBMz10``, ``IBMz196``, - ``x86x87``, ``x86SSE1``, ``x86SSE2``, ``x86SSE3``, ``P5``, - ``P5MMX``, ``PPRO``, ``PII``, ``PIII``, ``PM``, ``CoreSolo``, - ``CoreDuo``, ``Core2Solo``, ``Core2``, ``Corei1``, ``Corei2``, - ``Atom``, ``P4``, ``P4E``, ``Efficeon``, ``K7``, ``HAMMER``, - ``AMD64K10h``, ``AMDDOZER``, ``UNKNOWNx86``, ``IA64Itan``, - ``IA64Itan2``, ``USI``, ``USII``, ``USIII``, ``USIV``, ``UST2``, - ``UnknownUS``, ``MIPSR1xK``, ``MIPSICE9``, ``ARMv7``. - - and instruction set extensions are - - ``VSX``, ``AltiVec``, ``AVXMAC``, ``AVXFMA4``, ``AVX``, ``SSE3``, - ``SSE2``, ``SSE1``, ``3DNow``, ``NEON``. - - In addition, you can also set - - - ``SAGE_ATLAS_ARCH=fast`` which picks defaults for a modern (2-3 year old) - CPU of your processor line, and - - - ``SAGE_ATLAS_ARCH=base`` which picks defaults that should work for a ~10 - year old CPU. - - For example, - - ``SAGE_ATLAS_ARCH=Corei2,AVX,SSE3,SSE2,SSE1`` - - would be appropriate for a Core i7 CPU. - -- :envvar:`SAGE_ATLAS_LIB` - if you have an installation of ATLAS on your - system and you want Sage to use it instead of building and installing its - own version of ATLAS, set this variable to be the directory containing your - ATLAS installation. - It should contain the files :file:`libatlas`, :file:`liblapack`, - :file:`libcblas`, :file:`libf77blas` (and optionally :file:`libptcblas` and - :file:`libptf77blas` for multi-threaded computations), with extensions ``.a``, - ``.so``, or ``.dylib``. For backward compatibility, the libraries may also be - in the subdirectory :file:`SAGE_ATLAS_LIB/lib/`. - - :envvar:`SAGE_MATPLOTLIB_GUI` - if set to anything non-empty except ``no``, then Sage will attempt to build the graphical backend when it builds the matplotlib package. diff --git a/src/doc/it/faq/faq-general.rst b/src/doc/it/faq/faq-general.rst index 298178d1337..5f9234d57c8 100644 --- a/src/doc/it/faq/faq-general.rst +++ b/src/doc/it/faq/faq-general.rst @@ -168,9 +168,6 @@ Perché avete scritto Sage da zero, invece di usare software e librerie preesist Sage non è stato scritto da zero. La maggior parte delle sue funzionalità sono realizzate attraverso progetti FOSS come -* `ATLAS `_ --- libreria software per Algebra - Lineare ottimizzata automaticamente. - * `BLAS `_ --- sottoprogrammi per Algebra Lineare di base. diff --git a/src/doc/it/faq/faq-usage.rst b/src/doc/it/faq/faq-usage.rst index 5267c991c94..51a13b207fb 100644 --- a/src/doc/it/faq/faq-usage.rst +++ b/src/doc/it/faq/faq-usage.rst @@ -156,25 +156,6 @@ Posso usare Sage con la versione 3.x di Python? Dalla versione 9.0 del Gennaio 2020, SageMath utilizza Python 3. -Ho scaricato il binario di Sage e va in crash quando lo lancio, con il messaggio "illegal instruction" (istruzione non permessa). Cosa posso fare? -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -Un modo di risolvere è compilare Sage interamente dal codice sorgente. -Un'altra possibilità è correggere la tua installazione di Sage con la -ricompilazione dei componenti MPIR e ATLAS (richiede da 15 a 20 minuti), -da effettuarsi da riga di comando a partire dalla cartella -``SAGE_ROOT`` della tua installazione con le 2 istruzioni:: - - rm spkg/installed/mpir* spkg/installed/atlas* - make - -È possibile che i binari siano stati compilati per un'architettura più -recente di quella della tua macchina. Nessuno ha ancora trovato un -modo di compilare Sage in maniera che MPIR ed ATLAS funzionino su -qualunque hardware. Questo sarà prima o poi risolto. -Qualunque aiuto in tal senso sarà apprezzato. - - Ho usato Debian/Ubuntu per installare la versione 3.0.5 di Sage ed essa sta dando un sacco di errori. Cosa posso fare? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -461,28 +442,6 @@ riattivare successivamente l'interfaccia grafica, prima di tentare di accedere tramite un'interfaccia testuale. -Sage 2.9 o superiore non riesce a compilare ATLAS su Linux. Come posso risolvere? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -La causa più probabile è l'abilitazione della gestione -dell'alimentazione. Disabilitala per risolvere il problema. -In base al tuo tipo di distribuzione ciò si può fare da interfaccia -grafica oppure no. Digita da riga di comando, come utente root, -quanto segue, per ogni CPU presente sul tuo sistema:: - - /usr/bin/cpufreq-selector -g performance -c #number CPU - -Su Ubuntu, prova a disabilitare “Power Manager” -(gestione alimentazione) via - -.. CODE-BLOCK:: text - - System --> Preferences --> Sessions - -nel menu “Startup Programs” (programmi di avvio) o -utilizzando ``cpufreq-set`` da riga di comando. - - Quando lancio Sage, SELinux segnala che "/path/to/libpari-gmp.so.2" richiede "text-relocation" (riallocazione del testo). Come posso risolvere? """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index f2aca987f51..8168239ff1c 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -422,7 +422,7 @@ cdef class Matrix_double_dense(Matrix_dense): Note that if this matrix is (nearly) singular, finding its inverse will not help much and will give slightly different answers on similar platforms depending on the hardware - and tuning options given to ATLAS:: + and other factors:: sage: A = matrix(RDF,3,range(1,10));A [1.0 2.0 3.0] From 69db83912a25f1cfa4341df59b2a5a45bb27a3cb Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 21 Sep 2021 18:45:22 -0700 Subject: [PATCH 221/355] trac 30350: remove "--with-blas=" option to ./configure --- build/make/Makefile.in | 2 +- build/pkgs/openblas/spkg-configure.m4 | 23 +---------------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index bd8ca2a99da..912f455c566 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -33,7 +33,7 @@ SPKG_INST_RELDIR = var/lib/sage/installed TOOLCHAIN = @SAGE_TOOLCHAIN@ PYTHON = python3 MP_LIBRARY = @SAGE_MP_LIBRARY@ -BLAS = @SAGE_BLAS@ +BLAS = openblas # pkgconfig files generated/installed at build time PCFILES = @SAGE_SYSTEM_FACADE_PC_FILES@ diff --git a/build/pkgs/openblas/spkg-configure.m4 b/build/pkgs/openblas/spkg-configure.m4 index 177bbb1d4ff..c81533ba71a 100644 --- a/build/pkgs/openblas/spkg-configure.m4 +++ b/build/pkgs/openblas/spkg-configure.m4 @@ -110,26 +110,5 @@ SAGE_SPKG_CONFIGURE([openblas], [ LIBS="$SAVE_LIBS" CFLAGS="$SAVE_CFLAGS" ]) - ], [ - dnl REQUIRED-CHECK - AS_IF([test "x$with_blas" = xopenblas], [ - sage_require_openblas=yes - sage_require_atlas=no]) - ], [ - dnl PRE - AC_MSG_CHECKING([BLAS library]) - AC_ARG_WITH([blas], - [AS_HELP_STRING([--with-blas=openblas], - [use OpenBLAS as BLAS library (default)])] - [AS_HELP_STRING([--with-blas=atlas], - [use ATLAS as BLAS library])],, - [with_blas=openblas] # default - ) - AS_CASE(["$with_blas"], - [openblas], [], - [atlas], [sage_spkg_install_openblas=no], - [AC_MSG_ERROR([allowed values for --with-blas are 'atlas' and 'openblas'])]) - AC_MSG_RESULT([$with_blas]) - AC_SUBST([SAGE_BLAS], [$with_blas]) - ] + ] ) From 272424a33ba1a68b221b160ebbbc9c89852aa464 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 21 Sep 2021 19:30:01 -0700 Subject: [PATCH 222/355] trac 30350: remove remaining bits in build/pkgs/atlas/distros --- build/pkgs/atlas/distros/macports.txt | 1 - build/pkgs/atlas/distros/repology.txt | 1 - 2 files changed, 2 deletions(-) delete mode 100644 build/pkgs/atlas/distros/macports.txt delete mode 100644 build/pkgs/atlas/distros/repology.txt diff --git a/build/pkgs/atlas/distros/macports.txt b/build/pkgs/atlas/distros/macports.txt deleted file mode 100644 index ef8830e002d..00000000000 --- a/build/pkgs/atlas/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -atlas diff --git a/build/pkgs/atlas/distros/repology.txt b/build/pkgs/atlas/distros/repology.txt deleted file mode 100644 index fcea775a974..00000000000 --- a/build/pkgs/atlas/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -atlas-linear-algebra From 8355453fb5b2bbb7defc22eefd9a259e2f7d8113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Sep 2021 09:53:07 +0200 Subject: [PATCH 223/355] fixing pylint W0108 in rings, combinat, categories --- .../categories/examples/with_realizations.py | 6 +-- src/sage/combinat/growth.py | 15 ++++--- src/sage/combinat/integer_lists/nn.py | 1 + src/sage/combinat/posets/lattices.py | 6 +-- src/sage/combinat/posets/mobile.py | 2 +- src/sage/combinat/posets/poset_examples.py | 2 +- .../rigged_configuration_element.py | 2 +- .../root_system/extended_affine_weyl_group.py | 40 +++++++++---------- .../combinat/root_system/fundamental_group.py | 2 +- src/sage/combinat/sf/macdonald.py | 15 +++---- src/sage/combinat/sf/sfa.py | 4 +- .../combinat/species/partition_species.py | 10 ++--- .../rings/algebraic_closure_finite_field.py | 9 ++--- src/sage/rings/function_field/maps.py | 2 +- src/sage/rings/number_field/selmer_group.py | 4 +- src/sage/rings/qqbar.py | 2 +- src/sage/rings/valuation/gauss_valuation.py | 5 +-- .../rings/valuation/inductive_valuation.py | 8 ++-- 18 files changed, 65 insertions(+), 70 deletions(-) diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index f3c9e23845a..d322aba065a 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -173,12 +173,12 @@ def __init__(self, R, S): # Initializes the bases and change of bases of ``self`` - F = self.F() - In = self.In() + F = self.F() + In = self.In() Out = self.Out() category = self.Bases() - key = lambda x: self.indices_key(x) + key = self.indices_key In_to_F = In.module_morphism(F.sum_of_monomials * Subsets, codomain=F, category=category, triangular='upper', unitriangular=True, diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index ace55dd1709..c92608b002c 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -1823,8 +1823,7 @@ def P_graph(self, n): return D else: return Poset(([w for k in range(n) for w in self.vertices(k)], - lambda x, y: self.is_P_edge(x, y)), - cover_relations=True) + self.is_P_edge), cover_relations=True) def Q_graph(self, n): r""" @@ -1843,22 +1842,22 @@ def Q_graph(self, n): [[1, 1, 1, 1], [3, 1], [2, 2]] """ if self.has_multiple_edges: - D = DiGraph([(x,y,e) for k in range(n-1) - for x in self.vertices(k) - for y in self.vertices(k+1) - for e in self.is_Q_edge(x, y)], multiedges=True) + D = DiGraph([(x, y, e) for k in range(n - 1) + for x in self.vertices(k) + for y in self.vertices(k + 1) + for e in self.is_Q_edge(x, y)], multiedges=True) # unfortunately, layout_acyclic will not show multiple edges # D.layout_default = D.layout_acyclic return D else: return Poset(([w for k in range(n) for w in self.vertices(k)], - lambda x,y: self.is_Q_edge(x, y)), - cover_relations=True) + self.is_Q_edge), cover_relations=True) ###################################################################### # Specific rules of growth diagrams ###################################################################### + class RuleShiftedShapes(Rule): r""" A class modelling the Schensted correspondence for shifted diff --git a/src/sage/combinat/integer_lists/nn.py b/src/sage/combinat/integer_lists/nn.py index 24f58de9635..4329c6164d9 100644 --- a/src/sage/combinat/integer_lists/nn.py +++ b/src/sage/combinat/integer_lists/nn.py @@ -3,6 +3,7 @@ from sage.rings.semirings.non_negative_integer_semiring import NN from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + def IntegerListsNN(**kwds): """ Lists of nonnegative integers with constraints. diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 024ae3c8644..22cf011fba8 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1993,7 +1993,7 @@ def join(L): elems = [e for e in H.order_ideal([j]) if e not in too_close] achains = PairwiseCompatibleSubsets(elems, - lambda x, y: H.are_incomparable(x, y)) + H.are_incomparable) achains_n = achains.elements_of_depth_iterator(B) for A in achains_n: @@ -3347,7 +3347,7 @@ def sublattices_lattice(self, labels='lattice'): return L.canonical_label() L = L.relabel(lambda x: tuple(self._vertex_to_element(y) for y in x)) if labels == 'lattice': - return L.relabel(lambda x: self.sublattice(x)) + return L.relabel(self.sublattice) return L def isomorphic_sublattices_iterator(self, other): @@ -4934,7 +4934,7 @@ def congruences_lattice(self, labels='congruence'): for e in L: low = L.lower_covers(e) if len(low) == 1: # a join-irreducible element - C[e] = congs[max(e, key=lambda x: cong_ji._element_to_vertex(x))] + C[e] = congs[max(e, key=cong_ji._element_to_vertex)] if len(low) > 1: # "extending" congruence to avoid re-computation low_0 = min(low, key=lambda x: C[x].number_of_subsets()) for new_pair in e: diff --git a/src/sage/combinat/posets/mobile.py b/src/sage/combinat/posets/mobile.py index bf5838a6b5f..a335097fdba 100644 --- a/src/sage/combinat/posets/mobile.py +++ b/src/sage/combinat/posets/mobile.py @@ -140,7 +140,7 @@ def _anchor(self): sage: M._anchor (4, 3) """ - ribbon = list(map(lambda x: self._element_to_vertex(x), self._ribbon)) + ribbon = [self._element_to_vertex(x) for x in self._ribbon] H = self._hasse_diagram R = H.subgraph(ribbon) diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 67d9949db1a..c33c6373623 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -1599,7 +1599,7 @@ def YoungFibonacci(n): current_level = new_level D = DiGraph([[], covers], format='vertices_and_edges') - D.relabel(lambda v: Word(v), inplace=True) + D.relabel(Word, inplace=True) return FiniteMeetSemilattice(hasse_diagram=D, category=FinitePosets()) @staticmethod diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index efbe5b1b368..4a64e2c31f7 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -448,7 +448,7 @@ def _ascii_art_(self): if Partitions.options.convention == "French": baseline = lambda s: 0 else: - baseline = lambda s: len(s) + baseline = len from sage.typeset.ascii_art import AsciiArt s = repr(self[0]).splitlines() ret = AsciiArt(s, baseline=baseline(s)) diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py index 82ee907e1b5..874aa191690 100644 --- a/src/sage/combinat/root_system/extended_affine_weyl_group.py +++ b/src/sage/combinat/root_system/extended_affine_weyl_group.py @@ -585,16 +585,16 @@ def __init__(self, cartan_type, general_linear, **print_options): # coercions between realizations - W0P_to_PW0 = SetMorphism(Hom(W0P, PW0, Groups()),lambda x: PW0(x.to_opposite())) + W0P_to_PW0 = SetMorphism(Hom(W0P, PW0, Groups()), lambda x: PW0(x.to_opposite())) W0P_to_PW0.register_as_coercion() - PW0_to_W0P = SetMorphism(Hom(PW0, W0P, Groups()),lambda x: W0P(x.to_opposite())) + PW0_to_W0P = SetMorphism(Hom(PW0, W0P, Groups()), lambda x: W0P(x.to_opposite())) PW0_to_W0P.register_as_coercion() - FW_to_WF = SetMorphism(Hom(FW, WF, Groups()),lambda x: WF(x.to_opposite())) + FW_to_WF = SetMorphism(Hom(FW, WF, Groups()), lambda x: WF(x.to_opposite())) FW_to_WF.register_as_coercion() - WF_to_FW = SetMorphism(Hom(WF, FW, Groups()),lambda x: FW(x.to_opposite())) + WF_to_FW = SetMorphism(Hom(WF, FW, Groups()), lambda x: FW(x.to_opposite())) WF_to_FW.register_as_coercion() PW0_to_WF = SetMorphism(Hom(PW0, WF, Groups()), self.PW0_to_WF_func) @@ -602,9 +602,9 @@ def __init__(self, cartan_type, general_linear, **print_options): WF_to_PW0 = SetMorphism(Hom(WF, PW0, Groups()), self.WF_to_PW0_func) WF_to_PW0.register_as_coercion() - PvW0_to_W0Pv = SetMorphism(Hom(PvW0, W0Pv, Groups()),lambda x: W0Pv(x.to_opposite())) + PvW0_to_W0Pv = SetMorphism(Hom(PvW0, W0Pv, Groups()), lambda x: W0Pv(x.to_opposite())) PvW0_to_W0Pv.register_as_coercion() - W0Pv_to_PvW0 = SetMorphism(Hom(W0Pv, PvW0, Groups()),lambda x: PvW0(x.to_opposite())) + W0Pv_to_PvW0 = SetMorphism(Hom(W0Pv, PvW0, Groups()), lambda x: PvW0(x.to_opposite())) W0Pv_to_PvW0.register_as_coercion() if self._general_linear: @@ -629,39 +629,39 @@ def __init__(self, cartan_type, general_linear, **print_options): W0Pv_to_W0P.register_as_coercion() # coercions of the translation lattice into the appropriate realizations - P_to_PW0 = SetMorphism(Hom(self.lattice(), PW0, Sets()), lambda x: PW0.from_translation(x)) + P_to_PW0 = SetMorphism(Hom(self.lattice(), PW0, Sets()), PW0.from_translation) P_to_PW0.register_as_coercion() - P_to_W0P = SetMorphism(Hom(self.lattice(), W0P, Sets()), lambda x: W0P.from_translation(x)) + P_to_W0P = SetMorphism(Hom(self.lattice(), W0P, Sets()), W0P.from_translation) P_to_W0P.register_as_coercion() - Pv_to_PvW0 = SetMorphism(Hom(self.dual_lattice(), PvW0, Sets()), lambda x: PvW0.from_dual_translation(x)) + Pv_to_PvW0 = SetMorphism(Hom(self.dual_lattice(), PvW0, Sets()), PvW0.from_dual_translation) Pv_to_PvW0.register_as_coercion() - Pv_to_W0Pv = SetMorphism(Hom(self.dual_lattice(), W0Pv, Sets()), lambda x: W0Pv.from_dual_translation(x)) + Pv_to_W0Pv = SetMorphism(Hom(self.dual_lattice(), W0Pv, Sets()), W0Pv.from_dual_translation) Pv_to_W0Pv.register_as_coercion() # coercions of the classical Weyl group into the appropriate realizations - W0_to_PW0 = SetMorphism(Hom(self.classical_weyl(), PW0, Groups()), lambda x: PW0.from_classical_weyl(x)) + W0_to_PW0 = SetMorphism(Hom(self.classical_weyl(), PW0, Groups()), PW0.from_classical_weyl) W0_to_PW0.register_as_coercion() - W0_to_W0P = SetMorphism(Hom(self.classical_weyl(), W0P, Groups()), lambda x: W0P.from_classical_weyl(x)) + W0_to_W0P = SetMorphism(Hom(self.classical_weyl(), W0P, Groups()), W0P.from_classical_weyl) W0_to_W0P.register_as_coercion() - W0v_to_PvW0 = SetMorphism(Hom(self.dual_classical_weyl(), PvW0, Groups()), lambda x: PvW0.from_dual_classical_weyl(x)) + W0v_to_PvW0 = SetMorphism(Hom(self.dual_classical_weyl(), PvW0, Groups()), PvW0.from_dual_classical_weyl) W0v_to_PvW0.register_as_coercion() - W0v_to_W0Pv = SetMorphism(Hom(self.dual_classical_weyl(), W0Pv, Groups()), lambda x: W0Pv.from_dual_classical_weyl(x)) + W0v_to_W0Pv = SetMorphism(Hom(self.dual_classical_weyl(), W0Pv, Groups()), W0Pv.from_dual_classical_weyl) W0v_to_W0Pv.register_as_coercion() # coercions of the fundamental group into the appropriate realizations - F_to_WF = SetMorphism(Hom(self.fundamental_group(), WF, Groups()), lambda x: WF.from_fundamental(x)) + F_to_WF = SetMorphism(Hom(self.fundamental_group(), WF, Groups()), WF.from_fundamental) F_to_WF.register_as_coercion() - F_to_FW = SetMorphism(Hom(self.fundamental_group(), FW, Groups()), lambda x: FW.from_fundamental(x)) + F_to_FW = SetMorphism(Hom(self.fundamental_group(), FW, Groups()), FW.from_fundamental) F_to_FW.register_as_coercion() # coercions of the affine Weyl group into the appropriate realizations - W_to_WF = SetMorphism(Hom(self.affine_weyl(), WF, Groups()), lambda x: WF.from_affine_weyl(x)) + W_to_WF = SetMorphism(Hom(self.affine_weyl(), WF, Groups()), WF.from_affine_weyl) W_to_WF.register_as_coercion() - W_to_FW = SetMorphism(Hom(self.affine_weyl(), FW, Groups()), lambda x: FW.from_affine_weyl(x)) + W_to_FW = SetMorphism(Hom(self.affine_weyl(), FW, Groups()), FW.from_affine_weyl) W_to_FW.register_as_coercion() def PW0(self): @@ -2041,7 +2041,7 @@ def simple_reflections(self): sage: ExtendedAffineWeylGroup("A3").PW0().simple_reflections() Finite family {0: t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3} """ - return Family(self.realization_of().cartan_type().index_set(), lambda i: self.simple_reflection(i)) + return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) def from_classical_weyl(self, w): r""" @@ -2202,7 +2202,7 @@ def simple_reflections(self): sage: ExtendedAffineWeylGroup(["A",3,1]).W0P().simple_reflections() Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3} """ - return Family(self.realization_of().cartan_type().index_set(), lambda i: self.simple_reflection(i)) + return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) def from_classical_weyl(self, w): r""" diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 7c097ad7fe3..0f378d7e510 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -503,7 +503,7 @@ def group_generators(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1],prefix="f").group_generators() Finite family {0: f[0], 1: f[1], 6: f[6]} """ - return Family(self.special_nodes(), lambda i: self(i)) + return Family(self.special_nodes(), self) def __iter__(self): r""" diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 938b09d23dd..a0929367245 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1167,19 +1167,20 @@ def _to_s(self, part): sage: Sym.schur()( J[2,1] ) (q*t^3-t^4-q*t^2+t^3-q*t+t^2+q-t)*s[1, 1, 1] + (-q*t^4+2*q*t^3-q*t^2+t^2-2*t+1)*s[2, 1] """ - q,t = QQqt.gens() + q, t = QQqt.gens() S = self._macdonald.S() res = S(1) for k in reversed(part): res = res.creation(k) res = res._omega_qt_in_schurs() - res = res.map_coefficients(lambda c: c(t,q)) - f = lambda part2: res.coefficient(part2) + res = res.map_coefficients(lambda c: c(t, q)) + f = res.coefficient return f class Element(MacdonaldPolynomials_generic.Element): pass + class MacdonaldPolynomials_h(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" @@ -1776,14 +1777,14 @@ def _to_s(self, part): sage: S2(Partition([1,1])) (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1) """ - #Convert to the power sum - (q,t) = QQqt.gens() + # Convert to the power sum + (q, t) = QQqt.gens() p = self._sym.p() s = self._s p_x = p(s(part)) - f = lambda m, c: (m, c*prod([(1-t**k)/(1-q**k) for k in m])) + f = lambda m, c: (m, c * prod([(1 - t**k) / (1 - q**k) for k in m])) res = s(p_x.map_item(f)) - f = lambda part2: res.coefficient(part2) + f = res.coefficient return f def _s_cache(self, n): diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 89b1b35abfe..fbfb2ea2d75 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2619,9 +2619,9 @@ def set_print_style(self, ps): if ps == 'lex': self.print_options(sorting_key=lambda x: x) elif ps == 'length': - self.print_options(sorting_key=lambda x: len(x)) + self.print_options(sorting_key=len) elif ps == 'maximal_part': - self.print_options(sorting_key=lambda x: _lmax(x)) + self.print_options(sorting_key=_lmax) else: raise ValueError("the print style must be one of lex, length, or maximal_part ") self._print_style = ps diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index af4ed3cf8fe..7ba6ea84a13 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -183,23 +183,23 @@ def _structures(self, structure_class, labels): yield structure_class(self, labels, []) return - u = [i for i in reversed(range(1, n+1))] + u = [i for i in reversed(range(1, n + 1))] s0 = u.pop() - #Reconstruct the set partitions from - #restricted growth arrays + # Reconstruct the set partitions from + # restricted growth arrays for a in RestrictedGrowthArrays(n): m = a.pop(0) r = [[] for _ in range(m)] i = n - for i,z in enumerate(u): + for i, z in enumerate(u): r[a[i]].append(z) r[0].append(s0) for sp in r: sp.reverse() - r.sort(key=lambda x: len(x), reverse=True) + r.sort(key=len, reverse=True) yield structure_class(self, labels, r) diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index f86aab174b9..a0d5bac9d76 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -865,17 +865,14 @@ def gens(self): sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') - sage: g = F.gens() - sage: g - Lazy family ((i))_{i in Positive integers} + sage: g = F.gens(); g + Lazy family (...(i))_{i in Positive integers} sage: g[3] z3 - """ from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers - - return Family(PositiveIntegers(), lambda n: self.gen(n)) + return Family(PositiveIntegers(), self.gen) def _first_ngens(self, n): """ diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index 702c4768745..998b7909757 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -269,7 +269,7 @@ def __init__(self, L, d): x = self.domain().gen() f = L.polynomial() self._d = d - self._gen_image = - f.map_coefficients(lambda c: d(c))(x) / f.derivative()(x) + self._gen_image = - f.map_coefficients(d)(x) / f.derivative()(x) def _call_(self, x): r""" diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index 0e296497051..77facaaf86a 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -346,11 +346,11 @@ class is a ``p``'th power; k = M.left_kernel() bas = [prod([P ** bj.lift() for P, bj in zip(S, b.list())], C.number_field().ideal(1)) for b in k.basis()] - f = lambda v: k.coordinate_vector(v) - return bas, f + return bas, k.coordinate_vector # The main function + def pSelmerGroup(K, S, p, proof=None, debug=False): r""" Return the ``p``-Selmer group `K(S,p)` of the number field ``K`` diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a63315f93b1..e75d09d58f0 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -7698,7 +7698,7 @@ def simplify(self, n): # for instance, the .exactify() call will try to factor poly, # even though we know that poly is irreducible poly = self.minpoly() - intv = isolating_interval(lambda prec: n._interval_fast(prec), poly) + intv = isolating_interval(n._interval_fast, poly) new_v = QQbar.polynomial_root(poly, intv) new_v.exactify() return new_v._descr diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 3730c21ba22..26e815caa5b 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -391,11 +391,10 @@ def lift(self, F): .. SEEALSO:: :meth:`reduce` - """ F = self.residue_ring().coerce(F) - - return F.map_coefficients(lambda c:self._base_valuation.lift(c), self._base_valuation.domain()) + return F.map_coefficients(self._base_valuation.lift, + self._base_valuation.domain()) def lift_to_key(self, F): """ diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index 5cafb68bfff..ba4364b712b 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -207,9 +207,7 @@ def equivalence_reciprocal(self, f, coefficients=None, valuations=None, check=Tr # - we may lift h to arbitrary precision # - we can add anything which times e0 has positive valuation, e.g., we # may drop coefficients of positive valuation - h = h.map_coefficients(lambda c:_lift_to_maximal_precision(c)) - - return h + return h.map_coefficients(_lift_to_maximal_precision) @cached_method def mu(self): @@ -1384,8 +1382,8 @@ def minimal_representative(self, f): raise ValueError("equivalence units cannot have a minimal representative") e = list(self.coefficients(f))[degree] - h = self.equivalence_reciprocal(e).map_coefficients(lambda c:_lift_to_maximal_precision(c)) - g = h*f + h = self.equivalence_reciprocal(e).map_coefficients(_lift_to_maximal_precision) + g = h * f vg = self(g) coeffs = [c if v == vg else c.parent().zero() for v,c in zip(self.valuations(g), self.coefficients(g))] From 0d483129174c10dbfc641c5ac7f2eebc9f2ffecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Sep 2021 10:27:05 +0200 Subject: [PATCH 224/355] fix more pylint W0108 (useless lambda wrapping) --- src/sage/crypto/mq/sr.py | 2 +- src/sage/databases/findstat.py | 2 +- src/sage/dynamics/finite_dynamical_system_catalog.py | 6 ++++-- src/sage/game_theory/cooperative_game.py | 2 +- src/sage/geometry/cone.py | 2 +- src/sage/graphs/generic_graph.py | 2 +- src/sage/graphs/graph_database.py | 12 ++++++------ src/sage/groups/libgap_morphism.py | 2 +- src/sage/groups/perm_gps/permgroup_named.py | 8 ++++++-- src/sage/interfaces/polymake.py | 6 +++--- src/sage/plot/misc.py | 8 ++++---- 11 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 5a5c10072f8..5e3c6131cea 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1788,7 +1788,7 @@ def ring(self, order=None, reverse_variables=None): reverse_variables = self._reverse_variables if reverse_variables: - process = lambda x: reversed(x) + process = reversed else: process = lambda x: x diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 6ba94aed722..ada9bb53ee0 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4395,7 +4395,7 @@ def name(self, style="singular"): lambda x: x.node_number(), lambda x: isinstance(x, BinaryTree)), "Cores": - _SupportedFindStatCollection(lambda x: (lambda pi, k: Core(pi, k))(*literal_eval(x)), + _SupportedFindStatCollection(lambda x: Core(*literal_eval(x)), lambda X: "( " + X._repr_() + ", " + str(X.k()) + " )", lambda x: Cores(x[1], x[0]), lambda x: (x.length(), x.k()), diff --git a/src/sage/dynamics/finite_dynamical_system_catalog.py b/src/sage/dynamics/finite_dynamical_system_catalog.py index 429b06d73e9..fc925c2d5cf 100755 --- a/src/sage/dynamics/finite_dynamical_system_catalog.py +++ b/src/sage/dynamics/finite_dynamical_system_catalog.py @@ -299,14 +299,16 @@ def order_ideal_rowmotion(P): # Using P.order_ideals_lattice() instead causes intransparency issues: # sage can't always do P.rowmotion(I) when I is in P.order_ideals_lattice(). # Bug in P.order_ideals_lattice() when P is facade? - phi = lambda I : P.rowmotion(I) - def psi(I): # inverse of rowmotion + phi = P.rowmotion + + def psi(I): # inverse of rowmotion result = I for i in P.linear_extension(): result = P.order_ideal_toggle(result, i) return result return InvertibleFiniteDynamicalSystem(X, phi, inverse=psi) + def bulgarian_solitaire(n): r""" Return the finite discrete dynamical system defined diff --git a/src/sage/game_theory/cooperative_game.py b/src/sage/game_theory/cooperative_game.py index 6d2c630cd40..0cb18189191 100644 --- a/src/sage/game_theory/cooperative_game.py +++ b/src/sage/game_theory/cooperative_game.py @@ -320,7 +320,7 @@ def __init__(self, characteristic_function): sortedkey = tuple(sorted(key)) self.ch_f[sortedkey] = self.ch_f.pop(key) - self.player_list = max(characteristic_function, key=lambda key: len(key)) + self.player_list = max(characteristic_function, key=len) for coalition in powerset(self.player_list): if tuple(sorted(coalition)) not in self.ch_f: raise ValueError("characteristic function must be the power set") diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 39a2f902c50..1b9b36e0c98 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -722,7 +722,7 @@ def normalize_rays(rays, lattice): if lattice.is_ambient(): # Handle the most common case efficiently. V = lattice.base_extend(QQ) - length = lambda ray: integral_length(ray) + length = integral_length except AttributeError: pass if V is None: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee9191b90a6..5ed31fd4ae6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -2570,7 +2570,7 @@ def _check_embedding_validity(self, embedding=None, boolean=True): if self._directed: connected = lambda u, v: self.has_edge(u, v) or self.has_edge(v, u) else: - connected = lambda u, v: self.has_edge(u, v) + connected = self.has_edge for v in embedding: if len(embedding[v]) != self.degree(v): if boolean: diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 1e695e6047b..c7c6fe18cca 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -669,18 +669,18 @@ def show(self, max_field_size=20, with_picture=False): relabel[col] = ' '.join([word.capitalize() for word in col.split('_')]) if re.search('SELECT .*degree_sequence.* FROM', self.__query_string__): - format_cols = {'degree_sequence': (lambda x, y: data_to_degseq(x, y))} + format_cols = {'degree_sequence': data_to_degseq} else: format_cols = {} if with_picture: SQLQuery.show(self, max_field_size=max_field_size, - plot_cols={'graph6': (lambda x: graph6_to_plot(x))}, - format_cols=format_cols, id_col='graph6', - relabel_cols=relabel) + plot_cols={'graph6': graph6_to_plot}, + format_cols=format_cols, id_col='graph6', + relabel_cols=relabel) else: SQLQuery.show(self, max_field_size=max_field_size, - format_cols=format_cols, relabel_cols=relabel, - id_col='graph6') + format_cols=format_cols, relabel_cols=relabel, + id_col='graph6') def get_graphs_list(self): """ diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 7e89603ed2b..0dd91115145 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -578,7 +578,7 @@ def section(self): from sage.categories.homset import Hom from sage.categories.sets_cat import Sets H = Hom(self.codomain(), self.domain(), category=Sets()) - return H(lambda x: self.lift(x)) + return H(self.lift) class GroupHomset_libgap(HomsetWithBase): diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 513c7ade76d..f1c8c715889 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1934,7 +1934,9 @@ def __init__(self): Category of facade infinite enumerated sets sage: TestSuite(TransitiveGroups()).run() """ - DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), lambda i: TransitiveGroups(i)) ) + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), + TransitiveGroups)) # We override the __call__ as the elements are not instances of Element __call__ = DisjointUnionEnumeratedSets._element_constructor_facade @@ -2338,7 +2340,9 @@ def __init__(self): sage: S.category() Category of facade infinite enumerated sets """ - DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), lambda i: PrimitiveGroups(i)) ) + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), + PrimitiveGroups)) def _repr_(self): """ diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 8ac83e87ad6..c39ab6fba65 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -1563,7 +1563,7 @@ def _sage_(self): if 'Float' in T1: from sage.rings.all import RDF base_ring = RDF - str_to_base_ring = lambda s: RDF(s) + str_to_base_ring = RDF elif 'QuadraticExtension' in T1 and 'r' in r: i = r.find('r') i1 = min((r[i:]+' ').find(' '), (r[i:]+'\n').find('\n')) @@ -1574,12 +1574,12 @@ def _sage_(self): def str_to_base_ring(s): m = re.match(r'(-?[0-9/]+)[+]?((-?[0-9/]+)r([0-9/]+))?', s) a, b = m.group(1), m.group(3) - return base_ring(a) + base_ring(b)*base_ring.gen() + return base_ring(a) + base_ring(b) * base_ring.gen() elif 'Rational' in T1: from sage.rings.all import QQ base_ring = QQ - str_to_base_ring = lambda s: QQ(s) + str_to_base_ring = QQ else: raise NotImplementedError diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index b170e7c4a3b..b57976552b6 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -192,14 +192,14 @@ def unify_arguments(funcs): vars=set() free_variables=set() if not isinstance(funcs, (list, tuple)): - funcs=[funcs] + funcs = [funcs] for f in funcs: if is_CallableSymbolicExpression(f): - f_args=set(f.arguments()) + f_args = set(f.arguments()) vars.update(f_args) else: - f_args=set() + f_args = set() try: free_vars = set(f.variables()).difference(f_args) @@ -208,7 +208,7 @@ def unify_arguments(funcs): except AttributeError: # we probably have a constant pass - return tuple(sorted(vars, key=lambda x: str(x))), tuple(sorted(free_variables, key=lambda x: str(x))) + return tuple(sorted(vars, key=str)), tuple(sorted(free_variables, key=str)) def _multiple_of_constant(n, pos, const): From 493f0c0a6e431ea6304f0d1a40c675466406f3b8 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 23 Sep 2021 16:21:27 +0200 Subject: [PATCH 225/355] trac #32538: use good_edge = frozenset --- src/sage/graphs/generic_graph.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 1b87de7554c..7efed983287 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6575,8 +6575,7 @@ def weight(x): def good_edge(e): return e else: - def good_edge(e): - return frozenset(e) + good_edge = frozenset # Some vertices belong to part 1, others to part 0 p.add_constraint(v[s], min=0, max=0) @@ -6846,8 +6845,7 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, def good_edge(e): return e else: - def good_edge(e): - return frozenset(e) + good_edge = frozenset # Weight function if use_edge_labels: @@ -6980,8 +6978,7 @@ def weight(x): def good_edge(e): return e else: - def good_edge(e): - return frozenset(e) + good_edge = frozenset from sage.numerical.mip import MixedIntegerLinearProgram From cd6bd11649b1b6e7cb96d424b5abd69a923d92af Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 23 Sep 2021 16:27:07 +0200 Subject: [PATCH 226/355] trac 32537: remove objective_only=value_only --- 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 825df816cfa..ff7638a5dc6 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4201,7 +4201,7 @@ def weight(x): 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(objective_only=value_only, log=verbose) + p.solve(log=verbose) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: if use_edge_labels: @@ -6788,7 +6788,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, for u,v in g.edge_iterator(labels=None): p.add_constraint(b[u] + b[v], min=1) - p.solve(objective_only=value_only, log=verbose) + p.solve(log=verbose) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: size_cover_g = sum(1 for v in g if b[v]) From 43d3121639024c972edb5e11bb4b13f4d8ca3935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 23 Sep 2021 21:20:21 +0200 Subject: [PATCH 227/355] refresh typing of Tamari interval-posets --- src/sage/combinat/interval_posets.py | 50 +++++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 7709195e447..ed2de3bd9ce 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -30,8 +30,8 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from collections.abc import Iterator -from typing import List, Tuple, Union, NewType from sage.categories.enumerated_sets import EnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -60,9 +60,6 @@ from sage.graphs.digraph import DiGraph -TIP = NewType('TIP', 'TamariIntervalPoset') - - class TamariIntervalPoset(Element, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -540,7 +537,7 @@ def draw_decreasing(i, j) -> str: return start + nodes + relations + end - def poset(self): + def poset(self) -> Poset: r""" Return ``self`` as a labelled poset. @@ -598,7 +595,7 @@ def _mul_(self, other: TIP) -> TIP: for i, j in other._poset.cover_relations_iterator()]) P = FinitePoset(DiGraph([list(range(1, n + m + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def __hash__(self): """ @@ -613,7 +610,7 @@ def __hash__(self): return hash(pair) @cached_method - def increasing_cover_relations(self) -> List[Tuple[int, int]]: + def increasing_cover_relations(self) -> list[tuple[int, int]]: r""" Return the cover relations of the initial forest of ``self``. @@ -721,7 +718,7 @@ def increasing_children(self, v) -> list: root = i return children - def increasing_parent(self, v) -> Union[None, int]: + def increasing_parent(self, v) -> None | int: r""" Return the vertex parent of ``v`` in the initial forest of ``self``. @@ -754,7 +751,7 @@ def increasing_parent(self, v) -> Union[None, int]: return parent @cached_method - def decreasing_cover_relations(self) -> List[Tuple[int, int]]: + def decreasing_cover_relations(self) -> list[tuple[int, int]]: r""" Return the cover relations of the final forest of ``self``. @@ -857,7 +854,7 @@ def decreasing_children(self, v) -> list: root = i return children - def decreasing_parent(self, v) -> Union[None, int]: + def decreasing_parent(self, v) -> None | int: r""" Return the vertex parent of ``v`` in the final forest of ``self``. @@ -981,7 +978,7 @@ def size(self) -> Integer: return self._size @cached_method - def cubical_coordinates(self) -> Tuple[int, ...]: + def cubical_coordinates(self) -> tuple[int, ...]: """ Return the cubical coordinates of ``self``. @@ -1061,7 +1058,7 @@ def complement(self) -> TIP: for i, j in self._poset.cover_relations_iterator()] P = FinitePoset(DiGraph([list(range(1, N)), new_covers], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def left_branch_involution(self) -> TIP: """ @@ -1713,7 +1710,7 @@ def initial_forest(self) -> TIP: relations = self.increasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def final_forest(self) -> TIP: r""" @@ -1733,7 +1730,7 @@ def final_forest(self) -> TIP: relations = self.decreasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def is_initial_interval(self) -> bool: r""" @@ -1972,14 +1969,14 @@ class of ``self.lower_binary_tree()`` and is a 312-avoiding self.decreasing_cover_relations()], format='vertices_and_edges') - def add(perm: List, i): + def add(perm: list, i): r""" Internal recursive method to compute the min linear extension. """ for j in sorted(final_forest.neighbors_in(i)): add(perm, j) perm.append(i) - perm = [] + perm: list[int] = [] for i in sorted(final_forest.sinks()): add(perm, i) return Permutation(perm) @@ -2022,14 +2019,14 @@ class of ``self.upper_binary_tree()`` and is a 132-avoiding self.increasing_cover_relations()], format='vertices_and_edges') - def add(perm: List, i): + def add(perm: list, i): r""" Internal recursive method to compute the max linear extension. """ for j in sorted(initial_forest.neighbors_in(i), reverse=True): add(perm, j) perm.append(i) - perm = [] + perm: list[int] = [] for i in sorted(initial_forest.sinks(), reverse=True): add(perm, i) return Permutation(perm) @@ -2289,7 +2286,7 @@ def maximal_chain_dyck_words(self) -> Iterator: for it in self.maximal_chain_tamari_intervals(): yield it.lower_dyck_word() - def tamari_inversions(self) -> List[Tuple[int, int]]: + def tamari_inversions(self) -> list[tuple[int, int]]: r""" Return the Tamari inversions of ``self``. @@ -2440,7 +2437,7 @@ def number_of_new_components(self) -> Integer: t_up = self.upper_binary_tree().to_tilting() return sum(1 for p in t_low if p in t_up) - def new_decomposition(self) -> List[TIP]: + def new_decomposition(self) -> list[TIP]: """ Return the decomposition of the interval-poset into new interval-posets. @@ -2508,7 +2505,7 @@ def extract_tree(x, y, tilt, common): extract_tree(cx, cy, t_up, common)) for cx, cy in common] - def decomposition_to_triple(self) -> Union[None, Tuple[TIP, TIP, int]]: + def decomposition_to_triple(self) -> None | tuple[TIP, TIP, int]: """ Decompose an interval-poset into a triple (``left``, ``right``, ``r``). @@ -2571,7 +2568,9 @@ def grafting_tree(self): n = self.size() if n == 0: return LabelledBinaryTree(None) - left, right, r = self.decomposition_to_triple() + triplet = self.decomposition_to_triple() + assert triplet is not None + left, right, r = triplet return LabelledBinaryTree([left.grafting_tree(), right.grafting_tree()], label=r) @@ -3047,7 +3046,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod def initial_forest(element): @@ -3155,7 +3154,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod def from_binary_trees(tree1, tree2) -> TIP: @@ -3619,6 +3618,9 @@ def __contains__(self, x) -> bool: Element = TamariIntervalPoset +TIP = TamariIntervalPoset + + ################################################################# # Enumerated set of Tamari interval-posets of a given size ################################################################# From 21adace08bca058b6825840c6c5dd0f624da70c3 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Fri, 24 Sep 2021 10:10:20 -0700 Subject: [PATCH 228/355] Fix tox installing miniforge Having CONDA_PREFIX set to a non-existent directory screws up micromamba Adding a workaround until this can be resolved --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 14da3d82db0..78baf729ca3 100644 --- a/tox.ini +++ b/tox.ini @@ -519,7 +519,7 @@ commands = local-conda: bash -c 'echo > {env:CONDA_PREFIX}/.condarc "pkgs_dirs:"' local-conda: bash -c 'echo >> {env:CONDA_PREFIX}/.condarc " - {env:SHARED_CACHE_DIR}/conda_pkgs"' local-conda: bash -c 'cat {env:CONDARC} >> {env:CONDA_PREFIX}/.condarc' - local-conda: bash -c 'if [ ! -x {env:CONDA_PREFIX}/bin/conda ]; then curl -L {env:CONDA_INSTALLER_URL_BASE}{env:CONDA_INSTALLER_FILE} -C - -o {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} && bash {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} -b -f -p {env:CONDA_PREFIX}; fi' + local-conda: bash -c 'if [ ! -x {env:CONDA_PREFIX}/bin/conda ]; then mkdir {env:CONDA_PREFIX}/conda-meta && curl -L {env:CONDA_INSTALLER_URL_BASE}{env:CONDA_INSTALLER_FILE} -C - -o {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} && bash {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} -b -f -p {env:CONDA_PREFIX}; fi' local-conda: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) {env:SETENV} && {env:CONDA_PREFIX}/bin/conda update -n base --yes conda;; esac' local-conda: bash -c 'PACKAGES=$(build/bin/sage-get-system-packages conda $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:EXTRA_SAGE_PACKAGES}); {env:SETENV} && {env:CONDA_PREFIX}/bin/conda install --yes --quiet $PACKAGES' # From 9495d04b2ac72acdb0597a57f25c13f4b61b2d77 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Fri, 24 Sep 2021 22:09:04 -0700 Subject: [PATCH 229/355] fix building python using system python with new setuptools installed --- build/pkgs/python3/spkg-build.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/python3/spkg-build.in b/build/pkgs/python3/spkg-build.in index bcdc5f6898d..dd9e4d553ac 100644 --- a/build/pkgs/python3/spkg-build.in +++ b/build/pkgs/python3/spkg-build.in @@ -2,6 +2,7 @@ # the Python installer. unset PYTHONHOME unset PYTHONPATH +unset SETUPTOOLS_USE_DISTUTILS # Prevent use of the system hg and svn as it might make the installation fail export HAS_HG=no From 8460d20cef7af18f43af007a3dc5b4cd2bd9adb2 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 13:48:55 +0200 Subject: [PATCH 230/355] trac #32559: rewrite HyperStarGraph generator --- src/doc/en/reference/references/index.rst | 6 ++ src/sage/graphs/generators/families.py | 86 +++++++++++------------ 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 3643fe08de6..8bf1b83334f 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3789,6 +3789,12 @@ REFERENCES: Algebra 207 (2006), no 1, pages 1-18. Preprint: :arxiv:`math/0504296v2`. +.. [LKOL2002] Hyeong-Ok Lee, Jong-Seok Kim, Eunseuk Oh and Hyeong-Seok Lim, + *Hyper-Star Graph: A New Interconnection Network Improving the + Network Cost of the Hypercube*, Eurasian Conference on Information + and Communication Technology, LNCS 2510, pp 858-865, 2002. + :doi:`10.1007/3-540-36087-5_99` + .. [LLM2003] \A. Lascoux, L. Lapointe, and J. Morse. *Tableau atoms and a new Macdonald positivity conjecture.* Duke Math Journal, **116 (1)**, 2003. :arxiv:`math/0008073` diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index e3da579d10a..aab6f5e1e5e 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -21,6 +21,7 @@ from copy import copy from math import sin, cos, pi from sage.graphs.graph import Graph +from itertools import combinations def JohnsonGraph(n, k): @@ -199,7 +200,7 @@ def FurerGadget(k, prefix=None): (('Prefix', (1, 2)), ('Prefix', (1, 'a')), None), (('Prefix', (1, 2)), ('Prefix', (2, 'a')), None)] """ - from itertools import repeat as rep, chain, combinations + from itertools import repeat as rep, chain if k <= 0: raise ValueError("The order of the Furer gadget must be greater than zero") G = Graph() @@ -2091,62 +2092,62 @@ def HararyGraph( k, n ): G.name('Harary graph {0}, {1}'.format(k,n)) return G -def HyperStarGraph(n,k): +def HyperStarGraph(n, k): r""" - Returns the hyper-star graph HS(n,k). + Return the hyper-star graph `HS(n, k)`. - The vertices of the hyper-star graph are the set of binary strings - of length n which contain k 1s. Two vertices, u and v, are adjacent - only if u can be obtained from v by swapping the first bit with a - different symbol in another position. + The vertices of the hyper-star graph are the set of binary strings of length + `n` which contain `k` 1s. Two vertices, `u` and `v`, are adjacent only if + `u` can be obtained from `v` by swapping the first bit with a different + symbol in another position. For instance, vertex ``'011100'`` of `HS(6, 3)` + is adjacent to vertices ``'101100'``, ``'110100'`` and ``'111000'``. + See [LKOL2002]_ for more details. INPUT: - - ``n`` + - ``n`` -- non-negative integer; length of the binary strings - - ``k`` + - ``k`` -- non-negative integer; number of 1s per binary string EXAMPLES:: sage: g = graphs.HyperStarGraph(6,3) - sage: g.plot() # long time + sage: sorted(g.neighbors('011100')) + ['101100', '110100', '111000'] + sage: g.plot() # long time Graphics object consisting of 51 graphics primitives - REFERENCES: - - - Lee, Hyeong-Ok, Jong-Seok Kim, Eunseuk Oh, and Hyeong-Seok Lim. - "Hyper-Star Graph: A New Interconnection Network Improving the - Network Cost of the Hypercube." In Proceedings of the First EurAsian - Conference on Information and Communication Technology, 858-865. - Springer-Verlag, 2002. - AUTHORS: - Michael Yurko (2009-09-01) """ - from sage.combinat.combination import Combinations - # dictionary associating the positions of the 1s to the corresponding - # string: e.g. if n=6 and k=3, comb_to_str([0,1,4])=='110010' - comb_to_str={} - for c in Combinations(n,k): - L = ['0']*n - for i in c: - L[i]='1' - comb_to_str[tuple(c)] = ''.join(L) - - g = Graph(name="HS(%d,%d)"%(n,k)) - g.add_vertices(comb_to_str.values()) - - for c in Combinations(list(range(1, n)), k): # 0 is not in c - L = [] - u = comb_to_str[tuple(c)] - # switch 0 with the 1s - for i in range(len(c)): - v = tuple([0]+c[:i]+c[i+1:]) - g.add_edge( u , comb_to_str[v] ) - - return g - + if n < 0 or k < 0 or k > n: + raise ValueError("parameters n and k must be non-negative integers" + "satisfying n >= k >= 0") + if not n: + adj = {} + elif not k: + adj = {'0'*n: []} + elif k == n: + adj = {'1'*n: []} + else: + from sage.data_structures.bitset import Bitset + adj = dict() + # We consider the strings of n bits with k 1s and starting with a 0 + for c in combinations(range(1, n), k): + u = str(Bitset(c, capacity=n)) + L = [] + c = list(c) + # The neighbors of u are all the strings obtained by swapping a 1 + # with the first bit (0) + for i in range(k): + one = c[i] + c[i] = 0 + L.append(str(Bitset(c, capacity=n))) + c[i] = one + adj[u] = L + + return Graph(adj, format='dict_of_lists', name="HS(%d,%d)"%(n,k)) def LCFGraph(n, shift_list, repeats): r""" @@ -3839,7 +3840,6 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from time import time - import itertools assert d > 1, 'd must be at least 2' assert is_even(n * (d-1)), 'n must be even or d must be odd' @@ -3887,7 +3887,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): for C in ParClasses: EC = matrix(QQ, v) for line in C: - for i,j in itertools.combinations(line, 2): + for i,j in combinations(line, 2): EC[i,j] = EC[j,i] = 1/k EC -= ones_v E[tuple(C[0])] = EC From fe3db78686766e7a00751fff00e815392cf60561 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 13:53:54 +0200 Subject: [PATCH 231/355] trac #32559: small details --- src/sage/graphs/generators/families.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index aab6f5e1e5e..fcf07d8829c 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2105,9 +2105,9 @@ def HyperStarGraph(n, k): INPUT: - - ``n`` -- non-negative integer; length of the binary strings + - ``n`` -- non-negative integer; length of the binary strings - - ``k`` -- non-negative integer; number of 1s per binary string + - ``k`` -- non-negative integer; number of 1s per binary string EXAMPLES:: From 9eacbdc5821da99f97ee5aa56a39aae25cdb9b89 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 17:51:24 +0200 Subject: [PATCH 232/355] trac #32561: faster RandomBoundedToleranceGraph --- src/sage/graphs/generators/random.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 9ff451b22da..a9341768dea 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -575,16 +575,14 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): def RandomBoundedToleranceGraph(n): r""" - Returns a random bounded tolerance graph. + Return a random bounded tolerance graph. - The random tolerance graph is built from a random bounded - tolerance representation by using the function - `ToleranceGraph`. This representation is a list - `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where - `k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and - `t_i` a random positive value less then or equal to the length - of the interval `I_i`. The width of the representation is - limited to n**2 * 2**n. + The random tolerance graph is built from a random bounded tolerance + representation by using the function `ToleranceGraph`. This representation + is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = + n-1` and `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random + positive value less then or equal to the length of the interval `I_i`. The + width of the representation is limited to `n^2 * 2^n`. .. NOTE:: @@ -611,13 +609,14 @@ def RandomBoundedToleranceGraph(n): sage: for _ in range(100): _ = graphs.RandomBoundedToleranceGraph(1) """ from sage.misc.prandom import randint - from sage.combinat.combination import Combinations from sage.graphs.generators.intersection import ToleranceGraph W = n ** 2 * 2 ** n - C = Combinations(W + 1, 2) - - tolrep = [(l_r[0], l_r[1], randint(1, l_r[1] - l_r[0])) for l_r in [C.random_element() for i in range(n)]] + tolrep = [] + for _ in range(n): + l = randint(0, W - 1) + r = randint(l + 1, W) + tolrep.append((l, r, randint(1, r - l))) return ToleranceGraph(tolrep) From 4b050d6d8abe3049881a5580e4dae617b68e2dc6 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 17:59:21 +0200 Subject: [PATCH 233/355] trac #32561: randint is imported at module level --- src/sage/graphs/generators/random.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index a9341768dea..f0ddc409061 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -608,7 +608,6 @@ def RandomBoundedToleranceGraph(n): sage: for _ in range(100): _ = graphs.RandomBoundedToleranceGraph(1) """ - from sage.misc.prandom import randint from sage.graphs.generators.intersection import ToleranceGraph W = n ** 2 * 2 ** n @@ -1331,7 +1330,6 @@ def RandomTree(n): sage: graphs.RandomTree(1) Graph on 1 vertex """ - from sage.misc.prandom import randint g = Graph(n) if n <= 1: return g @@ -1523,7 +1521,6 @@ def RandomToleranceGraph(n): ... ValueError: The number `n` of vertices must be >= 0. """ - from sage.misc.prandom import randint from sage.graphs.generators.intersection import ToleranceGraph if n<0: From 04e0547947d1ac23f42a4790b7e36716faf0b2ff Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 18:05:05 +0200 Subject: [PATCH 234/355] trac #32561: also modifies RandomToleranceGraph --- src/sage/graphs/generators/random.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index f0ddc409061..1db51288d32 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -607,7 +607,17 @@ def RandomBoundedToleranceGraph(n): Check that :trac:`32186` is fixed:: sage: for _ in range(100): _ = graphs.RandomBoundedToleranceGraph(1) + + Check input parameter:: + + sage: g = graphs.RandomToleranceGraph(-2) + Traceback (most recent call last): + ... + ValueError: the number `n` of vertices must be >= 0 """ + if n < 0: + raise ValueError('the number `n` of vertices must be >= 0') + from sage.graphs.generators.intersection import ToleranceGraph W = n ** 2 * 2 ** n @@ -1487,13 +1497,13 @@ def RandomShell(constructor, seed=None): def RandomToleranceGraph(n): r""" - Returns a random tolerance graph. + Return a random tolerance graph. The random tolerance graph is built from a random tolerance representation by using the function `ToleranceGraph`. This representation is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random positive - value. The width of the representation is limited to n**2 * 2**n. + value. The width of the representation is limited to `n^2 * 2^n`. .. NOTE:: @@ -1519,16 +1529,22 @@ def RandomToleranceGraph(n): sage: g = graphs.RandomToleranceGraph(-2) Traceback (most recent call last): ... - ValueError: The number `n` of vertices must be >= 0. + ValueError: the number `n` of vertices must be >= 0 """ from sage.graphs.generators.intersection import ToleranceGraph - if n<0: - raise ValueError('The number `n` of vertices must be >= 0.') + if n < 0: + raise ValueError('the number `n` of vertices must be >= 0') W = n**2 * 2**n - tolrep = [tuple(sorted((randint(0,W), randint(0,W)))) + (randint(0,W),) for i in range(n)] + tolrep = [] + for _ in range(n): + l = randint(0, W) + r = randint(0, W) + if l > r: + l, r = r, l + tolrep.append((l, r, randint(0, W))) return ToleranceGraph(tolrep) From a5c2119ba54682ff7f775c378bfc2eebb5ae5b12 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Sep 2021 19:37:07 +0200 Subject: [PATCH 235/355] trac #32562: more use of _circle_embedding --- src/sage/graphs/generators/smallgraphs.py | 143 ++++++---------------- 1 file changed, 40 insertions(+), 103 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 77489cfaacb..9051a8b7c88 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -1788,19 +1788,11 @@ def ChvatalGraph(): """ edges = {0:[1, 4, 6, 9], 1:[2, 5, 7], 2:[3, 6, 8], 3:[4, 7, 9], 4:[5, 8], 5:[10, 11], 6:[10, 11], 7:[8, 11], 8:[10], 9:[10, 11]} - pos_dict = {} - for i in range(5, 10): - x = float(cos((pi / 2) + ((2 * pi) / 5) * i)) - y = float(sin((pi / 2) + ((2 * pi) / 5) * i)) - pos_dict[i] = (x, y) - for i in range(5): - x = float(2 * (cos((pi / 2) + ((2 * pi) / 5) * (i - 5)))) - y = float(2 * (sin((pi / 2) + ((2 * pi) / 5) * (i - 5)))) - pos_dict[i] = (x, y) - pos_dict[10] = (0.5, 0) - pos_dict[11] = (-0.5, 0) - - return Graph(edges, pos=pos_dict, name="Chvatal graph") + g = Graph(edges, format='dict_of_lists', name="Chvatal graph") + g._circle_embedding(range(5), radius=4, angle=pi/2) + g._circle_embedding(range(5, 10), radius=2, angle=pi/2) + g._circle_embedding(range(10, 12), radius=1) + return g def ClebschGraph(): r""" @@ -2411,19 +2403,13 @@ def FlowerSnark(): sage: F.show() # long time """ - pos_dict = {} - for i in range(15): - x = float(2.5*(cos((pi/2) + ((2*pi)/15)*i))) - y = float(2.5*(sin((pi/2) + ((2*pi)/15)*i))) - pos_dict[i] = (x,y) - for i in range(15,20): - x = float(cos((pi/2) + ((2*pi)/5)*i)) - y = float(sin((pi/2) + ((2*pi)/5)*i)) - pos_dict[i] = (x,y) d = {0: [1, 14, 15], 1: [2, 11], 2: [3, 7], 3: [2, 4, 16], 4: [5, 14], 5: [6, 10], 6: [5, 7, 17], 8: [7, 9, 13], 9: [10, 18], 11: [10, 12], 12: [13, 19], 13: [14], 15: [19], 16: [15, 17], 18: [17, 19]} - return Graph(d, format="dict_of_lists", pos=pos_dict, name="Flower Snark") + g = Graph(d, format="dict_of_lists", name="Flower Snark") + g._circle_embedding(range(15), radius=2.5, angle=pi/2) + g._circle_embedding(range(15, 20), radius=1, angle=pi/2) + return g def FolkmanGraph(): """ @@ -2541,20 +2527,10 @@ def FranklinGraph(): 7: [10], 8: [9,11], 10: [11]} - pos_dict = { - 0: [2, 0], - 1: [1, 1.73205080756888], - 2: [-1, 1.73205080756888], - 3: [-2, 0], - 4: [-1, -1.73205080756888], - 5: [1, -1.73205080756888], - 6: [1, 0], - 7: [0.5, 0.866025403784439], - 8: [-0.5, 0.866025403784439], - 9: [-1, 0], - 10: [-0.5, -0.866025403784439], - 11: [0.5, -0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Franklin graph") + g = Graph(edge_dict, format='dict_of_lists', name="Franklin graph") + g._circle_embedding(range(6), radius=2) + g._circle_embedding(range(6, 12), radius=1) + return g def FruchtGraph(): """ @@ -2586,17 +2562,11 @@ def FruchtGraph(): """ edges = {0:[1, 6, 7], 1:[2, 7], 2:[3, 8], 3:[4, 9], 4:[5, 9], 5:[6, 10], 6:[10], 7:[11], 8:[9, 11], 10:[11]} - pos_dict = {} - for i in range(7): - x = float(2*(cos((pi/2) + ((2*pi)/7)*i))) - y = float(2*(sin((pi/2) + ((2*pi)/7)*i))) - pos_dict[i] = (x,y) - pos_dict[7] = (0,1) - pos_dict[8] = (-1,0) - pos_dict[9] = (0,-1) - pos_dict[10] = (1,0) - pos_dict[11] = (0,0) - return Graph(edges, pos=pos_dict, name="Frucht graph") + g = Graph(edges, format='dict_of_lists', name="Frucht graph") + g._circle_embedding(range(7), radius=2, angle=pi/2) + g._circle_embedding(range(7, 11), radius=1, angle=pi/2) + g._pos[11] = (0, 0) + return g def GoldnerHararyGraph(): r""" @@ -2808,14 +2778,12 @@ def GrotzschGraph(): for u in range(7, 11): edges.append((u, u - 6)) - pos = {} - pos[0] = (0,0) - for u in range(1, 6): - theta = (u - 1) * 2 * pi / 5 - pos[u] = (float(5 * sin(theta)), float(5 * cos(theta))) - pos[u + 5] = (2 * pos[u][0], 2 * pos[u][1]) + g = Graph(edges, format='list_of_edges', name="Grotzsch graph") + g._circle_embedding(range(1, 6), radius=1, angle=pi/2) + g._circle_embedding(range(6, 11), radius=2, angle=pi/2) + g._pos[0] = (0, 0) - return Graph(edges, format='list_of_edges', pos=pos, name="Grotzsch graph") + return g def HeawoodGraph(): """ @@ -2850,12 +2818,9 @@ def HeawoodGraph(): """ edges = {0:[1, 5, 13], 1:[2, 10], 2:[3, 7], 3:[4, 12], 4:[5, 9], 5:[6], 6:[7, 11], 7:[8], 8:[9, 13], 9:[10], 10:[11], 11:[12], 12:[13]} - pos_dict = {} - for i in range(14): - x = float(cos((pi/2) + (pi/7)*i)) - y = float(sin((pi/2) + (pi/7)*i)) - pos_dict[i] = (x,y) - return Graph(edges, pos=pos_dict, name="Heawood graph") + g = Graph(edges, format='dict_of_lists', name="Heawood graph") + g._circle_embedding(range(14), radius=1, angle=pi/2) + return g def HerschelGraph(): r""" @@ -2911,19 +2876,11 @@ def HerschelGraph(): 7: [8], 8: [10], 9: [10]} - pos_dict = { - 0: [2, 0], - 1: [0, 2], - 2: [-2, 0], - 3: [0, -2], - 4: [1, 0], - 5: [0.5, 0.866025403784439], - 6: [-0.5, 0.866025403784439], - 7: [-1, 0], - 8: [-0.5, -0.866025403784439], - 9: [0.5, -0.866025403784439], - 10: [0, 0]} - return Graph(edge_dict, pos=pos_dict, name="Herschel graph") + g = Graph(edge_dict, format='dict_of_lists', name="Herschel graph") + g._circle_embedding(range(4), radius=2) + g._circle_embedding(range(4, 10), radius=1) + g._pos[10] = (0, 0) + return g def GritsenkoGraph(): r""" @@ -3083,21 +3040,10 @@ def HigmanSimsGraph(relabel=True): c = (m*(m-a) + b - 2) % 5 HS.add_edge(('1%d%d'%(m, c), '3%d%d'%(a, b))) - # Rename to integer vertex labels, creating dictionary - # Or not, and create identity mapping + # Layout vertices in a circle, in the order given in vlist + HS._circle_embedding(vlist, radius=10, angle=pi/2) if relabel: - vmap = HS.relabel(range(100), return_map=True) - else: - vmap = {v: v for v in vlist} - # Layout vertices in a circle - # In the order given in vlist - # Using labels from vmap - pos_dict = {} - for i in range(100): - x = float(cos((pi/2) + ((2*pi)/100)*i)) - y = float(sin((pi/2) + ((2*pi)/100)*i)) - pos_dict[vmap[vlist[i]]] = (x, y) - HS.set_pos(pos_dict) + HS.relabel(range(100)) return HS def HoffmanSingletonGraph(): @@ -3180,12 +3126,7 @@ def HoffmanSingletonGraph(): s = int(v[0]) l += 1 map = H.relabel(range(50), return_map=True) - pos_dict = {} - for i in range(50): - x = float(cos((pi/2) + ((2*pi)/50)*i)) - y = float(sin((pi/2) + ((2*pi)/50)*i)) - pos_dict[map[D[i]]] = (x, y) - H.set_pos(pos_dict) + H._circle_embedding([map[d] for d in D], angle=pi/2) return H def HoffmanGraph(): @@ -3862,18 +3803,14 @@ def PappusGraph(): sage: G.is_isomorphic(L) True """ - pos_dict = {} - for i in range(6): - pos_dict[i] = [float(cos(pi/2 + ((2*pi)/6)*i)), - float(sin(pi/2 + ((2*pi)/6)*i))] - pos_dict[6 + i] = [(2/3.0)*float(cos(pi/2 + ((2*pi)/6)*i)), - (2/3.0)*float(sin(pi/2 + ((2*pi)/6)*i))] - pos_dict[12 + i] = [(1/3.0)*float(cos(pi/2 + ((2*pi)/6)*i)), - (1/3.0)*float(sin(pi/2 + ((2*pi)/6)*i))] edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], 6: [13, 17], 7: [12, 14], 8: [13, 15], 9: [14, 16], 10: [15, 17], 11: [12, 16], 12: [15], 13: [16], 14: [17]} - return Graph(edges, pos=pos_dict, name="Pappus Graph") + g = Graph(edges, format='dict_of_lists', name="Pappus Graph") + g._circle_embedding(range(6), radius=3, angle=pi/2) + g._circle_embedding(range(6, 12), radius=2, angle=pi/2) + g._circle_embedding(range(12, 18), radius=1, angle=pi/2) + return g def PoussinGraph(): r""" From b41384a03ddd87b759c056b911d2eb0bf05afb75 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 11:36:57 -0700 Subject: [PATCH 236/355] src/sage/calculus/test_sympy.py, src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py: Make doctests pass with sympy 1.9 and <1.9 --- src/sage/calculus/test_sympy.py | 4 ++-- .../recequadiff_doctest.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 86f93667040..5383f589eef 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -193,7 +193,7 @@ sage: u = Function('u') sage: n = Symbol('n', integer=True) sage: f = u(n+2) - u(n+1) + u(n)/4 - sage: rsolve(f,u(n)) - 2**(-n)*(C0 + C1*n) + sage: 2**n * rsolve(f,u(n)) + C1*n + C0 """ diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index 97ac97b81d8..1062f4f7e8c 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -374,8 +374,8 @@ Sage example in ./recequadiff.tex, line 1707:: sage: from sympy import rsolve - sage: rsolve(f, u(n), {u(0):-1,u(1):1}) - 3 - 4*2**(-n) + sage: rsolve(f, u(n), {u(0):-1,u(1):1}) == 3 - 4*2**(-n) + True Sage example in ./recequadiff.tex, line 1798:: From 28797f945da0af77844d847505ce717587cfca29 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 12:07:32 -0700 Subject: [PATCH 237/355] src/sage/calculus/calculus.py: Prepare laplace(dirac_delta) doctest for sympy 1.9 --- src/sage/calculus/calculus.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 4de7210e6ad..07e71fa3b42 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1629,8 +1629,11 @@ def laplace(ex, t, s, algorithm='maxima'): sage: laplace(dirac_delta(t), t, s) 1 - sage: laplace(dirac_delta(t), t, s, algorithm='sympy') - (-heaviside(0) + 1, -oo, True) + sage: F, a, cond = laplace(dirac_delta(t), t, s, algorithm='sympy') + sage: a, cond + (-oo, True) + sage: F # random - sympy <1.9 includes undefined heaviside(0) in answer + 1 sage: laplace(dirac_delta(t), t, s, algorithm='giac') 1 From 20e60f26d38ced0005472e45661b968a8ab53c91 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 14:02:10 -0700 Subject: [PATCH 238/355] sage.features.Executable: Remove use of distutils --- src/sage/features/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 42058cf07dc..3ce6acd432e 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -52,8 +52,8 @@ """ import os +import shutil from distutils.errors import CCompilerError -from distutils.spawn import find_executable from sage.env import SAGE_SHARE from sage.misc.lazy_string import lazy_string @@ -571,6 +571,8 @@ class Executable(Feature): sage: from sage.features import Executable sage: Executable(name="sh", executable="sh").is_present() FeatureTestResult('sh', True) + sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").is_present() + FeatureTestResult('does-not-exist', False) """ def __init__(self, name, executable, **kwds): r""" @@ -595,7 +597,7 @@ def _is_present(self): sage: Executable(name="sh", executable="sh").is_present() FeatureTestResult('sh', True) """ - if find_executable(self.executable) is None: + if shutil.which(self.executable) is None: return FeatureTestResult(self, False, "Executable {executable!r} not found on PATH.".format(executable=self.executable)) return self.is_functional() From 8c763f4505701d48ee512f5a2e53e29096eeecce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 14:03:34 -0700 Subject: [PATCH 239/355] sage.features.CCompilerError: Move global import from distutils.errors into method --- src/sage/features/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 3ce6acd432e..839bde0d8d4 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -53,7 +53,6 @@ import os import shutil -from distutils.errors import CCompilerError from sage.env import SAGE_SHARE from sage.misc.lazy_string import lazy_string @@ -770,6 +769,7 @@ def _is_present(self): FeatureTestResult('empty', True) """ from sage.misc.temporary_file import tmp_filename + from distutils.errors import CCompilerError with open(tmp_filename(ext=".pyx"), 'w') as pyx: pyx.write(self.test_code) from sage.misc.cython import cython_import From c7ec7428931e30c20d09f885a35e5ca1266dab94 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 13 Sep 2021 12:54:14 -0700 Subject: [PATCH 240/355] src/sage/__init__.py: Move load_ipython_extension to src/sage/repl/__init__.py, monkey-patch it into sage from there --- src/sage/__init__.py | 5 ----- src/sage/repl/__init__.py | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sage/__init__.py b/src/sage/__init__.py index 49098fa7e08..6ea8b846de3 100644 --- a/src/sage/__init__.py +++ b/src/sage/__init__.py @@ -3,11 +3,6 @@ # See https://trac.sagemath.org/ticket/29705 -# IPython calls this when starting up -def load_ipython_extension(*args): - import sage.repl.ipython_extension - sage.repl.ipython_extension.load_ipython_extension(*args) - # Deprecated leftover of monkey-patching inspect.isfunction() to support Cython functions. # We cannot use lazy_import for the deprecation here. diff --git a/src/sage/repl/__init__.py b/src/sage/repl/__init__.py index e69de29bb2d..8590d1616f0 100644 --- a/src/sage/repl/__init__.py +++ b/src/sage/repl/__init__.py @@ -0,0 +1,14 @@ +# IPython calls this when "%load_ext sage.repl" is used. +# The Sage application loads it when starting up. +def load_ipython_extension(*args): + import sage.repl.ipython_extension + sage.repl.ipython_extension.load_ipython_extension(*args) + + +# The above used to be in sage.__init__, allowing users to use "%load_ext sage". +# But we removed the __init__.py file in order to make sage a native namespace package. +# +# So we make "%load_ext sage" work by monkey-patching the function +# into the sage package upon importing sage.repl. +import sage +sage.load_ipython_extension = load_ipython_extension From 2b4b142fbcdad6cc53313d84fdc88e49a6168de2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 16:45:34 -0700 Subject: [PATCH 241/355] build/pkgs: Split out spkg liblzma from xz --- build/pkgs/liblzma/SPKG.rst | 23 +++++++++++++++++++++++ build/pkgs/liblzma/dependencies | 9 +++++++++ build/pkgs/liblzma/distros/conda.txt | 1 + build/pkgs/liblzma/distros/cygwin.txt | 2 ++ build/pkgs/liblzma/distros/debian.txt | 3 +++ build/pkgs/liblzma/distros/fedora.txt | 1 + build/pkgs/liblzma/distros/homebrew.txt | 1 + build/pkgs/liblzma/distros/macports.txt | 1 + build/pkgs/liblzma/distros/opensuse.txt | 2 ++ build/pkgs/liblzma/distros/repology.txt | 1 + build/pkgs/liblzma/distros/slackware.txt | 1 + build/pkgs/liblzma/distros/void.txt | 2 ++ build/pkgs/liblzma/spkg-configure.m4 | 10 ++++++++++ build/pkgs/liblzma/spkg-install | 3 +++ build/pkgs/liblzma/type | 1 + build/pkgs/xz/distros/cygwin.txt | 2 +- build/pkgs/xz/distros/debian.txt | 1 - build/pkgs/xz/distros/fedora.txt | 2 +- build/pkgs/xz/distros/opensuse.txt | 1 - build/pkgs/xz/distros/void.txt | 1 - build/pkgs/xz/spkg-configure.m4 | 6 ------ 21 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 build/pkgs/liblzma/SPKG.rst create mode 100644 build/pkgs/liblzma/dependencies create mode 100644 build/pkgs/liblzma/distros/conda.txt create mode 100644 build/pkgs/liblzma/distros/cygwin.txt create mode 100644 build/pkgs/liblzma/distros/debian.txt create mode 100644 build/pkgs/liblzma/distros/fedora.txt create mode 100644 build/pkgs/liblzma/distros/homebrew.txt create mode 100644 build/pkgs/liblzma/distros/macports.txt create mode 100644 build/pkgs/liblzma/distros/opensuse.txt create mode 100644 build/pkgs/liblzma/distros/repology.txt create mode 100644 build/pkgs/liblzma/distros/slackware.txt create mode 100644 build/pkgs/liblzma/distros/void.txt create mode 100644 build/pkgs/liblzma/spkg-configure.m4 create mode 100755 build/pkgs/liblzma/spkg-install create mode 100644 build/pkgs/liblzma/type diff --git a/build/pkgs/liblzma/SPKG.rst b/build/pkgs/liblzma/SPKG.rst new file mode 100644 index 00000000000..925da031898 --- /dev/null +++ b/build/pkgs/liblzma/SPKG.rst @@ -0,0 +1,23 @@ +liblzma: General-purpose data compression software +================================================== + +Description +----------- + +This packages represents liblzma, a part of XZ Utils, the free general-purpose +data compression software with a high compression ratio. + +License +------- + +Some parts public domain, other parts GNU LGPLv2.1, GNU GPLv2, or GNU +GPLv3. + + +Upstream Contact +---------------- + +http://tukaani.org/xz/ + +Dependencies +------------ diff --git a/build/pkgs/liblzma/dependencies b/build/pkgs/liblzma/dependencies new file mode 100644 index 00000000000..43f7abfd1e2 --- /dev/null +++ b/build/pkgs/liblzma/dependencies @@ -0,0 +1,9 @@ +$(INST)/xz-$(vers_xz) + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. + +Adding the above instead of "xz" makes sure that the dependency is not replaced +by ".dummy". In this way, liblzma delegates building to xz when +liblzma appears as a dependency. diff --git a/build/pkgs/liblzma/distros/conda.txt b/build/pkgs/liblzma/distros/conda.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/conda.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/cygwin.txt b/build/pkgs/liblzma/distros/cygwin.txt new file mode 100644 index 00000000000..c5fa156f8a0 --- /dev/null +++ b/build/pkgs/liblzma/distros/cygwin.txt @@ -0,0 +1,2 @@ +xz +liblzma-devel diff --git a/build/pkgs/liblzma/distros/debian.txt b/build/pkgs/liblzma/distros/debian.txt new file mode 100644 index 00000000000..5cc8e2ad176 --- /dev/null +++ b/build/pkgs/liblzma/distros/debian.txt @@ -0,0 +1,3 @@ +xz-utils +liblzma-dev +# pixz # provides pixz but not xz on debian buster diff --git a/build/pkgs/liblzma/distros/fedora.txt b/build/pkgs/liblzma/distros/fedora.txt new file mode 100644 index 00000000000..813a264efd5 --- /dev/null +++ b/build/pkgs/liblzma/distros/fedora.txt @@ -0,0 +1 @@ +xz xz-devel diff --git a/build/pkgs/liblzma/distros/homebrew.txt b/build/pkgs/liblzma/distros/homebrew.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/homebrew.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/macports.txt b/build/pkgs/liblzma/distros/macports.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/macports.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/opensuse.txt b/build/pkgs/liblzma/distros/opensuse.txt new file mode 100644 index 00000000000..f84d903df3e --- /dev/null +++ b/build/pkgs/liblzma/distros/opensuse.txt @@ -0,0 +1,2 @@ +xz +"pkgconfig(liblzma)" diff --git a/build/pkgs/liblzma/distros/repology.txt b/build/pkgs/liblzma/distros/repology.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/repology.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/slackware.txt b/build/pkgs/liblzma/distros/slackware.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/slackware.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/void.txt b/build/pkgs/liblzma/distros/void.txt new file mode 100644 index 00000000000..c5fa156f8a0 --- /dev/null +++ b/build/pkgs/liblzma/distros/void.txt @@ -0,0 +1,2 @@ +xz +liblzma-devel diff --git a/build/pkgs/liblzma/spkg-configure.m4 b/build/pkgs/liblzma/spkg-configure.m4 new file mode 100644 index 00000000000..52caa060f0a --- /dev/null +++ b/build/pkgs/liblzma/spkg-configure.m4 @@ -0,0 +1,10 @@ +SAGE_SPKG_CONFIGURE([liblzma], [ + SAGE_SPKG_DEPCHECK([xz], [ + dnl The library is actually installed by the xz spkg. + AC_CHECK_LIB([lzma], [lzma_raw_decoder], [lzma_cv_liblzma=yes], [lzma_cv_liblzma=no]) + AC_CHECK_HEADER([lzma.h], [lzma_cv_lzma_h=yes], [lzma_cv_lzma_h=no]) + if test "$lzma_cv_liblzma" != "yes" -o "$lzma_cv_lzma_h" != "yes"; then + sage_spkg_install_liblzma=yes + fi + ]) +]) diff --git a/build/pkgs/liblzma/spkg-install b/build/pkgs/liblzma/spkg-install new file mode 100755 index 00000000000..3104094580f --- /dev/null +++ b/build/pkgs/liblzma/spkg-install @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +# Actual installation is done by the xz spkg +# via a tricky dependency in liblzma/dependencies. diff --git a/build/pkgs/liblzma/type b/build/pkgs/liblzma/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/liblzma/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/xz/distros/cygwin.txt b/build/pkgs/xz/distros/cygwin.txt index 0267fff5270..d66e95ca507 100644 --- a/build/pkgs/xz/distros/cygwin.txt +++ b/build/pkgs/xz/distros/cygwin.txt @@ -1 +1 @@ -xz liblzma-devel +xz diff --git a/build/pkgs/xz/distros/debian.txt b/build/pkgs/xz/distros/debian.txt index 5cc8e2ad176..4b3b46661f7 100644 --- a/build/pkgs/xz/distros/debian.txt +++ b/build/pkgs/xz/distros/debian.txt @@ -1,3 +1,2 @@ xz-utils -liblzma-dev # pixz # provides pixz but not xz on debian buster diff --git a/build/pkgs/xz/distros/fedora.txt b/build/pkgs/xz/distros/fedora.txt index 813a264efd5..d66e95ca507 100644 --- a/build/pkgs/xz/distros/fedora.txt +++ b/build/pkgs/xz/distros/fedora.txt @@ -1 +1 @@ -xz xz-devel +xz diff --git a/build/pkgs/xz/distros/opensuse.txt b/build/pkgs/xz/distros/opensuse.txt index f84d903df3e..d66e95ca507 100644 --- a/build/pkgs/xz/distros/opensuse.txt +++ b/build/pkgs/xz/distros/opensuse.txt @@ -1,2 +1 @@ xz -"pkgconfig(liblzma)" diff --git a/build/pkgs/xz/distros/void.txt b/build/pkgs/xz/distros/void.txt index c5fa156f8a0..d66e95ca507 100644 --- a/build/pkgs/xz/distros/void.txt +++ b/build/pkgs/xz/distros/void.txt @@ -1,2 +1 @@ xz -liblzma-devel diff --git a/build/pkgs/xz/spkg-configure.m4 b/build/pkgs/xz/spkg-configure.m4 index 4a02e31bead..88303e6f518 100644 --- a/build/pkgs/xz/spkg-configure.m4 +++ b/build/pkgs/xz/spkg-configure.m4 @@ -1,7 +1,4 @@ SAGE_SPKG_CONFIGURE([xz], [ - AC_CHECK_LIB([lzma], [lzma_raw_decoder], [lzma_cv_liblzma=yes], [lzma_cv_liblzma=no]) - AC_CHECK_HEADER([lzma.h], [lzma_cv_lzma_h=yes], [lzma_cv_lzma_h=no]) - if test "$lzma_cv_liblzma" = "yes" && test "$lzma_cv_lzma_h" = "yes"; then AC_CACHE_CHECK([for xz >= 4.999.0], [ac_cv_path_XZ], [ AC_PATH_PROGS_FEATURE_CHECK([XZ], [xz], [ xz_version=`$ac_path_XZ --version 2>&1 | cut -d' ' -f4 | $SED -n 1p` @@ -14,7 +11,4 @@ SAGE_SPKG_CONFIGURE([xz], [ ]) AS_IF([test -z "$ac_cv_path_XZ"], [sage_spkg_install_xz=yes]) ]) - else - sage_spkg_install_xz=yes - fi ]) From 5137ae91f2dd0e61de3da26d3458459d21df7c24 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 16:48:41 -0700 Subject: [PATCH 242/355] build/pkgs/{cmake,r}/dependencies: Depend on liblzma, not xz --- build/pkgs/cmake/dependencies | 2 +- build/pkgs/r/dependencies | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/cmake/dependencies b/build/pkgs/cmake/dependencies index 8637994a7b7..2b79396e60e 100644 --- a/build/pkgs/cmake/dependencies +++ b/build/pkgs/cmake/dependencies @@ -1,4 +1,4 @@ -curl zlib bzip2 xz +curl zlib bzip2 liblzma ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/r/dependencies b/build/pkgs/r/dependencies index ceb34c5e8c2..281dc007225 100644 --- a/build/pkgs/r/dependencies +++ b/build/pkgs/r/dependencies @@ -1,4 +1,4 @@ -$(BLAS) gfortran iconv readline bzip2 xz pcre curl | pkgconf +$(BLAS) gfortran iconv readline bzip2 liblzma pcre curl | pkgconf ---------- All lines of this file are ignored except the first. From 462fd33dfa0afc26f07635bce582a24e51ce5db8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 16:48:55 -0700 Subject: [PATCH 243/355] build/pkgs/python3/dependencies: Add liblzma --- build/pkgs/python3/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/python3/dependencies b/build/pkgs/python3/dependencies index 4dd1e381802..0b9e91a711c 100644 --- a/build/pkgs/python3/dependencies +++ b/build/pkgs/python3/dependencies @@ -1,4 +1,4 @@ -zlib readline sqlite libpng bzip2 xz libffi openssl +zlib readline sqlite libpng bzip2 liblzma xz libffi openssl ---------- All lines of this file are ignored except the first. From ba6fdcd228428ad397fffcc2110fa58c4e8f75b2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 16:50:26 -0700 Subject: [PATCH 244/355] build/pkgs/r/spkg-configure.m4: Change DEPCHECK from xz to liblzma --- build/pkgs/r/spkg-configure.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/r/spkg-configure.m4 b/build/pkgs/r/spkg-configure.m4 index e88f3393a91..2fe4b1e97be 100644 --- a/build/pkgs/r/spkg-configure.m4 +++ b/build/pkgs/r/spkg-configure.m4 @@ -1,12 +1,12 @@ SAGE_SPKG_CONFIGURE([r], [ m4_pushdef([SAGE_R_MINVER],["3.4.4"]) - SAGE_SPKG_DEPCHECK([atlas openblas iconv readline bzip2 xz pcre curl], [ + SAGE_SPKG_DEPCHECK([atlas openblas iconv readline bzip2 liblzma pcre curl], [ AS_CASE([$host], [*-*-cygwin*], [ dnl #29486: rpy2 2.8.x does not build against system R on cygwin. sage_spkg_install_r=yes ], [ - PKG_CHECK_MODULES([R], [libR >= $SAGE_R_MINVER], [ + PKG_CHECK_MODULES([R], [libR >= SAGE_R_MINVER], [ AC_PATH_PROG([R], [R]) AS_IF([test "x$R" = x], [ AC_MSG_NOTICE([R is not found]) From bba3a93cd92e5ddec9a6a718d30ad9552bf3ee70 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 16:51:56 -0700 Subject: [PATCH 245/355] build/pkgs/python3/spkg-configure.m4: Change DEPCHECK from xz to liblzma --- build/pkgs/python3/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4 index 9ebcdf77fa9..65e269abae8 100644 --- a/build/pkgs/python3/spkg-configure.m4 +++ b/build/pkgs/python3/spkg-configure.m4 @@ -19,7 +19,7 @@ SAGE_SPKG_CONFIGURE([python3], [ dnl dnl However, if we add another package (providing a shared library linked into a Python module) dnl that also uses libsqlite3, then we will have to put the DEPCHECK back in. - SAGE_SPKG_DEPCHECK([bzip2 xz libffi], [ + SAGE_SPKG_DEPCHECK([bzip2 liblzma libffi], [ dnl Check if we can do venv with a system python3 dnl instead of building our own copy. dnl Trac #31160: We no longer check for readline here. From bf500bea95744af285d461b4f84ac573ecc97e3d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 17:12:33 -0700 Subject: [PATCH 246/355] build/pkgs/xz/spkg-configure.m4: Set sage_require_xz=no if sage-bootstrap-python is new enough --- build/pkgs/xz/spkg-configure.m4 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/pkgs/xz/spkg-configure.m4 b/build/pkgs/xz/spkg-configure.m4 index 88303e6f518..a4ed2f8c15e 100644 --- a/build/pkgs/xz/spkg-configure.m4 +++ b/build/pkgs/xz/spkg-configure.m4 @@ -11,4 +11,12 @@ SAGE_SPKG_CONFIGURE([xz], [ ]) AS_IF([test -z "$ac_cv_path_XZ"], [sage_spkg_install_xz=yes]) ]) +], [dnl REQUIRED-CHECK + dnl Trac #30948: All dependencies on "xz" are merely build-time dependencies + dnl on the xz binary (for unpacking the tarball in sage_bootstrap.uncompress.tar_file + dnl - when sage-bootstrap-python is so old that it cannot do that by itself). + dnl Packages that depend on actual xz or liblzma should depend on the liblzma spkg. + AS_IF(["$SAGE_BOOTSTRAP_PYTHON" -c "import lzma"], [ + sage_require_xz=no + ]) ]) From bc010068136dbdda22a83bb933dbffa3686865e4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 17:58:52 -0700 Subject: [PATCH 247/355] build/pkgs/xz: Update to 5.2.5, add upstream_url --- build/pkgs/xz/checksums.ini | 7 ++++--- build/pkgs/xz/package-version.txt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/pkgs/xz/checksums.ini b/build/pkgs/xz/checksums.ini index b344faf8359..6fa58c3a084 100644 --- a/build/pkgs/xz/checksums.ini +++ b/build/pkgs/xz/checksums.ini @@ -1,4 +1,5 @@ tarball=xz-VERSION.tar.gz -sha1=14663612422ab61386673be78fbb2556f50a1f08 -md5=7cf6a8544a7dae8e8106fdf7addfa28c -cksum=2298486723 +sha1=fa2ae4db119f639a01b02f99f1ba671ece2828eb +md5=0d270c997aff29708c74d53f599ef717 +cksum=1153713708 +upstream_url=https://tukaani.org/xz/xz-VERSION.tar.gz diff --git a/build/pkgs/xz/package-version.txt b/build/pkgs/xz/package-version.txt index 7cffe05675a..462faf74854 100644 --- a/build/pkgs/xz/package-version.txt +++ b/build/pkgs/xz/package-version.txt @@ -1 +1 @@ -5.2.2.p0 +5.2.5 From 009256e4068b5d349d8e0a2793e77cd83b7c10ec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 18:02:21 -0700 Subject: [PATCH 248/355] build/pkgs/liblzma/dependencies: Update --- build/pkgs/liblzma/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/liblzma/dependencies b/build/pkgs/liblzma/dependencies index 43f7abfd1e2..f111204fa1f 100644 --- a/build/pkgs/liblzma/dependencies +++ b/build/pkgs/liblzma/dependencies @@ -1,4 +1,4 @@ -$(INST)/xz-$(vers_xz) +$(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/xz-$(vers_xz) ---------- All lines of this file are ignored except the first. From 1d93f2f740752b8197a82debf34db58413855764 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Sep 2021 18:59:43 -0700 Subject: [PATCH 249/355] configure.ac: --disable-r should disable pcre --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7156bf4aecf..337fefdb643 100644 --- a/configure.ac +++ b/configure.ac @@ -447,7 +447,7 @@ AC_ARG_ENABLE([notebook], AC_ARG_ENABLE([r], AS_HELP_STRING([--disable-r], [disable build of the R package and related packages]), [ - for pkg in r rpy2 r_jupyter; do + for pkg in r rpy2 r_jupyter pcre; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done ]) From 2b40d390c2d554e02192dd6fda48caa6264ba5d7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 26 Sep 2021 15:18:58 +0900 Subject: [PATCH 250/355] Strengthening Laurent series conversion. --- src/sage/rings/lazy_series_ring.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index f68dbecac83..35e1c921dfc 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -34,6 +34,7 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.lazy_series import (LazyModuleElement, + LazyCauchyProductSeries, LazyLaurentSeries, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -253,6 +254,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No ... ValueError: constant may only be specified if the degree is specified + sage: D = LazyDirichletSeriesRing(ZZ, 't') + sage: m = D(moebius) + sage: L(m) + Traceback (most recent call last): + ... + ValueError: unable to convert ... into Lazy Laurent Series Ring ... + We support the old input format for ``constant``:: sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) @@ -263,11 +271,6 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: f == g True - sage: D = LazyDirichletSeriesRing(ZZ, 't') - sage: m = D(moebius) - sage: L(m) - z - z^2 - z^3 - z^5 + z^6 - z^7 + O(z^8) - .. TODO:: Add a method to change the sparse/dense implementation. @@ -318,7 +321,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return self.element_class(self, coeff_stream) # Handle when it is a lazy series - if isinstance(x, LazyModuleElement): + if isinstance(x, LazyCauchyProductSeries): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") From eb3304dd521a3d5a9334e747a08e234bbf16b4eb Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 26 Sep 2021 12:00:07 +0200 Subject: [PATCH 251/355] Update tests for arb 2.21 --- src/sage/functions/gamma.py | 12 +++++----- src/sage/functions/other.py | 4 ++-- src/sage/rings/complex_arb.pyx | 42 +++++++++++++++++----------------- src/sage/rings/real_arb.pyx | 24 +++++++++---------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 08f549777c2..d3c2d17e38b 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -357,12 +357,12 @@ def _method_arguments(self, x, y): TESTS:: sage: b = RBF(1, 1e-10) - sage: gamma(b) - [1.00000000 +/- 8.07e-10] - sage: gamma(CBF(b)) - [1.00000000 +/- 8.07e-10] - sage: gamma(CBF(b), 4) - [0.01831564 +/- 2.65e-9] + sage: gamma(b) # abs tol 1e-9 + [1.0000000000 +/- 5.78e-11] + sage: gamma(CBF(b)) # abs tol 1e-9 + [1.0000000000 +/- 5.78e-11] + sage: gamma(CBF(b), 4) # abs tol 2e-9 + [0.018315639 +/- 9.00e-10] sage: gamma(CBF(1), b) [0.3678794412 +/- 6.54e-11] """ diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 053e0120454..3f675ac648d 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1579,8 +1579,8 @@ def __init__(self): Check that :trac:`16166` is fixed:: sage: RBF = RealBallField(53) - sage: factorial(RBF(4.2)) - [32.5780960503313 +/- 6.72e-14] + sage: factorial(RBF(4.2)) # abs tol 1e-13 + [32.5780960503314 +/- 6.06e-14] Test pickling:: diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 2fc0a3bb420..9aa6ba15d7b 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -1040,8 +1040,8 @@ class ComplexBallField(UniqueRepresentation, Field): sage: CBF.integral(lambda x, _: x, 0, 1) [0.500000000000000 +/- ...e-16] - sage: CBF.integral(lambda x, _: x.gamma(), 1 - CBF(i), 1 + CBF(i)) - [+/- 4...e-15] + [1.5723926694981 +/- 4...e-14]*I + sage: CBF.integral(lambda x, _: x.gamma(), 1 - CBF(i), 1 + CBF(i)) # abs tol 1e-13 + [+/- 1.39e-15] + [1.57239266949806 +/- 8.33e-15]*I sage: C = ComplexBallField(100) sage: C.integral(lambda x, _: x.cos() * x.sin(), 0, 1) @@ -1144,8 +1144,8 @@ class ComplexBallField(UniqueRepresentation, Field): [50.00000000 +/- ...e-9] sage: i = QuadraticField(-1).gen() - sage: CBF.integral(lambda x, _: (1 + i*x).gamma(), -1, 1) - [1.5723926694981 +/- 4...e-14] + [+/- 4...e-15]*I + sage: CBF.integral(lambda x, _: (1 + i*x).gamma(), -1, 1) # abs tol 1e-13 + [1.57239266949806 +/- 8.33e-15] + [+/- 1.39e-15]*I sage: ComplexBallField(10000).integral(lambda x, _: x.sin(), 0, 1, rel_tol=1e-300) [0.459... +/- ...e-3...] @@ -2976,8 +2976,8 @@ cdef class ComplexBall(RingElement): [+/- ...e+347382171326740403407] sage: ComplexBallField(128)(1).rising_factorial(2**64) [2.343691126796861348e+347382171305201285713 +/- ...e+347382171305201285694] - sage: CBF(1/2).rising_factorial(CBF(2,3)) - [-0.123060451458124 +/- ...e-16] + [0.040641263167655 +/- ...e-16]*I + sage: CBF(1/2).rising_factorial(CBF(2,3)) # abs tol 1e-15 + [-0.123060451458124 +/- 3.06e-16] + [0.0406412631676552 +/- 7.57e-17]*I """ cdef ComplexBall result = self._new() @@ -3488,16 +3488,16 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(1, 1).gamma() - [0.498015668118356 +/- ...e-16] + [-0.154949828301811 +/- ...e-16]*I + sage: CBF(1, 1).gamma() # abs tol 1e-15 + [0.498015668118356 +/- 1.26e-16] + [-0.1549498283018107 +/- 8.43e-17]*I sage: CBF(-1).gamma() nan - sage: CBF(1, 1).gamma(0) - [0.498015668118356 +/- ...e-16] + [-0.154949828301811 +/- ...e-16]*I + sage: CBF(1, 1).gamma(0) # abs tol 1e-15 + [0.498015668118356 +/- 1.26e-16] + [-0.1549498283018107 +/- 8.43e-17]*I sage: CBF(1, 1).gamma(100) [-3.6143867454139e-45 +/- ...e-59] + [-3.7022961377791e-44 +/- ...e-58]*I - sage: CBF(1, 1).gamma(CLF(i)) - [0.32886684193500 +/- ...e-15] + [-0.18974945045621 +/- ...e-15]*I + sage: CBF(1, 1).gamma(CLF(i)) # abs tol 1e-14 + [0.328866841935004 +/- 7.07e-16] + [-0.189749450456210 +/- 9.05e-16]*I """ cdef ComplexBall my_z cdef ComplexBall res = self._new() @@ -3536,9 +3536,9 @@ cdef class ComplexBall(RingElement): sage: CBF(-1/2).log_gamma() [1.265512123484645 +/- ...e-16] + [-3.141592653589793 +/- ...e-16]*I sage: CBF(-1).log_gamma() - nan + [-3.141592653589793 +/- ...e-16]*I - sage: CBF(-3/2).log_gamma() - [0.860047015376481 +/- ...e-16] + [-6.28318530717959 +/- ...e-15]*I + nan + ...*I + sage: CBF(-3/2).log_gamma() # abs tol 1e-14 + [0.860047015376481 +/- 3.82e-16] + [-6.283185307179586 +/- 6.77e-16]*I sage: CBF(-3/2).log_gamma(analytic=True) nan + nan*I """ @@ -3822,8 +3822,8 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).hypergeometric([1], []) 1.000000000000000*I - sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) - [0.7871684267473 +/- 7...e-14] + [0.2749254173721 +/- 9...e-14]*I + sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) # abs tol 1e-14 + [0.7871684267473 +/- 6.79e-14] + [0.2749254173721 +/- 8.82e-14]*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2],regularized=True) [0.4441122268685 +/- 3...e-14] + [0.1551100567338 +/- 5...e-14]*I @@ -3832,8 +3832,8 @@ cdef class ComplexBall(RingElement): sage: CBF(5).hypergeometric([2,3], [-5], regularized=True) [5106.925964355 +/- ...e-10] - sage: CBF(2016).hypergeometric([], [2/3]) - [2.025642692328e+38 +/- ...e+25] + sage: CBF(2016).hypergeometric([], [2/3]) # abs tol 1e+26 + [2.0256426923278e+38 +/- 9.59e+24] sage: CBF(-2016).hypergeometric([], [2/3], regularized=True) [-0.0005428550847 +/- ...e-14] @@ -4927,8 +4927,8 @@ cdef class ComplexBall(RingElement): [-45.6666666666666 +/- ...e-14] sage: CBF(10).laguerre_L(3, 2) [-6.666666666667 +/- ...e-13] - sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) - [5515.315030271 +/- ...e-10] + [-12386.942845271 +/- ...e-10]*I + sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) # abs tol 1e-9 + [5515.3150302713 +/- 5.02e-11] + [-12386.9428452714 +/- 6.21e-11]*I """ cdef ComplexBall my_n = self._parent.coerce(n) cdef ComplexBall my_m = self._parent.coerce(m) diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index f6c09f44a5d..bcbea52d322 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -752,8 +752,8 @@ class RealBallField(UniqueRepresentation, Field): EXAMPLES:: - sage: RBF.euler_constant() - [0.577215664901533 +/- ...e-16] + sage: RBF.euler_constant() # abs tol 1e-15 + [0.5772156649015329 +/- 9.00e-17] sage: RealBallField(128).euler_constant() [0.57721566490153286060651209008240243104 +/- ...e-39] """ @@ -896,8 +896,8 @@ class RealBallField(UniqueRepresentation, Field): TESTS:: - sage: RBF.gamma(RLF(pi)) - [2.2880377953400 +/- ...e-14] + sage: RBF.gamma(RLF(pi)) # abs tol 1e-13 + [2.28803779534003 +/- 4.12e-15] """ cdef RealBall res cdef Integer x_as_Integer @@ -1156,8 +1156,8 @@ cdef class RealBall(RingElement): sage: a = RealBallField()(RIF(1)) # indirect doctest sage: b = a.psi() - sage: b - [-0.577215664901533 +/- ...e-16] + sage: b # abs tol 1e-15 + [-0.5772156649015329 +/- 4.84e-17] sage: RIF(b) -0.577215664901533? """ @@ -1302,8 +1302,8 @@ cdef class RealBall(RingElement): [1.282427129100623 +/- ...e-16] sage: RealBall(RBF, sage.symbolic.constants.e) [2.718281828459045 +/- ...e-16] - sage: RealBall(RBF, sage.symbolic.constants.EulerGamma()) - [0.577215664901533 +/- ...e-16] + sage: RealBall(RBF, sage.symbolic.constants.EulerGamma()) # abs tol 1e-15 + [0.5772156649015329 +/- 9.00e-17] sage: RBF("1 +/- 0.001") [1.00 +/- ...e-3] sage: RBF("2.3e10000000000000000000000 +/- 0.00005e10000000000000000000000") @@ -3535,8 +3535,8 @@ cdef class RealBall(RingElement): sage: RBF(1).rising_factorial(5) 120.0000000000000 - sage: RBF(1/2).rising_factorial(1/3) - [0.63684988431797 +/- ...e-15] + sage: RBF(1/2).rising_factorial(1/3) # abs tol 1e-14 + [0.636849884317974 +/- 8.98e-16] """ cdef RealBall result = self._new() cdef RealBall my_n = self._parent.coerce(n) @@ -3551,8 +3551,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(1).psi() - [-0.577215664901533 +/- ...e-16] + sage: RBF(1).psi() # abs tol 1e-15 + [-0.5772156649015329 +/- 4.84e-17] """ cdef RealBall result = self._new() From 65a543de404ad7754b43dfcebe2313cca10ea5fb Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 26 Sep 2021 12:24:43 +0200 Subject: [PATCH 252/355] trac #32562: some more --- src/sage/graphs/generators/smallgraphs.py | 74 ++++------------------- 1 file changed, 12 insertions(+), 62 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 9051a8b7c88..a7ddfa7c1d9 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -1052,20 +1052,9 @@ def BidiakisCube(): edge_dict = { 0:[1,6,11], 1:[2,5], 2:[3,10], 3:[4,9], 4:[5,8], 5:[6], 6:[7], 7:[8,11], 8:[9], 9:[10], 10:[11]} - pos_dict = { - 0: [0, 1], - 1: [0.5, 0.866025403784439], - 2: [0.866025403784439, 0.500000000000000], - 3: [1, 0], - 4: [0.866025403784439, -0.5], - 5: [0.5, -0.866025403784439], - 6: [0, -1], - 7: [-0.5, -0.866025403784439], - 8: [-0.866025403784439, -0.5], - 9: [-1, 0], - 10: [-0.866025403784439, 0.5], - 11: [-0.5, 0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Bidiakis cube") + g = Graph(edge_dict, format='dict_of_lists', name="Bidiakis cube") + g._circle_embedding(range(12), angle=pi/2) + return g def BiggsSmithGraph(embedding=1): r""" @@ -1307,29 +1296,11 @@ def BrinkmannGraph(): 15: [18,19], 16: [19,20], 17: [20]} - pos_dict = { - 0: [0, 4], - 1: [3.12732592987212, 2.49395920743493], - 2: [3.89971164872729, -0.890083735825258], - 3: [1.73553495647023, -3.60387547160968], - 4: [-1.73553495647023, -3.60387547160968], - 5: [-3.89971164872729, -0.890083735825258], - 6: [-3.12732592987212, 2.49395920743493], - 7: [0.867767478235116, 1.80193773580484], - 8: [1.94985582436365, 0.445041867912629], - 9: [1.56366296493606, -1.24697960371747], - 10: [0, -2], - 11: [-1.56366296493606, -1.24697960371747], - 12: [-1.94985582436365, 0.445041867912629], - 13: [-0.867767478235116, 1.80193773580484], - 14: [0.433883739117558, 0.900968867902419], - 15: [0.974927912181824, 0.222520933956314], - 16: [0.781831482468030, -0.623489801858733], - 17: [0, -1], - 18: [-0.781831482468030, -0.623489801858733], - 19: [-0.974927912181824, 0.222520933956315], - 20: [-0.433883739117558, 0.900968867902419]} - return Graph(edge_dict, pos=pos_dict, name="Brinkmann graph") + g = Graph(edge_dict, format='dict_of_lists', name="Brinkmann graph") + g._circle_embedding(range(7), radius=4, angle=pi/2) + g._circle_embedding(range(7, 14), radius=2, angle=pi/2 + pi/7) + g._circle_embedding(range(14, 21), radius=1, angle=pi/2 + pi/7) + return g def BrouwerHaemersGraph(): r""" @@ -1948,31 +1919,10 @@ def DurerGraph(): sage: ag.is_isomorphic(DihedralGroup(6)) True """ - edge_dict = { - 0: [1,5,6], - 1: [2,7], - 2: [3,8], - 3: [4,9], - 4: [5,10], - 5: [11], - 6: [8,10], - 7: [9,11], - 8: [10], - 9: [11]} - pos_dict = { - 0: [2, 0], - 1: [1, 1.73205080756888], - 2: [-1, 1.73205080756888], - 3: [-2, 0], - 4: [-1, -1.73205080756888], - 5: [1, -1.73205080756888], - 6: [1, 0], - 7: [0.5, 0.866025403784439], - 8: [-0.5, 0.866025403784439], - 9: [-1, 0], - 10: [-0.5, -0.866025403784439], - 11: [0.5, -0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Durer graph") + from sage.graphs.generators.families import GeneralizedPetersenGraph + G = GeneralizedPetersenGraph(6, 2) + G.name("Durer graph") + return G def DyckGraph(): """ From 8ae26363bc3089cf3769a3f49f995373cc879470 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 26 Sep 2021 13:53:48 +0200 Subject: [PATCH 253/355] trac #32569: refresh classical_geometries.py --- .../graphs/generators/classical_geometries.py | 460 +++++++++--------- 1 file changed, 237 insertions(+), 223 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 238380c31e7..67805a34d1a 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -8,13 +8,15 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ -########################################################################### -# +# **************************************************************************** # Copyright (C) 2015 Sagemath project # -# Distributed under the terms of the GNU General Public License (GPL) -# https://www.gnu.org/licenses/ -########################################################################### +# 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. +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.graphs.graph import Graph from sage.arith.all import is_prime_power @@ -23,23 +25,24 @@ def SymplecticPolarGraph(d, q, algorithm=None): r""" - Returns the Symplectic Polar Graph `Sp(d,q)`. + Return the Symplectic Polar Graph `Sp(d,q)`. - The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of dimension - `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices `u,v` are - made adjacent if `f(u,v)=0`. + The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of + dimension `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices + `u,v` are made adjacent if `f(u,v)=0`. See the page `on symplectic graphs on Andries Brouwer's website `_. INPUT: - - ``d,q`` (integers) -- note that only even values of `d` are accepted by - the function. + - ``d,q`` -- integers; note that only even values of `d` are accepted by the + function. - - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP - library interface, computing totally singular subspaces, which is faster for `q>3`. - Otherwise it is done directly. + - ``algorithm`` -- string (default: ``None``); if set to 'gap' then the + computation is carried via GAP library interface, computing totally + singular subspaces, which is faster for `q>3`. Otherwise it is done + directly. EXAMPLES: @@ -97,19 +100,19 @@ def SymplecticPolarGraph(d, q, algorithm=None): V = VectorSpace(F,d) PV = list(ProjectiveSpace(d-1,F)) - G = Graph([[tuple(_) for _ in PV], lambda x,y:V(x)*(M*V(y)) == 0], loops = False) + G = Graph([[tuple(_) for _ in PV], lambda x,y:V(x)*(M*V(y)) == 0], loops=False) else: raise ValueError("unknown algorithm!") - G.name("Symplectic Polar Graph Sp("+str(d)+","+str(q)+")") + G.name("Symplectic Polar Graph Sp({},{})".format(d,q)) G.relabel() return G -def AffineOrthogonalPolarGraph(d,q,sign="+"): +def AffineOrthogonalPolarGraph(d, q, sign="+"): r""" - Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. + Return the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. Affine Polar graphs are built from a `d`-dimensional vector space over `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic @@ -118,20 +121,19 @@ def AffineOrthogonalPolarGraph(d,q,sign="+"): Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)` is not. - For more information on Affine Polar graphs, see `Affine Polar - Graphs page of Andries Brouwer's website - `_. + For more information on Affine Polar graphs, see `Affine Polar Graphs page + of Andries Brouwer's website `_. INPUT: - - ``d`` (integer) -- ``d`` must be even if ``sign is not None``, and odd - otherwise. + - ``d`` -- integer; ``d`` must be even if ``sign is not None``, and odd + otherwise - - ``q`` (integer) -- a power of a prime number, as `F_q` must exist. + - ``q`` -- integer; a power of a prime number, as `F_q` must exist - - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute - (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default - ``sign="+"``. + - ``sign`` -- string (default: ``"+"``); must be equal to ``"+"``, ``"-"``, + or ``None`` to compute (respectively) `VO^+(d,q),VO^-(d,q)` or + `VO(d,q)` .. NOTE:: @@ -176,7 +178,7 @@ def AffineOrthogonalPolarGraph(d,q,sign="+"): if d % 2: raise ValueError("d must be even when sign is not None") else: - if d % 2 == 0: + if not d % 2: raise ValueError("d must be odd when sign is None") s = 0 @@ -208,10 +210,10 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``sign`` -- ``"+"`` or ``"-"`` if `m` is even, ``"+"`` (default) - otherwise. + - ``sign`` -- string (default: ``"+"``); must be ``"+"`` or ``"-"`` if `m` + is even, ``"+"`` (default) otherwise - ``point_type`` -- a list of elements from `F_q` @@ -235,13 +237,13 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^+(7,3)`:: sage: g=_orthogonal_polar_graph(7,3,point_type=[1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (378, 117, 36, 36) `NO^-(7,3)`:: - sage: g=_orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g=_orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (351, 126, 45, 45) `NO^+(6,3)`:: @@ -258,14 +260,14 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^{-,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[2,3]) # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g=_orthogonal_polar_graph(5,5,point_type=[2,3]) # long time + sage: g.is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g=_orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (325, 60, 15, 10) TESTS:: @@ -283,7 +285,7 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap - if m % 2 == 0: + if not m % 2: if sign != "+" and sign != "-": raise ValueError("sign must be equal to either '-' or '+' when " "m is even") @@ -323,17 +325,17 @@ def P(x,y): def OrthogonalPolarGraph(m, q, sign="+"): r""" - Returns the Orthogonal Polar Graph `O^{\epsilon}(m,q)`. + Return the Orthogonal Polar Graph `O^{\epsilon}(m,q)`. - For more information on Orthogonal Polar graphs, see the `page of - Andries Brouwer's website `_. + For more information on Orthogonal Polar graphs, see the `page of Andries + Brouwer's website `_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``sign`` -- ``"+"`` or ``"-"`` if `m` is even, ``"+"`` (default) - otherwise. + - ``sign`` -- string (default: ``"+"``); must be ``"+"`` or ``"-"`` if `m` + is even, ``"+"`` (default) otherwise EXAMPLES:: @@ -378,22 +380,22 @@ def OrthogonalPolarGraph(m, q, sign="+"): def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): r""" - Returns the Graph `NO^{\epsilon,\perp}_{m}(q)` + Return the Graph `NO^{\epsilon,\perp}_{m}(q)` - Let the vectorspace of dimension `m` over `F_q` be - endowed with a nondegenerate quadratic form `F`, of type ``sign`` for `m` even. + Let the vectorspace of dimension `m` over `F_q` be endowed with a + nondegenerate quadratic form `F`, of type ``sign`` for `m` even. * `m` even: assume further that `q=2` or `3`. Returns the graph of the - points (in the underlying projective space) `x` satisfying `F(x)=1`, with adjacency - given by orthogonality w.r.t. `F`. Parameter ``perp`` is ignored. - - * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and - return the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``, - respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency - given by orthogonality w.r.t. `F` (cf. Sect 7.D of [BL1984]_). - Otherwise return the graph - of nongenerate hyperplanes of type ``sign``, adjacent whenever the intersection - is degenerate (cf. Sect. 7.C of [BL1984]_). + points (in the underlying projective space) `x` satisfying `F(x)=1`, with + adjacency given by orthogonality w.r.t. `F`. Parameter ``perp`` is + ignored. + + * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and return + the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``, + respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency given by + orthogonality w.r.t. `F` (cf. Sect 7.D of [BL1984]_). Otherwise return + the graph of nongenerate hyperplanes of type ``sign``, adjacent whenever + the intersection is degenerate (cf. Sect. 7.C of [BL1984]_). Note that for `q=2` one will get a complete graph. For more information, see Sect. 9.9 of [BH2012]_ and [BL1984]_. Note that @@ -402,11 +404,11 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): INPUT: - - ``m`` - integer, half the dimension of the underlying vectorspace + - ``m`` -- integer; half the dimension of the underlying vectorspace - - ``q`` - a power of a prime number, the size of the underlying field + - ``q`` -- a power of a prime number, the size of the underlying field - - ``sign`` -- ``"+"`` (default) or ``"-"``. + - ``sign`` -- string (default: ``"+"``); must be either ``"+"`` or ``"-"`` EXAMPLES: @@ -435,9 +437,9 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): Wilbrink's graphs for `q=5`:: - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time (325, 60, 15, 10) - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) Wilbrink's graphs:: @@ -448,9 +450,9 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') sage: g.is_strongly_regular(parameters=True) (120, 51, 18, 24) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) + sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (2080, 1071, 558, 544) TESTS:: @@ -466,7 +468,7 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time sage: g.is_strongly_regular(parameters=True) # long time (117, 36, 15, 9) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time + sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time NO^-(6, 3): Graph on 126 vertices sage: g.is_strongly_regular(parameters=True) # long time (126, 45, 12, 18) @@ -480,18 +482,17 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): Traceback (most recent call last): ... ValueError: for m even q must be 2 or 3 - """ p, k = is_prime_power(q, get_data=True) - if k == 0: + if not k: raise ValueError('q must be a prime power') dec = '' - if m % 2 == 0: + if not m % 2: if q in [2, 3]: G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1]) else: raise ValueError("for m even q must be 2 or 3") - elif not perp is None: + elif perp is not None: if q == 5: G = _orthogonal_polar_graph(m, q, point_type=\ [-1,1] if sign=='+' else [2,3] if sign=='-' else []) @@ -499,7 +500,7 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): else: raise ValueError("for perp not None q must be 5") else: - if not sign in ['+','-']: + if sign not in ['+', '-']: raise ValueError("sign must be '+' or '-'") from sage.libs.gap.libgap import libgap g0 = libgap.GeneralOrthogonalGroup(m,q) @@ -532,13 +533,14 @@ def _polar_graph(m, q, g, intersection_size=None): r""" The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)` - Building a graph on an orbit of a group `g` of `m\times m` matrices over `GF(q)` on - the points (or subspaces of dimension ``m//2``) isotropic w.r.t. the form `F` - left invariant by the group `g`. + Building a graph on an orbit of a group `g` of `m\times m` matrices over + `GF(q)` on the points (or subspaces of dimension ``m//2``) isotropic + w.r.t. the form `F` left invariant by the group `g`. The only constraint is that the first ``m//2`` elements of the standard - basis must generate a totally isotropic w.r.t. `F` subspace; this is the case with - these groups coming from GAP; namely, `F` has the anti-diagonal all-1 matrix. + basis must generate a totally isotropic w.r.t. `F` subspace; this is the + case with these groups coming from GAP; namely, `F` has the anti-diagonal + all-1 matrix. INPUT: @@ -548,10 +550,10 @@ def _polar_graph(m, q, g, intersection_size=None): - ``g`` -- the group acting - - ``intersection_size`` -- if ``None``, build the graph on the isotropic points, with - adjacency being orthogonality w.r.t. `F`. Otherwise, build the graph on the maximal - totally isotropic subspaces, with adjacency specified by ``intersection_size`` being - as given. + - ``intersection_size`` -- (default: ``None``); if ``None``, build the graph + on the isotropic points, with adjacency being orthogonality w.r.t. `F`. + Otherwise, build the graph on the maximal totally isotropic subspaces, + with adjacency specified by ``intersection_size`` being as given. TESTS:: @@ -563,18 +565,18 @@ def _polar_graph(m, q, g, intersection_size=None): """ from sage.libs.gap.libgap import libgap from itertools import combinations - W=libgap.FullRowSpace(libgap.GF(q), m) # F_q^m - B=libgap.Elements(libgap.Basis(W)) # the standard basis of W - V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points - gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group - s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace + W=libgap.FullRowSpace(libgap.GF(q), m) # F_q^m + B=libgap.Elements(libgap.Basis(W)) # the standard basis of W + V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points + gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group + s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] - h = libgap.Set([libgap.Position(V, x) for x in sp]) # indices of the points in s - L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces + h = libgap.Set([libgap.Position(V, x) for x in sp]) # indices of the points in s + L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces if intersection_size is None: G = Graph() - for x in L: # every pair of points in the subspace is adjacent to each other in G + for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) return G else: @@ -583,18 +585,19 @@ def _polar_graph(m, q, g, intersection_size=None): def UnitaryPolarGraph(m, q, algorithm="gap"): r""" - Returns the Unitary Polar Graph `U(m,q)`. + Return the Unitary Polar Graph `U(m,q)`. - For more information on Unitary Polar graphs, see the `page of - Andries Brouwer's website `_. + For more information on Unitary Polar graphs, see the `page of Andries + Brouwer's website `_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP - library interface, computing totally singular subspaces, which is faster for - large examples (especially with `q>2`). Otherwise it is done directly. + - ``algorithm`` -- string (default: ``"gap"``); if set to 'gap' then the + computation is carried via GAP library interface, computing totally + singular subspaces, which is faster for large examples (especially with + `q>2`). Otherwise it is done directly. EXAMPLES:: @@ -622,7 +625,7 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): from sage.libs.gap.libgap import libgap G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q)) - elif algorithm is None: # slow on large examples + elif algorithm is None: # slow on large examples from sage.schemes.projective.projective_space import ProjectiveSpace from sage.modules.free_module_element import free_module_element as vector Fq = FiniteField(q**2, 'a') @@ -650,17 +653,17 @@ def P(x, y): def NonisotropicUnitaryPolarGraph(m, q): r""" - Returns the Graph `NU(m,q)`. + Return the Graph `NU(m,q)`. - Returns the graph on nonisotropic, with respect to a nondegenerate - Hermitean form, points of the `(m-1)`-dimensional projective space over `F_q`, - with points adjacent whenever they lie on a tangent (to the set of isotropic points) - line. - For more information, see Sect. 9.9 of [BH2012]_ and series C14 in [Hub1975]_. + Returns the graph on nonisotropic, with respect to a nondegenerate Hermitean + form, points of the `(m-1)`-dimensional projective space over `F_q`, with + points adjacent whenever they lie on a tangent (to the set of isotropic + points) line. For more information, see Sect. 9.9 of [BH2012]_ and series + C14 in [Hub1975]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power EXAMPLES:: @@ -673,7 +676,7 @@ def NonisotropicUnitaryPolarGraph(m, q): sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) (40, 27, 18, 18) - sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time (540, 224, 88, 96) sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): @@ -681,13 +684,13 @@ def NonisotropicUnitaryPolarGraph(m, q): ValueError: q must be a prime power """ p, k = is_prime_power(q,get_data=True) - if k==0: + if not k: raise ValueError('q must be a prime power') from sage.libs.gap.libgap import libgap from itertools import combinations F=libgap.GF(q**2) # F_{q^2} W=libgap.FullRowSpace(F, m) # F_{q^2}^m - B=libgap.Elements(libgap.Basis(W)) # the standard basis of W + B=libgap.Elements(libgap.Basis(W)) # the standard basis of W if m % 2: point = B[(m-1)/2] else: @@ -696,18 +699,18 @@ def NonisotropicUnitaryPolarGraph(m, q): else: point = B[(m-2)/2] + B[m/2] g = libgap.GeneralUnitaryGroup(m,q) - V = libgap.Orbit(g,point,libgap.OnLines) # orbit on nonisotropic points + V = libgap.Orbit(g,point,libgap.OnLines) # orbit on nonisotropic points gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group - s = libgap.Subspace(W,[point, point+B[0]]) # a tangent line on point + s = libgap.Subspace(W,[point, point+B[0]]) # a tangent line on point # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] h = libgap.Set([libgap.Position(V, x) for x in libgap.Intersection(V, sp)]) # indices - L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines + L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines G = Graph() - for x in L: # every pair of points in the subspace is adjacent to each other in G + for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) G.relabel() G.name("NU" + str((m, q))) @@ -715,14 +718,14 @@ def NonisotropicUnitaryPolarGraph(m, q): def UnitaryDualPolarGraph(m, q): r""" - Returns the Dual Unitary Polar Graph `U(m,q)`. + Return the Dual Unitary Polar Graph `U(m,q)`. For more information on Unitary Dual Polar graphs, see [BCN1989]_ and Sect. 2.3.1 of [Coh1981]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power EXAMPLES: @@ -760,23 +763,23 @@ def UnitaryDualPolarGraph(m, q): intersection_size=int((q**(2*(m//2-1))-1)/(q**2-1))) G.relabel() G.name("Unitary Dual Polar Graph DU" + str((m, q))) - if m==4: + if m == 4: G.name(G.name()+'; GQ'+str((q,q**2))) - if m==5: + if m == 5: G.name(G.name()+'; GQ'+str((q**3,q**2))) return G def SymplecticDualPolarGraph(m, q): r""" - Returns the Symplectic Dual Polar Graph `DSp(m,q)`. + Return the Symplectic Dual Polar Graph `DSp(m,q)`. For more information on Symplectic Dual Polar graphs, see [BCN1989]_ and Sect. 2.3.1 of [Coh1981]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power, and `m` must be even. + - ``m,q`` -- integers; `q` must be a prime power, and `m` must be even EXAMPLES:: @@ -802,13 +805,13 @@ def SymplecticDualPolarGraph(m, q): G.relabel() G.name("Symplectic Dual Polar Graph DSp" + str((m, q))) - if m==4: + if m == 4: G.name(G.name()+'; GQ'+str((q,q))) return G -def TaylorTwographDescendantSRG(q, clique_partition=None): +def TaylorTwographDescendantSRG(q, clique_partition=False): r""" - constructing the descendant graph of the Taylor's two-graph for `U_3(q)`, `q` odd + Return the descendant graph of the Taylor's two-graph for `U_3(q)`, `q` odd. This is a strongly regular graph with parameters `(v,k,\lambda,\mu)=(q^3, (q^2+1)(q-1)/2, (q-1)^3/4-1, (q^2+1)(q-1)/4)` @@ -818,17 +821,19 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): :func:`~sage.graphs.graph_generators.GraphGenerators.TaylorTwographSRG`, a strongly regular graph on `q^3+1` vertices in the Seidel switching class of `T`, for which we need `(q^2+1)/2` cliques. - The cliques are the `q^2` lines on `v_0` of the projective plane containing the unital - for `U_3(q)`, and intersecting the unital (i.e. the vertices of the graph and the point - we remove) in `q+1` points. This is all taken from §7E of [BL1984]_. + The cliques are the `q^2` lines on `v_0` of the projective plane containing + the unital for `U_3(q)`, and intersecting the unital (i.e. the vertices of + the graph and the point we remove) in `q+1` points. This is all taken from + §7E of [BL1984]_. INPUT: - ``q`` -- a power of an odd prime number - - ``clique_partition`` -- if ``True``, return `q^2-1` cliques of size `q` - with empty pairwise intersection. (Removing all of them leaves a clique, too), - and the point removed from the unital. + - ``clique_partition`` -- boolean (default: ``False``); when set to + ``True``, return `q^2-1` cliques of size `q` with empty pairwise + intersection. (Removing all of them leaves a clique, too), and the point + removed from the unital. EXAMPLES:: @@ -838,7 +843,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph sage: T = taylor_twograph(3) # long time - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True sage: g=graphs.TaylorTwographDescendantSRG(5) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -859,7 +864,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): ValueError: q must be an odd prime power """ p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q must be an odd prime power') from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.integer_mod import mod @@ -872,7 +877,7 @@ def S(x, y): V = [x for x in PG if S(x,x) == 0] # the points of the unital v0 = V[0] V.remove(v0) - if mod(q,4)==1: + if mod(q, 4) == 1: G = Graph([V,lambda y,z: not (S(v0,y)*S(y,z)*S(z,v0)).is_square()], loops=False) else: G = Graph([V,lambda y,z: (S(v0,y)*S(y,z)*S(z,v0)).is_square()], loops=False) @@ -887,7 +892,8 @@ def S(x, y): def TaylorTwographSRG(q): r""" - constructing a strongly regular graph from the Taylor's two-graph for `U_3(q)`, `q` odd + Return a strongly regular graph from the Taylor's two-graph for `U_3(q)`, + `q` odd This is a strongly regular graph with parameters `(v,k,\lambda,\mu)=(q^3+1, q(q^2+1)/2, (q^2+3)(q-1)/4, (q^2+1)(q+1)/4)` @@ -909,7 +915,6 @@ def TaylorTwographSRG(q): Taylor two-graph SRG: Graph on 28 vertices sage: t.is_strongly_regular(parameters=True) (28, 15, 6, 10) - """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) G.add_vertex(v0) @@ -919,7 +924,8 @@ def TaylorTwographSRG(q): def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): r""" - Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual + Return the collinearity graph of the generalized quadrangle `AS(q)`, or of + its dual Let `q` be an odd prime power. `AS(q)` is a generalized quadrangle (:wikipedia:`Generalized_quadrangle`) of @@ -936,8 +942,8 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): - ``q`` -- a power of an odd prime number - - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`. - Otherwise return the collinearity graph of the dual `AS(q)`. + - ``dual`` -- boolean (default: ``False``); whether to return the + collinearity graph of `AS(q)` or of the dual `AS(q)` (when ``True``) EXAMPLES:: @@ -952,7 +958,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): """ from sage.combinat.designs.incidence_structures import IncidenceStructure p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q must be an odd prime power') F = FiniteField(q, 'a') L = [] @@ -972,38 +978,39 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual + Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or + of its dual Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalized quadrangle (:wikipedia:`Generalized_quadrangle`) of order `(q-1,q+1)`, see 3.1.3 in [PT2009]_. Fix a plane `\Pi \subset \Theta` and a `hyperoval `__ - `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta` - outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` - that meet `\Pi` in a point of `O`. + `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of + `\Theta` outside `\Pi`, and the lines are the lines of `\Theta` outside + `\Pi` that meet `\Pi` in a point of `O`. INPUT: - ``q`` -- a power of two - - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`. - Otherwise return the graph of the dual `T_2^*(O)`. + - ``dual`` -- boolean (default: ``False``); whether to return the graph of + `T_2^*(O)` or of the dual `T_2^*(O)` (when ``True``) - - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane - meeting every line in 0 or 2 points) in the plane of points with 0th coordinate - 0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4 - vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and - ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval`` - we build is the classical one, i.e. a conic with the point of intersection of its - tangent lines. + - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in + the plane meeting every line in 0 or 2 points) in the plane of points with + 0th coordinate 0 in `PG(3,q)` over the field ``field``. Each point of + ``hyperoval`` must be a length 4 vector over ``field`` with 1st non-0 + coordinate equal to 1. By default, ``hyperoval`` and ``field`` are not + specified, and constructed on the fly. In particular, ``hyperoval`` we + build is the classical one, i.e. a conic with the point of intersection of + its tangent lines. - ``field`` -- an instance of a finite field of order `q`, must be provided - if ``hyperoval`` is provided. - - - ``check_hyperoval`` -- (default: ``True``) if ``True``, - check ``hyperoval`` for correctness. + if ``hyperoval`` is provided + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not EXAMPLES: @@ -1045,7 +1052,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG p, k = is_prime_power(q,get_data=True) - if k==0 or p!=2: + if not k or p != 2: raise ValueError('q must be a power of 2') if field is None: F = FiniteField(q, 'a') @@ -1090,16 +1097,16 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h of a strongly regular graph with parameters `(q^2(q+2),q^2+q-1,q-2,q)` from the graph of `T_2^*(q)^*`, constructed by :func:`~sage.graphs.graph_generators.GraphGenerators.T2starGeneralizedQuadrangleGraph`, - by redefining adjacencies in the way specified by an arbitrary ``hyperoval_matching`` - of the points (i.e. partitioning into size two parts) of ``hyperoval`` defining - `T_2^*(q)^*`. + by redefining adjacencies in the way specified by an arbitrary + ``hyperoval_matching`` of the points (i.e. partitioning into size two parts) + of ``hyperoval`` defining `T_2^*(q)^*`. While [BL1984]_ gives the construction in geometric terms, it can be formulated, and is implemented, in graph-theoretic ones, of re-adjusting the - edges. Namely, `G=T_2^*(q)^*` has a partition - into `q+2` independent sets `I_k` of size `q^2` each. Each vertex in `I_j` is - adjacent to `q` vertices from `I_k`. Each `I_k` is paired to some `I_{k'}`, - according to ``hyperoval_matching``. One adds edges `(s,t)` for `s,t \in I_k` whenever + edges. Namely, `G=T_2^*(q)^*` has a partition into `q+2` independent sets + `I_k` of size `q^2` each. Each vertex in `I_j` is adjacent to `q` vertices + from `I_k`. Each `I_k` is paired to some `I_{k'}`, according to + ``hyperoval_matching``. One adds edges `(s,t)` for `s,t \in I_k` whenever `s` and `t` are adjacent to some `u \in I_{k'}`, and removes all the edges between `I_k` and `I_{k'}`. @@ -1118,10 +1125,10 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h for more information. - ``field`` -- an instance of a finite field of order `q`, must be provided - if ``hyperoval`` is provided. + if ``hyperoval`` is provided - - ``check_hyperoval`` -- (default: ``True``) if ``True``, check - ``hyperoval`` for correctness. + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not EXAMPLES: @@ -1164,7 +1171,7 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h from itertools import combinations p, k = is_prime_power(q, get_data=True) - if k == 0 or p != 2: + if not k or p != 2: raise ValueError('q must be a power of 2') if hyperoval_matching is None: @@ -1175,7 +1182,9 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h F = field # for q=8, 95% of CPU time taken by this function is spent in the following call - G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, hyperoval=hyperoval, check_hyperoval=check_hyperoval) + G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, + hyperoval=hyperoval, + check_hyperoval=check_hyperoval) def normalize(v): # make sure the 1st non-0 coordinate is 1. d = next(x for x in v if x != F.zero()) @@ -1184,7 +1193,7 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. # build the partition into independent sets P = [tuple(normalize(v[0] - v[1])) for v in G.vertices()] O = list(set(P)) - I_ks = {x:[] for x in range(q+2)} # the partition into I_k's + I_ks = {x:[] for x in range(q+2)} # the partition into I_k's for i, Pi in enumerate(P): I_ks[O.index(tuple(Pi))].append(i) @@ -1195,7 +1204,7 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. Pij = set(I_ks[i]+I_ks[j]) for v in Pij: cliques.append(Pij.intersection(G.neighbors(v))) - G.delete_edges(G.edge_boundary(I_ks[i],I_ks[j])) # edges on (I_i,I_j) + G.delete_edges(G.edge_boundary(I_ks[i],I_ks[j])) # edges on (I_i,I_j) G.add_edges(e for c in cliques for e in combinations(c,2)) G.name('Haemers('+str(q)+')') return G @@ -1203,30 +1212,34 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. def CossidentePenttilaGraph(q): r""" - Cossidente-Penttila `((q^3+1)(q+1)/2,(q^2+1)(q-1)/2,(q-3)/2,(q-1)^2/2)`-strongly regular graph - - For each odd prime power `q`, one can partition the points of the `O_6^-(q)`-generalized - quadrangle `GQ(q,q^2)` into two parts, so that on any of them the induced subgraph of - the point graph of the GQ has parameters as above [CP2005]_. - - Directly following the construction in [CP2005]_ is not efficient, - as one then needs to construct the dual `GQ(q^2,q)`. Thus we - describe here a more efficient approach that we came up with, following a suggestion by - T.Penttila. Namely, this partition is invariant - under the subgroup `H=\Omega_3(q^2)3` one gets new graphs. :: - sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) + sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (378, 52, 1, 8) TESTS:: - sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time + sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time + sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): @@ -1257,14 +1270,14 @@ def CossidentePenttilaGraph(q): ValueError: q(=2) must be an odd prime power """ p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q(={}) must be an odd prime power'.format(q)) from sage.features.gap import GapPackage GapPackage("grape", spkg="gap_packages").require() from sage.libs.gap.libgap import libgap - adj_list=libgap.function_factory("""function(q) + adj_list = libgap.function_factory("""function(q) local z, e, so, G, nu, G1, G0, B, T, s, O1, O2, x; LoadPackage("grape"); G0:=SO(3,q^2); @@ -1298,41 +1311,42 @@ def CossidentePenttilaGraph(q): def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval. + Return the subgraph of nowhere 0 words from two-weight code of projective + plane hyperoval. Let `q=2^k` and `\Pi=PG(2,q)`. Fix a `hyperoval `__ - `O \subset \Pi`. Let `V=F_q^3` and `C` the two-weight 3-dimensional linear code - over `F_q` with words `c(v)` obtained from `v\in V` by computing + `O \subset \Pi`. Let `V=F_q^3` and `C` the two-weight 3-dimensional linear + code over `F_q` with words `c(v)` obtained from `v\in V` by computing .. MATH:: c(v)=(\langle v,o_1 \rangle,...,\langle v,o_{q+2} \rangle), o_j \in O. - `C` contains `q(q-1)^2/2` words without 0 entries. The subgraph of the strongly - regular graph of `C` induced on the latter words is also strongly regular, - assuming `q>4`. This is a construction due to A.E.Brouwer [Bro2016]_, and - leads to graphs with parameters also given by a construction in [HHL2009]_. - According to [Bro2016]_, these two constructions are likely to produce - isomorphic graphs. + `C` contains `q(q-1)^2/2` words without 0 entries. The subgraph of the + strongly regular graph of `C` induced on the latter words is also strongly + regular, assuming `q>4`. This is a construction due to A.E.Brouwer + [Bro2016]_, and leads to graphs with parameters also given by a construction + in [HHL2009]_. According to [Bro2016]_, these two constructions are likely + to produce isomorphic graphs. INPUT: - ``q`` -- a power of two - - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane - meeting every line in 0 or 2 points) in `PG(2,q)` over the field ``field``. - Each point of ``hyperoval`` must be a length 3 - vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and - ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval`` - we build is the classical one, i.e. a conic with the point of intersection of its - tangent lines. + - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in + the plane meeting every line in 0 or 2 points) in `PG(2,q)` over the field + ``field``. Each point of ``hyperoval`` must be a length 3 vector over + ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` + and ``field`` are not specified, and constructed on the fly. In + particular, ``hyperoval`` we build is the classical one, i.e. a conic with + the point of intersection of its tangent lines. - ``field`` -- an instance of a finite field of order `q`, must be provided if ``hyperoval`` is provided. - - ``check_hyperoval`` -- (default: ``True``) if ``True``, - check ``hyperoval`` for correctness. + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not .. SEEALSO:: @@ -1347,7 +1361,7 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) - sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) + sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) (1800, 728, 268, 312) @@ -1378,9 +1392,9 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov from sage.matrix.constructor import matrix p, k = is_prime_power(q,get_data=True) - if k==0 or p!=2: + if not k or p != 2: raise ValueError('q must be a power of 2') - if k<3: + if k < 3: raise ValueError('q must be a at least 8') if field is None: F = FiniteField(q, 'a') @@ -1399,7 +1413,7 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov O = set(hyperoval) if check_hyperoval: - if len(O) != q+2: + if len(O) != q + 2: raise RuntimeError("incorrect hyperoval size") for L in Theta.blocks(): if set(L).issubset(Pi): @@ -1419,11 +1433,11 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov def OrthogonalDualPolarGraph(e, d, q): r""" - Return dual polar graph on $GO^e(n,q)$ of diameter `d`. + Return the dual polar graph on $GO^e(n,q)$ of diameter `d`. + The value of `n` is determined by `d` and `e`. - The graph is distance-regular with classical parameters - `(d, q, 0, q^e)`. + The graph is distance-regular with classical parameters `(d, q, 0, q^e)`. INPUT: From 465a187c653d77bf8acaec30da58ec7698448c91 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 26 Sep 2021 17:20:42 +0200 Subject: [PATCH 254/355] trac #22003: number of faces of trees and disconnected graphs --- src/sage/graphs/generic_graph.py | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee9191b90a6..366d0868666 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5927,6 +5927,21 @@ def num_faces(self, embedding=None): sage: T.num_faces() 4 + The external face of a disconnected graph is counted only once:: + + sage: (T + T).num_faces() + 7 + sage: (T + T + T).num_faces() + 10 + + Trees and forests have a single face:: + + sage: T = graphs.RandomTree(10) + sage: T.num_faces() + 1 + sage: (T + T).num_faces() + 1 + TESTS:: sage: G = graphs.CompleteBipartiteGraph(3, 3) @@ -5934,8 +5949,36 @@ def num_faces(self, embedding=None): Traceback (most recent call last): ... ValueError: no embedding is provided and the graph is not planar + + Ticket :trac:`22003` is fixed: + + sage: Graph(1).num_faces() + 1 """ - return len(self.faces(embedding)) + if not self: + return 0 + if self.is_connected(): + if self.order() == self.size() + 1: + # a tree has a single face + return 1 + return len(self.faces(embedding)) + + if embedding is None: + # get_embedding() raises an error if no (valid) embedding is set + try: + embedding = self.get_embedding() + except: + pass + + # We compute the number Fc of faces of each connected component c. + # The number of faces of the graph is the sum of the Fc values minus the + # number of connected components minus 1 to ensure that the external + # face is counted only once. That is, 1 + sum_{c} (Fc - 1). + F = 1 + for g in self.connected_components_subgraphs(): + emb = None if embedding is None else {v: embedding[v] for v in g} + F += g.num_faces(emb) - 1 + return F def planar_dual(self, embedding=None): """ @@ -6021,12 +6064,12 @@ def planar_dual(self, embedding=None): from sage.graphs.graph import Graph from itertools import combinations - verts = [tuple(f) for f in self.faces()] + verts = [tuple(f) for f in self.faces(embedding=embedding)] edges = [] for v1, v2 in combinations(verts, 2): e = set([tuple(reversed(e)) for e in v1]).intersection(v2) if e: - e = e.pop() # just one edge since self and its dual are simple + e = e.pop() # just one edge since self and its dual are simple edges.append([v1, v2, self.edge_label(e[0], e[1])]) return Graph([verts, edges]) From 80d05ec95eafbe0535e1cf6514060fc851c5e1bc Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 26 Sep 2021 20:45:36 +0200 Subject: [PATCH 255/355] trac #32569: review comment --- src/sage/graphs/generators/classical_geometries.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 67805a34d1a..d8b8e18bf47 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -655,11 +655,11 @@ def NonisotropicUnitaryPolarGraph(m, q): r""" Return the Graph `NU(m,q)`. - Returns the graph on nonisotropic, with respect to a nondegenerate Hermitean - form, points of the `(m-1)`-dimensional projective space over `F_q`, with - points adjacent whenever they lie on a tangent (to the set of isotropic - points) line. For more information, see Sect. 9.9 of [BH2012]_ and series - C14 in [Hub1975]_. + This returns the graph on nonisotropic, with respect to a nondegenerate + Hermitean form, points of the `(m-1)`-dimensional projective space over + `F_q`, with points adjacent whenever they lie on a tangent (to the set of + isotropic points) line. For more information, see Sect. 9.9 of [BH2012]_ + and series C14 in [Hub1975]_. INPUT: From 5b48191d2feb590cd8650c0050c9a30515a861f6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 27 Sep 2021 14:30:27 +0200 Subject: [PATCH 256/355] fix encoding --- src/sage/rings/lazy_series.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 381eab9df7d..398044c95d3 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Lazy Series From d4eb6cd2b312a5bacdeb020797fad75203c869c3 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 27 Sep 2021 10:44:13 -0400 Subject: [PATCH 257/355] fix small error --- src/sage/modular/quasimodform/element.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index acbc380c3ac..a5d18385fca 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -340,8 +340,7 @@ def is_modular_form(self): sage: QM.zero().is_modular_form() True """ -<<<<<<< HEAD - return not self._polynomial.degree() and self._polynomial[0].is_modular_form() + return self._polynomial.degree() <= 0 and self._polynomial[0].is_modular_form() def to_polynomial(self, names='E2, E4, E6'): r""" @@ -457,6 +456,3 @@ def homogeneous_components(self): poly_self = self.to_polynomial() pol_hom_comp = poly_self.homogeneous_components() return { k : QM.from_polynomial(pol) for k, pol in pol_hom_comp.items()} -======= - return self._polynomial.degree() <= 0 and self._polynomial[0].is_modular_form() ->>>>>>> develop From a686947b211baa6ee2882984779ff37c3373f9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Sep 2021 17:50:50 +0200 Subject: [PATCH 258/355] more pycodestyle checks, and make them pass --- src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py | 4 ++-- src/sage/groups/braid.py | 2 +- src/sage/schemes/elliptic_curves/hom.py | 8 +++++--- src/tox.ini | 5 ++++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index bbec2269143..8f8578ef8b9 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -258,13 +258,13 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): if not isinstance(morphism_domain.base_ring(), pAdicBaseGeneric): if morphism_domain.base_ring() in NumberFields(): - if domain is None and ideal != None: + if domain is None and ideal is not None: if is_AffineSpace(morphism_domain): domain = Berkovich_Cp_Affine(morphism_domain.base_ring(), ideal) else: domain = Berkovich_Cp_Projective(morphism_domain, ideal) else: - if ideal != None: + if ideal is not None: if ideal != domain.ideal(): raise ValueError('conflicting inputs for ideal and domain') else: diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 0011358343e..c55749c1cad 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -1092,7 +1092,7 @@ def _enhanced_states(self): last_crossing_in_row[abs(cr)] = i # tie up the ends of the list for k, i in enumerate(first_crossing_in_row): - if i != None: + if i is not None: j = last_crossing_in_row[k] if abs(crossings[i]["cr"]) == k: crossings[i]["prev_below"] = j diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 985da715a2f..cd6b328353b 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -12,6 +12,7 @@ from sage.categories.morphism import Morphism + class EllipticCurveHom(Morphism): """ Base class for elliptic-curve morphisms. @@ -67,11 +68,12 @@ def _composition_(self, other, homset): raise TypeError(f'cannot compose {type(self)} with {type(other)}') ret = self._composition_impl(self, other) - if ret is not NotImplemented: return ret + if ret is not NotImplemented: + return ret ret = other._composition_impl(self, other) - if ret is not NotImplemented: return ret + if ret is not NotImplemented: + return ret # fall back to generic formal composite map return Morphism._composition_(self, other, homset) - diff --git a/src/tox.ini b/src/tox.ini index dc773b0973d..668483ce6a4 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -79,10 +79,13 @@ description = # E401: multiple imports on one line # E701: multiple statements on one line (colon) # E702: multiple statements on one line (semicolon) + # E703: statement ends with a semicolon # W605: invalid escape sequence ‘x’ + # E711: comparison to None should be ‘if cond is None:’ + # E712: comparison to True should be ‘if cond is True:’ or ‘if cond:’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E401,E701,E702,W605 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E401,E70,W605,E711,E712 {posargs:{toxinidir}/sage/} [pycodestyle] max-line-length = 160 From 8d3e5395362a23b6f132e87f76d715c5de1f4cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Sep 2021 18:16:24 +0200 Subject: [PATCH 259/355] changing is not a Lie algebra + TypeError: codomain is not a Lie algebra sage: from sage.algebras.lie_algebras.morphism import LieAlgebraMorphism_from_generators sage: LieAlgebraMorphism_from_generators({ZZ(1): X}) diff --git a/src/sage/all.py b/src/sage/all.py index 4fa89329e81..954b0c0972d 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -41,7 +41,7 @@ Check lazy import of ``interacts``:: sage: type(interacts) - + sage: interacts """ diff --git a/src/sage/arith/functions.pyx b/src/sage/arith/functions.pyx index 74b95dee846..8d1d25528f8 100644 --- a/src/sage/arith/functions.pyx +++ b/src/sage/arith/functions.pyx @@ -145,14 +145,14 @@ cpdef LCM_list(v): sage: w = LCM_list([3,9,30]); w 90 sage: type(w) - + The inputs are converted to Sage integers:: sage: w = LCM_list([int(3), int(9), int(30)]); w 90 sage: type(w) - + TESTS:: diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 039e786aff7..7ec6d49bbfd 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -807,7 +807,7 @@ def prime_powers(start, stop=None): sage: v = prime_powers(10) sage: type(v[0]) - + sage: prime_powers(0,1) [] @@ -1365,9 +1365,9 @@ def random_prime(n, proof=None, lbound=2): TESTS:: sage: type(random_prime(2)) - + sage: type(random_prime(100)) - + sage: random_prime(1, lbound=-2) #caused Sage hang #10112 Traceback (most recent call last): ... @@ -1715,7 +1715,7 @@ def gcd(a, b=None, **kwargs): sage: gcd([]) 0 sage: type(gcd([])) - + TESTS: @@ -2963,7 +2963,7 @@ class Euler_Phi: sage: euler_phi(0) 0 sage: type(euler_phi(0)) - + We verify directly that the phi function is correct for 21. @@ -3472,22 +3472,22 @@ def binomial(x, m, **kwds): sage: a = binomial(float(1001), float(1)); a 1001.0 sage: type(a) - <... 'float'> + sage: binomial(float(1000), 1001) 0.0 Test more output types:: sage: type(binomial(5r, 2)) - <... 'int'> + sage: type(binomial(5, 2r)) - + sage: type(binomial(5.0r, 2)) - <... 'float'> + sage: type(binomial(5/1, 2)) - + sage: R = Integers(11) sage: b = binomial(R(7), R(3)) @@ -5756,7 +5756,7 @@ def squarefree_divisors(x): sage: a 1 sage: type(a) - + Tests with numpy and gmpy2 numbers:: diff --git a/src/sage/arith/srange.pyx b/src/sage/arith/srange.pyx index ccbfd98cb98..1603b87ca68 100644 --- a/src/sage/arith/srange.pyx +++ b/src/sage/arith/srange.pyx @@ -223,7 +223,7 @@ def srange(*args, **kwds): sage: v = srange(5); v [0, 1, 2, 3, 4] sage: type(v[2]) - + sage: srange(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9] sage: srange(10, 1, -1) diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index 1f89c3f7ffe..081d331c1b2 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -51,13 +51,13 @@ def symbolic_expression(x): sage: a = symbolic_expression(3/2); a 3/2 sage: type(a) - + sage: R. = QQ[]; type(x) - + sage: a = symbolic_expression(2*x^2 + 3); a 2*x^2 + 3 sage: type(a) - + sage: from sage.symbolic.expression import is_Expression sage: is_Expression(a) True diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 80e4a5de019..e2fd04d246c 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -40,7 +40,7 @@ sage: x^2 x^2 sage: type(x) - + More complicated expressions in Sage can be built up using ordinary arithmetic. The following are valid, and follow the rules of Python diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index b368ea28c50..1c81a072f0e 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -91,7 +91,6 @@ cdef class Spline: Traceback (most recent call last): ... ValueError: Order of derivative must be 1 or 2. - """ def __init__(self, v=[]): """ @@ -100,7 +99,7 @@ cdef class Spline: sage: S = spline([(1,1), (2,3), (4,5)]); S [(1, 1), (2, 3), (4, 5)] sage: type(S) - + """ self.v = list(v) self.started = 0 diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 86f93667040..1f0f9790a53 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -152,7 +152,7 @@ sage: type(t1) sage: type(t2) - + sage: t1, t2 (omega + x, omega + x) sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) @@ -162,7 +162,7 @@ sin(y) + cos(x) sage: e=e._sage_() sage: type(e) - + sage: e cos(x) + sin(y) sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 diff --git a/src/sage/calculus/var.pyx b/src/sage/calculus/var.pyx index 70ec9487868..85359ac098d 100644 --- a/src/sage/calculus/var.pyx +++ b/src/sage/calculus/var.pyx @@ -112,7 +112,7 @@ def var(*args, **kwds): to the symbolic expression ring:: sage: type(theta) - + sage: parent(theta) Symbolic Ring """ diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 59f3ee7ac99..44366e35a84 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -348,9 +348,9 @@ class inheritance from ``C.parent_class``. sage: D.__class__.mro() [, , - , - , - , + , + , + , , , , diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index c1ba98b6b4a..cf612f9a447 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -218,8 +218,8 @@ class Category_singleton(Category): , , , - , - , + , + , , , , diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index 8a948f827b4..e9afe0736f4 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -345,11 +345,11 @@ def __classget__(cls, base_category, base_category_class): It also forces the resolution of lazy imports (see :trac:`15648`):: sage: type(Algebras.__dict__["Graded"]) - + sage: Algebras.Graded sage: type(Algebras.__dict__["Graded"]) - + .. TODO:: diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index 56454fe5603..1be62053555 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -117,7 +117,7 @@ def degree_on_basis(self, t): sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) 10 sage: type(A.degree_on_basis(Partition((1,1)))) - + """ return t.size() diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 4550e1a2fc0..0374b723a71 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -1,12 +1,12 @@ r""" Examples of a finite dimensional Lie algebra with basis """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -16,6 +16,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.examples.lie_algebras import LieAlgebraFromAssociative as BaseExample + class AbelianLieAlgebra(Parent, UniqueRepresentation): r""" An example of a finite dimensional Lie algebra with basis: diff --git a/src/sage/categories/examples/graded_modules_with_basis.py b/src/sage/categories/examples/graded_modules_with_basis.py index 35314866ea4..0be39623fa3 100644 --- a/src/sage/categories/examples/graded_modules_with_basis.py +++ b/src/sage/categories/examples/graded_modules_with_basis.py @@ -131,7 +131,7 @@ def degree_on_basis(self, t): sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) 10 sage: type(A.degree_on_basis(Partition((1,1)))) - + """ return t.size() diff --git a/src/sage/categories/examples/infinite_enumerated_sets.py b/src/sage/categories/examples/infinite_enumerated_sets.py index 850bb4385e3..d606c9274da 100644 --- a/src/sage/categories/examples/infinite_enumerated_sets.py +++ b/src/sage/categories/examples/infinite_enumerated_sets.py @@ -1,18 +1,19 @@ """ Examples of infinite enumerated sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer import Integer + class NonNegativeIntegers(UniqueRepresentation, Parent): r""" An example of infinite enumerated set: the non negative integers @@ -31,12 +32,12 @@ class NonNegativeIntegers(UniqueRepresentation, Parent): ... NotImplementedError: cannot list an infinite set sage: NN.element_class - + sage: it = iter(NN) sage: [next(it), next(it), next(it), next(it), next(it)] [0, 1, 2, 3, 4] sage: x = next(it); type(x) - + sage: x.parent() Integer Ring sage: x+3 @@ -176,7 +177,7 @@ def _element_constructor_(self, i): sage: x = NN(42); x 42 sage: type(x) - + sage: x.parent() Integer Ring """ diff --git a/src/sage/categories/examples/semigroups_cython.pyx b/src/sage/categories/examples/semigroups_cython.pyx index 931ce2fdc03..6b6e179bc3a 100644 --- a/src/sage/categories/examples/semigroups_cython.pyx +++ b/src/sage/categories/examples/semigroups_cython.pyx @@ -79,7 +79,7 @@ cdef class LeftZeroSemigroupElement(Element): sage: S = LeftZeroSemigroup() sage: x = S(3) sage: x.__reduce__() - (, + (, (An example of a semigroup: the left zero semigroup, 3)) """ return LeftZeroSemigroupElement, (self._parent, self._value) diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index 5a691d46792..c2fba4de679 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -1,12 +1,12 @@ """ Examples of sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.structure.element import Element @@ -44,7 +44,7 @@ class PrimeNumbers(UniqueRepresentation, Parent): sage: x = P(13); x 13 sage: type(x) - + sage: x.parent() Integer Ring sage: 13 in P @@ -54,7 +54,7 @@ class PrimeNumbers(UniqueRepresentation, Parent): sage: y = x+1; y 14 sage: type(y) - + sage: TestSuite(P).run(verbose=True) running ._test_an_element() . . . pass @@ -334,13 +334,13 @@ class PrimeNumbers_Inherits(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: y.parent() Integer Ring sage: type(P(13)+P(17)) - + sage: type(P(2)+P(3)) - + sage: z = P.next(x); z 17 @@ -385,9 +385,9 @@ def __init__(self): sage: P = Sets().example("inherits") sage: type(P(13)+P(17)) - + sage: type(P(2)+P(3)) - + """ super(PrimeNumbers_Inherits, self).__init__() self._populate_coercion_lists_(embedding=IntegerRing()) @@ -468,7 +468,7 @@ class PrimeNumbers_Wrapper(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: z = P.next(x); z 17 @@ -579,7 +579,7 @@ class PrimeNumbers_Facade(PrimeNumbers_Abstract): sage: x = P(13); x 13 sage: type(x) - + sage: x.parent() Integer Ring sage: 13 in P @@ -589,12 +589,12 @@ class PrimeNumbers_Facade(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: z = P.next(x); z 17 sage: type(z) - + sage: z.parent() Integer Ring diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index c3a5506db8d..c796801944d 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -6,15 +6,15 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # 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.abstract_method import abstract_method @@ -28,6 +28,7 @@ from sage.sets.family import Family from sage.matrix.constructor import matrix + class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ Category of finite dimensional Lie algebras with a basis. @@ -196,7 +197,7 @@ def _basis_key(self, x): sage: sl2.indices() {'e1', 'f1', 'h1'} sage: type(sl2.basis().keys()) - + sage: Usl2 = sl2.pbw_basis() sage: Usl2._basis_key(2) 2 diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 1e4620ab12d..0f423dbb5de 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -124,7 +124,7 @@ def _cardinality_from_iterator(self, *ignored_args, **ignored_kwds): does not do it for us:: sage: type(C._cardinality_from_iterator()) - + We ignore additional inputs since during doctests classes which override ``cardinality()`` call up to the category rather than diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 2e28f84f1f1..d9a4c21a00d 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -1040,7 +1040,7 @@ def element_class_set_morphism(self): sage: H = Hom(ZZ, ZZ) sage: H.element_class_set_morphism - + """ return self.__make_element_class__(morphism.SetMorphism) diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index 5d2952c8bac..182a5929c9a 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -1,4 +1,4 @@ -## -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- r""" Homset categories """ diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index a74ab9ee525..c63a7b71639 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -155,7 +155,7 @@ cdef class Map(Element): sage: phi.domain sage: type(phi) - + sage: psi = copy(phi) # indirect doctest sage: psi Composite map: @@ -796,7 +796,7 @@ cdef class Map(Element): sage: f(1/2) # indirect doctest Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ raise NotImplementedError(type(self)) @@ -811,7 +811,7 @@ cdef class Map(Element): sage: f(1/2, 2, foo='bar') # indirect doctest Traceback (most recent call last): ... - NotImplementedError: _call_with_args not overridden to accept arguments for + NotImplementedError: _call_with_args not overridden to accept arguments for """ if not args and not kwds: return self(x) @@ -1185,7 +1185,7 @@ cdef class Map(Element): sage: f.is_surjective() Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ raise NotImplementedError(type(self)) @@ -1278,7 +1278,7 @@ cdef class Map(Element): sage: f = sage.rings.morphism.RingMap(ZZ.Hom(ZZ)) sage: type(f) - + sage: hash(f) == hash(f) True sage: {f: 1}[f] @@ -1310,7 +1310,7 @@ cdef class Section(Map): sage: sf(a) Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ def __init__(self, map): diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index 2149f1d8cb8..f9a8f35252c 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -398,7 +398,7 @@ class implements: sage: i = 12 sage: type(i) - + Applying an operation is generally done by *calling a method*:: @@ -408,7 +408,7 @@ class implements: sage: x = var('x') sage: p = 6*x^2 + 12*x + 6 sage: type(p) - + sage: p.factor() 6*(x + 1)^2 @@ -421,7 +421,7 @@ class implements: sage: pZ = ZZ['x'] ( p ) sage: type(pZ) - + sage: pZ.factor() 2 * 3 * (x + 1)^2 diff --git a/src/sage/categories/quotient_fields.py b/src/sage/categories/quotient_fields.py index 7198e394643..41acdaf3735 100644 --- a/src/sage/categories/quotient_fields.py +++ b/src/sage/categories/quotient_fields.py @@ -215,7 +215,7 @@ def lcm(self, other): sage: (1/2).lcm(2) 2 sage: type((1/2).lcm(2)) - + """ P = self.parent() try: diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 7e8cdc95146..cf9388290fa 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -118,10 +118,10 @@ class Sets(Category_singleton): - - - - + + + + @@ -169,18 +169,18 @@ class Sets(Category_singleton): sage: for cl in x.__class__.mro(): print(cl) - - - - - - - - - + + + + + + + + + - - + + @@ -954,7 +954,7 @@ def _element_constructor_(self): sage: A = FreeModule(QQ, 3) sage: A.element_class - + sage: A._element_constructor_ diff --git a/src/sage/cpython/cython_metaclass.pyx b/src/sage/cpython/cython_metaclass.pyx index 11294c2bb97..e3a00bdecb5 100644 --- a/src/sage/cpython/cython_metaclass.pyx +++ b/src/sage/cpython/cython_metaclass.pyx @@ -76,13 +76,13 @@ EXAMPLES:: ....: cdef class MyDerivedType(MyCustomType): ....: pass ....: ''') - Calling MyMetaclass.__init__(, None, None, None) - Calling MyMetaclass.__init__(, None, None, None) + Calling MyMetaclass.__init__(, None, None, None) + Calling MyMetaclass.__init__(, None, None, None) sage: MyCustomType.__class__ sage: class MyPythonType(MyDerivedType): ....: pass - Calling MyMetaclass.__init__(, 'MyPythonType', (,), {...}) + Calling MyMetaclass.__init__(, 'MyPythonType', (,), {...}) Implementation ============== diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index a8aa0f48fbb..e4f75062412 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -1387,7 +1387,7 @@ cdef class BooleanFunctionIterator: sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction(3) sage: type(B.__iter__()) - + """ self.f = f self.index = -1 diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 1d1e375e6cc..44b7185f43e 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -375,7 +375,7 @@ def carmichael_lambda(n): sage: from sage.crypto.util import carmichael_lambda sage: type(carmichael_lambda(16)) - + REFERENCES: diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index a5704d624cb..988a6a1be02 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1604,7 +1604,7 @@ def element(self, key): sage: e = P.element(42); e 42 sage: type(e) - + .. SEEALSO:: @@ -1850,9 +1850,9 @@ def elements(self, **kwargs): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP([3, 42, 7]) sage: [(v, type(v)) for v in sorted(P.elements())] - [(3, ), - (7, ), - (42, )] + [(3, ), + (7, ), + (42, )] Note that @@ -1937,14 +1937,14 @@ def keys(self, **kwargs): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP([3, 42, 7], key=lambda c: -c) sage: [(v, type(v)) for v in sorted(P.keys())] - [(-42, ), - (-7, ), - (-3, )] + [(-42, ), + (-7, ), + (-3, )] sage: [(v, type(v)) for v in sorted(P.elements())] - [(3, ), - (7, ), - (42, )] + [(3, ), + (7, ), + (42, )] sage: [(v, type(v)) for v in sorted(P.shells(), ....: key=lambda c: c.element)] @@ -1984,9 +1984,9 @@ def keys_topological(self, **kwargs): sage: P = MP([(1, 1), (2, 1), (4, 4)], ....: key=lambda c: c[0]) sage: [(v, type(v)) for v in P.keys_topological(key=repr)] - [(1, ), - (2, ), - (4, )] + [(1, ), + (2, ), + (4, )] sage: [(v, type(v)) for v in P.elements_topological(key=repr)] [((1, 1), <... 'tuple'>), ((2, 1), <... 'tuple'>), diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 11d4b652ceb..d16ea7b5ed0 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -614,9 +614,9 @@ cdef class ExpressionTreeBuilder: sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder('x') sage: v = etb(3); v, type(v) - (3, ) + (3, ) sage: v = etb(polygen(QQ)); v, type(v) - (v_0, ) + (v_0, ) sage: v is etb(v) True """ @@ -1084,7 +1084,7 @@ cdef class ExpressionConstant(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb(3)) - + """ cdef object _value @@ -1152,7 +1152,7 @@ cdef class ExpressionVariable(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var(x)) - + """ cdef int _variable_index @@ -1219,7 +1219,7 @@ cdef class ExpressionCall(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.call(sin, x)) - + """ cdef object _function cdef object _arguments @@ -1308,7 +1308,7 @@ cdef class ExpressionIPow(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var('x')^17) - + """ cdef object _base cdef object _exponent @@ -1708,7 +1708,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: instr_stream.instr('return') sage: v = Wrapper_py(instr_stream.get_current()) sage: type(v) - + sage: v(7) 8*pi + 56 @@ -1980,7 +1980,7 @@ cdef class InstructionStream: 'stack': 0} sage: md = instr_stream.get_metadata() sage: type(md) - + sage: md.by_opname['py_call'] (CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']), 3) sage: md.by_opcode[3] @@ -2154,7 +2154,7 @@ cdef class InstructionStream: sage: instr_stream = InstructionStream(metadata, 1) sage: md = instr_stream.get_metadata() sage: type(md) - + """ return self._metadata diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index c2f196c70ac..3f745d7a238 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -334,7 +334,7 @@ def __init__(self): sage: ceil(5.4) 6 sage: type(ceil(5.4)) - + :: @@ -483,7 +483,7 @@ def __init__(self): sage: floor(5.4) 5 sage: type(floor(5.4)) - + sage: var('x') x sage: a = floor(5.4 + x); a @@ -693,7 +693,7 @@ def __init__(self): sage: frac(5.4) 0.400000000000000 sage: type(frac(5.4)) - + sage: frac(456/123) 29/41 sage: var('x') @@ -1245,7 +1245,7 @@ def __init__(self): sage: real(a) 2.50000000000000 sage: type(real(a)) - + sage: real(1.0r) 1.0 sage: real(complex(3, 4)) @@ -1629,7 +1629,7 @@ def _eval_(self, x): sage: factorial(float(3.2)) # abs tol 1e-14 7.7566895357931776 sage: type(factorial(float(3.2))) - + """ if isinstance(x, Integer): try: @@ -1803,9 +1803,9 @@ def _eval_(self, n, k): sage: binomial._eval_(5, 3) 10 sage: type(binomial._eval_(5, 3)) - + sage: type(binomial._eval_(5., 3)) - + sage: binomial._eval_(x, 3) 1/6*(x - 1)*(x - 2)*x sage: binomial._eval_(x, x-2) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 5df1a220cd3..dd1fb496861 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -1473,9 +1473,9 @@ def _run_it_on_static_instead(f): sage: Graph.new_graph_method = new_graph_method sage: g = Graph(5) sage: print("My backend is of type {}".format(type(g._backend))) - My backend is of type + My backend is of type sage: g.new_graph_method() - My backend is of type + My backend is of type """ def same_function_on_static_version(*kwd, **kwds): if not isinstance(kwd[0]._backend, StaticSparseBackend): @@ -1485,4 +1485,3 @@ def _run_it_on_static_instead(f): return f(*kwd, **kwds) return same_function_on_static_version - diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6a966a01e3f..1c0e5e0646f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -541,7 +541,7 @@ def __add__(self, other): sage: G+42 Traceback (most recent call last): ... - TypeError: adding and is not defined + TypeError: adding and is not defined """ if isinstance(other, GenericGraph): return self.disjoint_union(other, labels='integers') diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index 3a36993927b..b06df8af2f7 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -912,7 +912,7 @@ def lift(self): sage: m.lift() 3 sage: type(m.lift()) - + """ return self.value diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index 8f7154137ad..cea6bd62fd4 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -140,7 +140,7 @@ cdef class PPLBackend(GenericBackend): sage: p.base_ring() Rational Field sage: type(p.zero()) - + sage: p.init_mip() """ diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 6d0c0604c37..d152bc407a4 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -11,12 +11,12 @@ either equalities or less-or-equal. For example:: sage: f = 1 + x[1] + 2*x[2]; f # a linear function 1 + x_0 + 2*x_1 sage: type(f) - + sage: c = (0 <= f); c # a constraint 0 <= 1 + x_0 + 2*x_1 sage: type(c) - + Note that you can use this module without any reference to linear programming, it only implements linear functions over a base ring and @@ -529,7 +529,7 @@ cdef class LinearFunctionsParent_class(Parent): sage: from sage.numerical.linear_functions import LinearFunctionsParent_class sage: LinearFunctionsParent_class - + """ def __cinit__(self): """ @@ -675,7 +675,7 @@ cdef class LinearFunctionsParent_class(Parent): sage: LF(123) # indirect doctest 123 sage: type(_) - + sage: p_QQ = MixedIntegerLinearProgram(solver='ppl') sage: LF_QQ = p_QQ.linear_functions_parent() @@ -1039,7 +1039,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): sage: p = MixedIntegerLinearProgram() sage: LF = p.linear_functions_parent() sage: f = LF(1); type(f) - + sage: f._coeff_formatter(1) '' sage: f._coeff_formatter(1, constant_term=True) @@ -1302,7 +1302,7 @@ cdef class LinearConstraintsParent_class(Parent): x_0 == x_1 == x_2 sage: type(_) - + TESTS:: diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index ffc253494db..bdf9529659a 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -387,7 +387,7 @@ def _element_constructor_(self, x): sage: LT({1:[1, 2]}) # indirect doctest (1.0, 2.0)*x_1 sage: type(_) - + Construct from scalar: diff --git a/src/sage/numerical/linear_tensor_element.pyx b/src/sage/numerical/linear_tensor_element.pyx index 597f96f953b..f04949d6c02 100644 --- a/src/sage/numerical/linear_tensor_element.pyx +++ b/src/sage/numerical/linear_tensor_element.pyx @@ -7,17 +7,17 @@ Here is an example of a linear function tensored with a vector space:: sage: lt = x[0] * vector([3,4]) + 1; lt (1, 1) + (3, 4)*x_0 sage: type(lt) - + """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun # # 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/ +# **************************************************************************** from cpython.object cimport * diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index de3a5569ba5..2642b091f14 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -244,7 +244,7 @@ def __call__(self, obj, p, cycle): sage: from sage.repl.display.fancy_repr import PlainPythonRepr sage: pp = PlainPythonRepr() sage: pp.format_string(type(1)) - "" + "" Do not swallow a trailing newline at the end of the output of a custom representer. Note that it is undesirable to have a diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index 0948bdd6096..804115051ed 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -92,14 +92,14 @@ def __init__(self, output, max_width, newline, max_seq_length=None): sage: 'this is a string' 'this is a string' sage: type(123) - + sage: type <... 'type'> sage: import types sage: type('name', (), {}) sage: types.BuiltinFunctionType - + sage: def foo(): pass sage: foo diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e5ac7f7ab73..206f152880f 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -86,11 +86,11 @@ Raw and hex work correctly:: sage: type(0xa1) - + sage: type(0xa1r) - + sage: type(0Xa1R) - + The preparser can handle PEP 515 (see :trac:`28490`):: @@ -165,7 +165,7 @@ sage: a 393939 sage: type(a) - + We create a raw float:: @@ -173,7 +173,7 @@ sage: z 1.5949 sage: type(z) - + You can also use an upper case letter:: @@ -181,7 +181,7 @@ sage: z 3.1415 sage: type(z) - + This next example illustrates how raw literals can be very useful in certain cases. We make a list of even integers up to 10000:: diff --git a/src/sage/sets/finite_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index 4066668b9ac..ec8f6e3968a 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -368,7 +368,7 @@ def __call__(self, el): sage: S(1) 1 sage: type(S(1)) - + """ if not isinstance(el, Element): return self._element_constructor_(el) diff --git a/src/sage/tensor/modules/free_module_morphism.py b/src/sage/tensor/modules/free_module_morphism.py index 3451b2c0554..404a91e38d1 100644 --- a/src/sage/tensor/modules/free_module_morphism.py +++ b/src/sage/tensor/modules/free_module_morphism.py @@ -1051,7 +1051,7 @@ def matrix(self, basis1=None, basis2=None): [-1 2 0] [ 5 1 2] sage: type(phi.matrix()) - + Matrix in bases different from those in which the homomorphism has been defined:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py index bd0d9ab10f7..518e958cad4 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -152,7 +152,7 @@ sage: mpmath.quad(f, [0, 1]) Traceback (most recent call last): ... - TypeError: no canonical coercion from to ... + TypeError: no canonical coercion from to ... Sage example in ./integration.tex, line 866:: From 7bf519b89c284dddda054b7d950e37cfd28d2a85 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 27 Sep 2021 18:32:01 +0200 Subject: [PATCH 260/355] adapt doctests, add a (currently failing) doctest --- src/sage/rings/lazy_series_ring.py | 53 ++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 35e1c921dfc..cfbf0cf31a7 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -57,7 +57,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No INPUT: - - ``x`` -- data used to the define a Laurent series + - ``x`` -- data used to the define a series - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - ``degree`` -- (optional) the degree when the series is ``constant`` @@ -66,9 +66,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No coefficients of the series; must be ``None`` if ``x`` is provided; see note below - If ``valuation`` is specified and ``x`` is convertible into a Laurent - polynomial or is a lazy Laurent series, then the data is shifted so - that the result has the specified valuation. + If ``valuation`` is specified and ``x`` is convertible into + an element of the underlying ring corresponding to series + with finite support or ``x`` is a lazy series of the same + parent, then the data is shifted so that the result has the + specified valuation. .. WARNING:: @@ -82,9 +84,19 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No input, then passing a function as ``x`` might be converted to the base ring. If instead the input is to be treated as the function giving the coefficients of the lazy series being - cosntructed, then use the ``coefficients`` argument in this + constructed, then use the ``coefficients`` argument in this case and do not provide ``x``. + .. WARNING:: + + Polynomials, but also :class:`LazyLaurentSeries` and + :class:`LazyDirichletSeries` are callable. Therefore, an + argument ``x`` which is not convertible into an element + of the underlying ring corresponding to series with + finite support is interpreted as a function providing the + coefficients when evaluated at integers. Examples are + provided below. + EXAMPLES:: sage: L = LazyLaurentSeriesRing(GF(2), 'z') @@ -184,6 +196,24 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + When the argument ``x`` is callable and not convertible into + an element of the underlying ring of series of finite + support, it is evaluated at integers to compute the + coefficients:: + + sage: R. = QQ[] + sage: D = LazyDirichletSeriesRing(ZZ, 't') + sage: D(1+2*q) + 3 + 5/2^t + 7/3^t + 9/4^t + 11/5^t + 13/6^t + 15/7^t + O(1/(8^t)) + + In some cases, this may yield surprising results:: + + sage: m = D(moebius) + sage: s = L(m, valuation=0); s[1] + Traceback (most recent call last): + ... + ValueError: the argument must be a linear polynomial of degree 1 with integer coefficients + TESTS: Checking the valuation is consistent:: @@ -254,13 +284,6 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No ... ValueError: constant may only be specified if the degree is specified - sage: D = LazyDirichletSeriesRing(ZZ, 't') - sage: m = D(moebius) - sage: L(m) - Traceback (most recent call last): - ... - ValueError: unable to convert ... into Lazy Laurent Series Ring ... - We support the old input format for ``constant``:: sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) @@ -274,6 +297,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No .. TODO:: Add a method to change the sparse/dense implementation. + """ if valuation is not None and valuation not in ZZ: raise ValueError("the valuation must be an integer") @@ -1123,6 +1147,10 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: D(coefficients=z+z^2) 2 + 6/2^t + 12/3^t + 20/4^t + 30/5^t + 42/6^t + 56/7^t + O(1/(8^t)) + sage: s = D(lambda n: n) + sage: D(s, valuation=2) + 1/(2^t) + 2/3^t + 3/4^t + 4/5^t + 5/6^t + 6/7^t + 7/8^t + O(1/(9^t)) + .. TODO:: Add a method to make a copy of ``self._sparse``. @@ -1215,4 +1243,3 @@ def _monomial(self, c, n): return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) options = LazyLaurentSeriesRing.options - From 1145168ef40e20dde6b86cee84841fe2280837ab Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 17:20:59 +0900 Subject: [PATCH 261/355] One last # optional - sirocco tag. --- src/sage/schemes/curves/zariski_vankampen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index ff6d165f44a..96a7ee5623d 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -331,7 +331,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): (1.0, -1.026166099551513, -0.32768940253604323)] sage: fup = f.subs({y:y-1/10}) sage: fdown = f.subs({y:y+1/10}) - sage: followstrand(f, [fup, fdown], x0, x1, -1.0) + sage: followstrand(f, [fup, fdown], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), (0.7651655429449553, -1.015686131039112, -0.25243563967299404), From 38ac82f1ffb2c12a471748847a0129c8b6398cc1 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 19:37:46 +0900 Subject: [PATCH 262/355] Fixing bug in Dirichlet _element_consructor_. --- src/sage/rings/lazy_series_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index cfbf0cf31a7..c483fd26f15 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -34,7 +34,6 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.lazy_series import (LazyModuleElement, - LazyCauchyProductSeries, LazyLaurentSeries, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -345,7 +344,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return self.element_class(self, coeff_stream) # Handle when it is a lazy series - if isinstance(x, LazyCauchyProductSeries): + if isinstance(x, self.element_class): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") @@ -1173,7 +1172,8 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No BR = self.base_ring() if x in BR: x = BR(x) - if (isinstance(x, LazyModuleElement) and not isinstance(x, LazyDirichletSeries)) or callable(x): + if not isinstance(x, LazyDirichletSeries) and (isinstance(x, LazyModuleElement) + or callable(x)): if coefficients is not None: raise ValueError("coefficients must be None if x is provided") coefficients = x From 85785859019238bab96db918bdbf90e565c4587e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 20:22:04 +0900 Subject: [PATCH 263/355] More bugfixes and expanding the Dirichlet __call__ input. --- src/sage/rings/lazy_series.py | 46 ++++++++++++++++++++++++++++-- src/sage/rings/lazy_series_ring.py | 44 ++++++++++++++++++---------- 2 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 6bbc812aedd..337192bef75 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2562,13 +2562,55 @@ def __call__(self, p): sage: Z(s)*Z(s-1)/Z(2*s-2) - (1/Psi).map_coefficients(abs) O(1/(8^s)) + sage: Z(5) + zeta(5) + sage: Z(1+I) + zeta(I + 1) + + sage: f = D([1,2,-3,-4], valuation=2); f + 1/(2^s) + 2/3^s - 3/4^s - 4/5^s + sage: f(2) + 449/3600 + sage: 1/2^2 + 2/3^2 + -3/4^2 + -4/5^2 + 449/3600 + sage: f(0) + 0 + sage: f(-2) + -126 + + sage: f = D([4,2,-3,2]) + sage: f(0) + 4 + + sage: f = D([1,2,-3,-4], constant=2) + sage: bool(f(2) == -1 + -5/3^2 + -6/4^2 + 2*zeta(2)) + True """ P = self.parent() + coeff_stream = self._coeff_stream + if not p: + return self[1] + + # Special behavior for finite series + if isinstance(coeff_stream, Stream_exact): + from sage.rings.all import CC + if not coeff_stream._constant: + try: + return sum(self[k] * ~(ZZ(k)**p) + for k in range(1, coeff_stream._degree)) + except (ValueError, TypeError, ArithmeticError): + pass + elif p in CC: + from sage.functions.transcendental import zeta + C = coeff_stream._constant + ret = sum((self[k] - C) * ~(ZZ(k)**p) + for k in range(1, coeff_stream._degree)) + return ret + C * zeta(p) + R = PolynomialRing(ZZ, P.variable_name()) p = R(p) if p.degree() != 1: raise ValueError("the argument must be a linear polynomial of degree 1 with integer coefficients") - coeff_stream = self._coeff_stream b, a = p if a < 0: raise ValueError("the leading coefficient must be positive") @@ -2578,7 +2620,7 @@ def coefficient(m): n = m.nth_root(a) return coeff_stream[n] * n ** (-b) except ValueError: - return 0 + return ZZ.zero() return P.element_class(P, Stream_function(coefficient, P._coeff_ring, P._sparse, 1)) def _format_series(self, formatter, format_strings=False): diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index c483fd26f15..2c292d719c1 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -205,13 +205,15 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: D(1+2*q) 3 + 5/2^t + 7/3^t + 9/4^t + 11/5^t + 13/6^t + 15/7^t + O(1/(8^t)) - In some cases, this may yield surprising results:: + In this example, the Dirichlet series ``m`` is considered as an + element in the base ring:: sage: m = D(moebius) - sage: s = L(m, valuation=0); s[1] - Traceback (most recent call last): - ... - ValueError: the argument must be a linear polynomial of degree 1 with integer coefficients + sage: s = L(m, valuation=0) + sage: s[0] + 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) + sage: s[1] + 0 TESTS: @@ -344,7 +346,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return self.element_class(self, coeff_stream) # Handle when it is a lazy series - if isinstance(x, self.element_class): + if isinstance(x, self.Element): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") @@ -1150,6 +1152,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: D(s, valuation=2) 1/(2^t) + 2/3^t + 3/4^t + 4/5^t + 5/6^t + 6/7^t + 7/8^t + O(1/(9^t)) + sage: Ds = LazyDirichletSeriesRing(ZZ, 's') + sage: m = Ds(moebius, valuation=2); m + -1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(9^s)) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(m) + -1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(9^t)) + .. TODO:: Add a method to make a copy of ``self._sparse``. @@ -1163,21 +1172,26 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No else: x = p.shift(1) else: - if valuation is None: - valuation = 1 - if coefficients is not None: + if valuation is None: + valuation = 1 return super()._element_constructor_(x, valuation, degree, constant, coefficients) BR = self.base_ring() if x in BR: + if valuation is None: + valuation = 1 x = BR(x) - if not isinstance(x, LazyDirichletSeries) and (isinstance(x, LazyModuleElement) - or callable(x)): - if coefficients is not None: - raise ValueError("coefficients must be None if x is provided") - coefficients = x - x = None + + if not isinstance(x, LazyDirichletSeries): + if valuation is None: + valuation = 1 + + if isinstance(x, LazyModuleElement) or callable(x): + if coefficients is not None: + raise ValueError("coefficients must be None if x is provided") + coefficients = x + x = None if valuation is not None and (valuation not in ZZ or valuation <= 0): raise ValueError("the valuation must be a positive integer") From 6456a2af2ba559f2c9766abd8cdcb94eb3597f70 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 28 Sep 2021 20:43:59 +0900 Subject: [PATCH 264/355] Rework Sage input preparser --- src/doc/en/developer/coding_in_python.rst | 2 +- src/sage/repl/interpreter.py | 722 +++++++++++++++++++++- src/sage/repl/ipython_extension.py | 61 +- src/sage/repl/preparse.py | 129 ++-- 4 files changed, 845 insertions(+), 69 deletions(-) diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 1d8b7c1d3bf..3e3143bf09c 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -238,7 +238,7 @@ replacements are made: sage: R. = QQ[] sage: preparse('R. = QQ[]') - "R = QQ['x, y']; (x, y,) = R._first_ngens(2)" + "R = QQ['x', 'y']; (x, y,) = R._first_ngens(2)" - Integer and real literals are Sage integers and Sage floating point numbers. For example, in pure Python these would be an attribute diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 71dbe429fdd..733dd4ed8f4 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -146,12 +146,15 @@ from sage.repl.configuration import sage_ipython_config, SAGE_EXTENSION from IPython.core.interactiveshell import InteractiveShell -from IPython.terminal.interactiveshell import TerminalInteractiveShell -from IPython.core.inputtransformer2 import PromptStripper from IPython.core.prefilter import PrefilterTransformer +from IPython.core.crashhandler import CrashHandler +from IPython.core.inputtransformer2 import (PromptStripper, + TokenTransformBase, + tokenize) + +from IPython.terminal.interactiveshell import TerminalInteractiveShell from IPython.terminal.embed import InteractiveShellEmbed from IPython.terminal.ipapp import TerminalIPythonApp, IPAppCrashHandler -from IPython.core.crashhandler import CrashHandler # TODO: This global variable _do_preparse should be associated with an @@ -396,18 +399,72 @@ def run_cell(self, *args, **kwds): # Transformers used in the SageInputSplitter ################################################################### +quote_state = None def SagePreparseTransformer(lines): r""" EXAMPLES:: sage: from sage.repl.interpreter import SagePreparseTransformer - sage: spt = SagePreparseTransformer - sage: spt(['1+1r+2.3^2.3r\n']) + sage: SagePreparseTransformer(['1+1r+2.3^2.3r\n']) ["Integer(1)+1+RealNumber('2.3')**2.3\n"] sage: preparser(False) - sage: spt(['2.3^2\n']) + sage: SagePreparseTransformer(['2.3^2\n']) ['2.3^2\n'] + sage: preparser(True) + + Numbers are parsed as Sage's numbers unless an ``r`` is appended:: + + sage: from sage.repl.interpreter import SagePreparseTransformer + sage: SagePreparseTransformer(["2+2r + 4"]) + ['Integer(2)+2 + Integer(4)'] + sage: SagePreparseTransformer(["def foo():\n", " return 2"]) + ['def foo():\n', ' return Integer(2)'] + + Multiline-strings are left as they are:: + + sage: SagePreparseTransformer(["def foo():\n", " return a + '''\n", " 2 - 3r\n", " '''"]) + ['def foo():\n', " return a + '''\n", ' 2 - 3r\n', " '''"] + + IPython magic is not yet preparsed:: + + sage: SagePreparseTransformer(["%time 2 + 2"]) + ['%time 2 + 2'] + sage: SagePreparseTransformer(["a = %time 2 + 2"]) + ['a = %time 2 + 2'] + sage: SagePreparseTransformer(["b = 2; a = %time 2 + 2"]) + ['b = Integer(2); a = %time Integer(2) + Integer(2)'] + sage: SagePreparseTransformer(["%%cython", "a = 2"]) + ['%%cython', 'a = 2'] + + Preparses [0,2,..,n] notation:: + + sage: SagePreparseTransformer(["for i in [2 .. 5 ..a]"]) + ['for i in (ellipsis_range(Integer(2) ,Ellipsis, Integer(5) ,Ellipsis,a))'] + sage: SagePreparseTransformer(["for i in (2 .. 5r)"]) + ['for i in (ellipsis_iter(Integer(2) ,Ellipsis, 5))'] + + Preparses generator access:: + + sage: SagePreparseTransformer(["K = QuadraticField(2)\n", "print(K.0)"]) + ['K = QuadraticField(Integer(2))\n', 'print(K.gen(0))'] + + Preparses implicit multiplication:: + + sage: SagePreparseTransformer(["2a"]) + ['2a'] + sage: implicit_multiplication(True) + sage: SagePreparseTransformer(["2a"]) + ['Integer(2)*a'] + sage: implicit_multiplication(False) + + Replaces ``^`` by exponentiation and ``^^`` as bitwise xor:: + + sage: SagePreparseTransformer(["x^2"]) + ['x**Integer(2)'] + sage: SagePreparseTransformer(["x^^2"]) + ['x^Integer(2)'] + TESTS: @@ -417,14 +474,14 @@ def SagePreparseTransformer(lines): sage: preparser(True) sage: bad_syntax = "R. = QQ{]" sage: preparse(bad_syntax) - Traceback (most recent call last): - ... - SyntaxError: Mismatched ']' + 'R = QQ{]; (t,) = R._first_ngens(1)' sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell(bad_syntax) - File "", line unknown - SyntaxError: Mismatched ']' + File "...", line 1 + R = QQ{]; (t,) = R._first_ngens(1) + ^ + SyntaxError: invalid syntax sage: shell.quit() @@ -443,16 +500,651 @@ def SagePreparseTransformer(lines): ``sage.repl.interpreter.SagePreparseTransformer.has_side_effects = True`` """ - if _do_preparse: - # IPython ensures the input lines end with a newline, and it expects - # the same of the output lines. - lines = preparse(''.join(lines)).splitlines(keepends=True) + if not _do_preparse: + return lines + + from .preparse import (strip_string_literals, + parse_ellipsis, + implicit_mul, + implicit_mul_level, + preparse_numeric_literals, + preparse_gen, + preparse_exponentiation) + + # Save the quote state. + global quote_state + + quote_state = None + new_lines = [] + for i in range(len(lines)): + line = lines[i] + magic_or_system = '' + if not quote_state: + if line[:2] == '%%': + # Cell magic. Stop the preparse. + new_lines += lines[i:] + return new_lines + if line[:1] in ('%', '!'): + # Line magic or system call. + # Do not preparse this line. + new_lines.append(line) + continue + + # Magic or system assignments are a bit harder to detect. + # If we detect them, we remove the corresponding part. + pos_eq = line.find('=') + while pos_eq != -1: + remainder = line[pos_eq+1:].strip() + if remainder[:1] == '%': + # Probably a magic assignment. + from IPython.core.inputtransformer2 import make_tokens_by_line + from IPython.core.inputtransformer2 import MagicAssign + tokens = make_tokens_by_line([line]) + M = MagicAssign.find(tokens) + if M: + magic_or_system = line[M.start_col:] + line = line[:M.start_col] + elif remainder[:1] == '!': + # Probably a system assignment. + from IPython.core.inputtransformer2 import make_tokens_by_line + from IPython.core.inputtransformer2 import SystemAssign + tokens = make_tokens_by_line([line]) + M = SystemAssign.find(tokens) + if M: + magic_or_system = line[M.start_col:] + line = line[:M.start_col] + pos_eq = line.find('=', pos_eq + 1) + + L, literals, quote_state = strip_string_literals(line, quote_state) + + # Ellipsis Range + # [1..n] + try: + L = parse_ellipsis(L, preparse_step=False) + except SyntaxError: + pass + + if implicit_mul_level: + # Implicit Multiplication + # 2x -> 2*x + L = implicit_mul(L, level = implicit_mul_level) + + # Wrapping numeric literals + # 1 + 0.5 -> Integer(1) + RealNumber('0.5') + L = preparse_numeric_literals(L, quotes=quote_state.safe_delimiter()) + + # Generators + # R.0 -> R.gen(0) + L = preparse_gen(L) + + # Use ^ for exponentiation and ^^ for xor + L = preparse_exponentiation(L) + + line = L % literals + magic_or_system + new_lines.append(line) + + from IPython.core.inputtransformer2 import TransformerManager + from sage.repl.interpreter import SageTokenTransformers + + T = TransformerManager() + T.token_transformers = SageTokenTransformers + + lines = T.do_token_transforms(new_lines) + return lines SagePromptTransformer = PromptStripper(prompt_re=re.compile(r'^(\s*(:?sage: |\.\.\.\.: ))+')) +class SageBackslashTransformer(TokenTransformBase): + r""" + Transform Sage's backslash operator. + + TESTS:: + + sage: from IPython import get_ipython + sage: ip = get_ipython() + sage: ip.transform_cell(r''' + ....: A\B''') + 'A * BackslashOperator() * B\n' + sage: ip.transform_cell(r''' + ....: a = (2, 3, \ + ....: 4)''') + 'a = (Integer(2), Integer(3), \\\n Integer(4))\n' + """ + priority = 20 + + @classmethod + def find(cls, tokens_by_line): + r""" + Find the first backslash operator. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageBackslashTransformer + sage: lines = ['for i in range(5):\n', r' C[i] = A[i] \ B[i]'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageBackslashTransformer.find(tokens) + sage: S.transform(lines) + ['for i in range(5):\n', ' C[i] = A[i] * BackslashOperator() * B[i]'] + """ + for line in tokens_by_line: + for token in line: + if token.string == '\\': + return cls(token.start) + + def transform(self, lines): + r""" + Transform the backslash operator. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageBackslashTransformer + sage: lines = [r'A = (B \ C) \ D'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageBackslashTransformer.find(tokens) + sage: while S: + ....: lines = S.transform(lines) + ....: tokens = make_tokens_by_line(lines) + ....: S = SageBackslashTransformer.find(tokens) + sage: lines + ['A = (B * BackslashOperator() * C) * BackslashOperator() * D'] + """ + start_line = lines[self.start_line][:self.start_col].rstrip() + ' * BackslashOperator() * ' \ + + lines[self.start_line][self.start_col + 1:].lstrip() + return lines[:self.start_line] + [start_line] + lines[self.start_line + 1:] + + +class SageGenConstructionTransformer(TokenTransformBase): + r""" + Transform Sage's construction with generators. + + TESTS:: + + sage: from IPython import get_ipython + sage: ip = get_ipython() + + Vanilla:: + + sage: ip.transform_cell(''' + ....: R. = ZZ['x']''') + "R = ZZ['x']; (x,) = R._first_ngens(1)\n" + sage: ip.transform_cell(''' + ....: R. = ZZ['x,y']''') + "R = ZZ['x,y']; (x, y,) = R._first_ngens(2)\n" + + No square brackets:: + + sage: ip.transform_cell(''' + ....: R. = PolynomialRing(ZZ, 'x')''') + "R = PolynomialRing(ZZ, 'x', names=('x',)); (x,) = R._first_ngens(1)\n" + sage: ip.transform_cell(''' + ....: R. = PolynomialRing(ZZ, 'x,y')''') + "R = PolynomialRing(ZZ, 'x,y', names=('x', 'y',)); (x, y,) = R._first_ngens(2)\n" + + Names filled in:: + + sage: ip.transform_cell(''' + ....: R. = ZZ[]''') + "R = ZZ['x']; (x,) = R._first_ngens(1)\n" + sage: ip.transform_cell(''' + ....: R. = ZZ[]''') + "R = ZZ['x', 'y']; (x, y,) = R._first_ngens(2)\n" + + Names given not the same as generator names:: + + sage: ip.transform_cell(''' + ....: R. = ZZ['y']''') + "R = ZZ['y']; (x,) = R._first_ngens(1)\n" + sage: ip.transform_cell(''' + ....: R. = ZZ['u,v']''') + "R = ZZ['u,v']; (x, y,) = R._first_ngens(2)\n" + + Number fields:: + + sage: ip.transform_cell(''' + ....: K. = QuadraticField(2)''') + "K = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1)\n" + sage: ip.transform_cell(''' + ....: K. = QQ[2^(1/3)]''') + 'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(1)\n' + sage: ip.transform_cell(''' + ....: K. = QQ[2^(1/3), 2^(1/2)]''') + 'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)\n' + + Just the .<> notation:: + + sage: ip.transform_cell(''' + ....: R. = ZZx''') + 'R = ZZx; (x,) = R._first_ngens(1)\n' + sage: ip.transform_cell(''' + ....: R. = a+b''') + 'R = a+b; (x, y,) = R._first_ngens(2)\n' + sage: ip.transform_cell(''' + ....: A.=FreeAlgebra(ZZ,3)''') + "A=FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)\n" + + Ensure we do not eat too much:: + + sage: ip.transform_cell(''' + ....: R. = ZZ;2''') + 'R = ZZ; (x, y,) = R._first_ngens(2);Integer(2)\n' + sage: ip.transform_cell(''' + ....: R. = ZZ['x,y'];2''') + "R = ZZ['x,y']; (x, y,) = R._first_ngens(2);Integer(2)\n" + sage: ip.transform_cell(''' + ....: F., f, g = S.field_extension()''') + "F, f, g = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)\n" + + Multiple lines:: + + sage: ip.transform_cell(''' + ....: K. = some_large_field( + ....: input1, + ....: input2, + ....: intput3)''') + "K = some_large_field(\n input1,\n input2,\n intput3, names=('a', 'b', 'c',)); (a, b, c,) = K._first_ngens(3)\n" + sage: ip.transform_cell(''' + ....: def foo(L): + ....: K.= L + ....: return K, a, b, c''') + 'def foo(L):\n K= L; (a, b, c,) = K._first_ngens(3)\n return K, a, b, c\n' + sage: ip.transform_cell(''' + ....: def foo(L, M): + ....: K1., K2. = L, M + ....: return a,b,c,d,e''') + 'def foo(L, M):\n K1, K2 = L, M; (d, e,) = K2._first_ngens(2); (a, b, c,) = K1._first_ngens(3)\n return a,b,c,d,e\n' + sage: ip.transform_cell(''' + ....: def p in primes(2, 20): + ....: K. = QuadraticField(p); print(a)''') + "def p in primes(Integer(2), Integer(20)):\n K = QuadraticField(p, names=('a',)); (a,) = K._first_ngens(1); print(a)\n" + + See :trac:`16731`:: + + sage: ip.transform_cell(''' + ....: R. = ''') + 'R = ; (x,) = R._first_ngens(1)\n' + + Check support for unicode characters (:trac:`29278`):: + + sage: ip.transform_cell(''' + ....: Ω.<λ,μ> = QQ[]''') + "Ω = QQ['λ', 'μ']; (λ, μ,) = Ω._first_ngens(2)\n" + + Check that :trac:`30953` is fixed:: + + sage: K. = QuadraticField(2 + # some comment + ....: 1); K, a + (Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878?, + a) + """ + priority = 25 + + def __init__(self, del_start, del_end, keyword_pos, argument_pos, insert_pos, name, gens): + """ + INPUT: + + - ``del_start`` -- start of the ``<`` + + - ``del_end`` -- end of the ``>`` + + - ``keyword_pos`` -- position to insert generator names as keyword or ``None`` + + - ``argument_pos`` -- position to insert generator names as arguments or ``None`` + + - ``names_pos`` -- position to insert the additional command to declare the generators + + - ``name`` -- name of the field or similar + + - ``gens`` -- names of the generators + + TESTS:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageGenConstructionTransformer + sage: lines = ['K. = QQ[]'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageGenConstructionTransformer.find(tokens) # indirect doctest + sage: S.transform(lines) + ["K = QQ['a', 'b']; (a, b,) = K._first_ngens(2)"] + """ + super().__init__(del_start) + self.name = name + self.gens = gens + + # Shift from 1-index to 0-indexed. + self.del_start = (del_start[0] - 1, del_start[1]) + self.del_end = (del_end[0] - 1, del_end[1]) + self.insert_pos = (insert_pos[0] - 1, insert_pos[1]) + self.keyword_pos = (keyword_pos[0] - 1, keyword_pos[1]) if keyword_pos is not None else None + self.argument_pos = (argument_pos[0] - 1, argument_pos[1]) if argument_pos is not None else None + + @classmethod + def find(cls, tokens_by_line): + r""" + Find the first construction with generators. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageGenConstructionTransformer + sage: lines = ['for p in primes(2, 20):\n', ' K. = QuadraticField(p)\n', ' print(a)'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageGenConstructionTransformer.find(tokens) + sage: S.transform(lines) + ['for p in primes(2, 20):\n', + " K = QuadraticField(p, names=('a',)); (a,) = K._first_ngens(1)\n", + ' print(a)'] + """ + for line in tokens_by_line: + name = None + gens = [] + for i, token in enumerate(line[2:], 2): + if token.string == '<' and line[i-1].string == '.' and token.start == line[i-1].end and line[i-2].type == tokenize.NAME: + if name is None: + name = line[i-2].string + del_start = line[i-1].start + else: + # Do not transform syntax errors. + break + elif token.string == '<': + # Do not transform syntax errors. + break + elif name is None: + continue + elif token.type == tokenize.NAME: + gens.append(token.string) + elif token.string[:1] == '>': + del_end = (token.start[0], token.start[1] + 1) + + if del_end[0] != del_start[0]: + # The generators must be written in one line. + break + if gens == []: + # At least one generator needed. + break + + # Find the position to insert the declaration of the generators. + ix = i + 1 + while not line[ix].string == ';' and not line[ix].type == tokenize.NEWLINE and ix + 1 < len(line): + ix += 1 + while line[ix - 1].type == tokenize.COMMENT: + ix -= 1 + insert_pos = line[ix].start + + # See if the names of the generators need to be given as keyword or argument. + keyword_pos = None + argument_pos = None + ix -= 1 + while line[ix].type in {tokenize.COMMENT, tokenize.NL}: + ix -= 1 + if line[ix].string == ')': + keyword_pos = True + elif line[ix].string == ']': + while line[ix-1].string == ']': + ix -= 1 + argument_pos = True + + if argument_pos or keyword_pos: + ix -= 1 + while line[ix].type in {tokenize.COMMENT, tokenize.NL}: + ix -= 1 + if keyword_pos: + keyword_pos = line[ix].end + else: + if line[ix].string == '[': + argument_pos = line[ix].end + else: + argument_pos = None + + return cls(del_start, del_end, keyword_pos, argument_pos, insert_pos, name, gens) + elif token.string != ',': + # Do not transform syntax errors. + break + + def transform(self, lines): + r""" + Transform the first construction with generators. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageGenConstructionTransformer + sage: lines = ['F., f, g = S.field_extension()'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageGenConstructionTransformer.find(tokens) + sage: S.transform(lines) + ["F, f, g = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)"] + """ + lines = [l for l in lines] + + new_command = '; (' + ', '.join(self.gens) + ',) = ' + self.name \ + + "._first_ngens({})".format(len(self.gens)) + lines[self.insert_pos[0]] = lines[self.insert_pos[0]][:self.insert_pos[1]] \ + + new_command \ + + lines[self.insert_pos[0]][self.insert_pos[1]:] + + if self.argument_pos or self.keyword_pos: + names = "'" + "', '".join(self.gens) + "'" + if self.keyword_pos: + names_pos = self.keyword_pos + names = "names=(" + names + if len(self.gens): + names += "," + names += ")" + else: + names_pos = self.argument_pos + if lines[names_pos[0]][names_pos[1] - 1] not in ('(', '['): + names = ", " + names + lines[names_pos[0]] = lines[names_pos[0]][:names_pos[1]] + names \ + + lines[names_pos[0]][names_pos[1]:] + + lines[self.del_start[0]] = lines[self.del_start[0]][:self.del_start[1]] \ + + lines[self.del_start[0]][self.del_end[1]:] + + return lines + + +class SageCalculusTransformer(TokenTransformBase): + r""" + Supports calculus-like function assignment, e.g., transforms:: + + f(x,y,z) = sin(x^3 - 4*y) + y^x + + into:: + + __tmp__=var("x,y,z") + f = symbolic_expression(sin(x**3 - 4*y) + y**x).function(x,y,z) + + TESTS: + + sage: from IPython import get_ipython + sage: ip = get_ipython() + sage: ip.transform_cell(''' + ....: f(x) = x^3 - x''') + '__tmp__ = var("x"); __tmpf__ = x**Integer(3) - x; f = symbolic_expression(__tmpf__).function(x)\n' + sage: ip.transform_cell(''' + ....: f(u,v) = u - v''') + '__tmp__ = var("u,v"); __tmpf__ = u - v; f = symbolic_expression(__tmpf__).function(u,v)\n' + sage: ip.transform_cell(''' + ....: f(x) =-5''') + '__tmp__ = var("x"); __tmpf__ =-Integer(5); f = symbolic_expression(__tmpf__).function(x)\n' + sage: ip.transform_cell(''' + ....: f(x) -= 5''') + 'f(x) -= Integer(5)\n' + sage: ip.transform_cell(''' + ....: f(x_1, x_2) = x_1^2 - x_2^2''') + '__tmp__ = var("x_1,x_2"); __tmpf__ = x_1**Integer(2) - x_2**Integer(2); f = symbolic_expression(__tmpf__).function(x_1,x_2)\n' + + sage: ip.transform_cell(''' + ....: f(t,s)=t^2''') + '__tmp__ = var("t,s"); __tmpf__=t**Integer(2); f = symbolic_expression(__tmpf__).function(t,s)\n' + + + sage: ip.transform_cell(''' + ....: f(x, y) = x^3 - y''') + '__tmp__ = var("x,y"); __tmpf__ = x**Integer(3) - y; f = symbolic_expression(__tmpf__).function(x,y)\n' + sage: ip.transform_cell(''' + ....: μ(x,y) = (x^3 - + ....: y)''') + '__tmp__ = var("x,y"); __tmpμ__ = (x**Integer(3) -\n y); μ = symbolic_expression(__tmpμ__).function(x,y)\n' + sage: ip.transform_cell(''' + ....: f(x, + ....: y) = (x^3 - + ....: y)''') + '__tmp__ = var("x,y"); __tmpf__ = (x**Integer(3) -\n y); f = symbolic_expression(__tmpf__).function(x,y)\n' + sage: ip.transform_cell(''' + ....: def foo: + ....: f(x, + ....: y) = (x^3 - + ....: y); return f''') + 'def foo:\n __tmp__ = var("x,y"); __tmpf__ = (x**Integer(3) -\n y); f = symbolic_expression(__tmpf__).function(x,y); return f\n' + + Check that :trac:`30953` is fixed:: + + sage: f(x) = (x + + ....: 1); f + x |--> x + 1 + sage: f(x, # Some comment + ....: y, + ....: z) = (x + # Some comment + ....: y + + ....: z); f + (x, y, z) |--> x + y + z + """ + priority = 30 + + def __init__(self, del_start, del_end, insert_pos, name, variables): + """ + INPUT: + + - ``del_start`` -- start of the name of the function + - ``del_end`` -- end of the ``)`` + - ``insert_pos`` -- position to insert the new command + - ``name`` -- name of the field or similar + - ``variables`` -- names of the variables + + TESTS:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageCalculusTransformer + sage: lines = ['f(z,zz) = z + zz\n'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageCalculusTransformer.find(tokens) # indirect doctest + sage: S.transform(lines) + ['__tmp__ = var("z,zz"); __tmpf__ = z + zz; f = symbolic_expression(__tmpf__).function(z,zz)\n'] + """ + super().__init__(del_start) + self.name = name + self.variables= variables + + # Shift from 1-index to 0-indexed. + self.del_end = (del_end[0] - 1, del_end[1]) + self.insert_pos = (insert_pos[0] - 1, insert_pos[1]) + + @classmethod + def find(cls, tokens_by_line): + r""" + Find the first calculus-like function assignment. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageCalculusTransformer + sage: lines = ['for i in range(2,20)):\n', ' f(x) = i*x\n'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageCalculusTransformer.find(tokens) + sage: S.transform(lines) + ['for i in range(2,20)):\n', + ' __tmp__ = var("x"); __tmpf__ = i*x; f = symbolic_expression(__tmpf__).function(x)\n'] + """ + for line in tokens_by_line: + name = None + gens = [] + for i, token in enumerate(line[:-1]): + if token.string == ')' and line[i+1].string == '=': + # Find matching '(' + variables = [] + ix = i-1 + while ix >= 1: + if line[ix].string == '(': + break + elif line[ix].string == ',': + pass + elif line[ix].type == tokenize.NAME: + variables = [line[ix].string] + variables + elif line[ix].type not in {tokenize.NL, tokenize.COMMENT}: + ix = 1 + ix -= 1 + else: + # Incorrect syntax or first token is '('. + break + + if line[ix-1].type != tokenize.NAME: + # A tuple assignment. + break + + name = line[ix-1].string + + del_start = line[ix-1].start + del_end = token.end + + # Find the position to insert the declaration of the generators. + ix = i + 1 + while (not line[ix].string == ';' + and not line[ix].type == tokenize.NEWLINE + and ix + 1 < len(line)): + ix += 1 + while line[ix - 1].type == tokenize.COMMENT: + ix -= 1 + insert_pos = line[ix].start + + return cls(del_start, del_end, insert_pos, name, variables) + + + def transform(self, lines): + r""" + Find the first calculus-like function assignment. + + EXAMPLES:: + + sage: from IPython.core.inputtransformer2 import make_tokens_by_line + sage: from sage.repl.interpreter import SageCalculusTransformer + sage: lines = ['f(x,y,z) = sqrt(x) - y^z\n'] + sage: tokens = make_tokens_by_line(lines) + sage: S = SageCalculusTransformer.find(tokens) + sage: S.transform(lines) + ['__tmp__ = var("x,y,z"); __tmpf__ = sqrt(x) - y^z; f = symbolic_expression(__tmpf__).function(x,y,z)\n'] + """ + start_line, start_col = self.start_line, self.start_col + + lines = [l for l in lines] + + tmpf = '__tmp{}__'.format(self.name) + variables = ','.join(self.variables) + line2 = '; {} = symbolic_expression({}).function({})'.format(self.name, tmpf, variables) + + lines[self.insert_pos[0]] = lines[self.insert_pos[0]][:self.insert_pos[1]] \ + + line2 \ + + lines[self.insert_pos[0]][self.insert_pos[1]:] + + line1 = lines[start_line][:start_col] + '__tmp__ = var("{}")'.format(variables) + "; " + tmpf + line1 += lines[self.del_end[0]][self.del_end[1]:] + + lines_before = lines[:start_line] + lines_after = lines[self.del_end[0] + 1:] + + return lines_before + [line1] + lines_after + + +SageTokenTransformers = [SageBackslashTransformer, + SageGenConstructionTransformer, + SageCalculusTransformer] + + ################### # Interface shell # ################### diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index f37a712e9da..ded5cdbde78 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -506,13 +506,68 @@ def init_inspector(self): def init_line_transforms(self): """ Set up transforms (like the preparser). + + TESTS: + + Check that :trac:`31951` is fixed:: + + sage: from IPython import get_ipython + sage: ip = get_ipython() + sage: ip.input_transformer_manager.check_complete(''' # indirect doctest + ....: for i in [1 .. 2]: + ....: a = 2''') + ('incomplete', 2) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L) + ....: K. = L''') + ('invalid', None) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L): + ....: K. = L''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L): + ....: K. = L''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(R): + ....: a = R.0''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(a): + ....: b = 2a''') + ('invalid', None) + sage: implicit_multiplication(True) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(a): + ....: b = 2a''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(): + ....: f(x) = x^2''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(): + ....: 2.factor()''') + ('incomplete', 4) """ - from .interpreter import (SagePreparseTransformer, - SagePromptTransformer) + from IPython.core.inputtransformer2 import TransformerManager + from .interpreter import SagePromptTransformer, SagePreparseTransformer - self.shell.input_transformers_cleanup.insert(1, SagePromptTransformer) + self.shell.input_transformer_manager.cleanup_transforms.insert(1, SagePromptTransformer) self.shell.input_transformers_post.append(SagePreparseTransformer) + # Create an input transformer that does Sage's special syntax in the first step. + # We append Sage's preparse to the cleanup step, so that ``check_complete`` recognizes + # Sage's special syntax. + # Behaviour is somewhat inconsistent, but the syntax is recognized as desired. + M = TransformerManager() + M.token_transformers = self.shell.input_transformer_manager.token_transformers + M.cleanup_transforms.insert(1, SagePromptTransformer) + M.cleanup_transforms.append(SagePreparseTransformer) + self.shell._check_complete_transformer = M + self.shell.input_transformer_manager.check_complete = M.check_complete + class SageJupyterCustomizations(SageCustomizations): @staticmethod diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e5ac7f7ab73..3743f2c2e27 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -140,7 +140,7 @@ expression:: sage: preparse('a(x) =- 5') - '__tmp__=var("x"); a = symbolic_expression(- Integer(5)).function(x)' + '__tmp__ = var("x"); __tmpa__ =- Integer(5); a = symbolic_expression(__tmpa__).function(x)' sage: f(x)=-x sage: f(10) -10 @@ -1105,6 +1105,7 @@ def parse_ellipsis(code, preparse_step=True): ix = code.find('..') return code + def extract_numeric_literals(code): """ Pulls out numeric literals and assigns them to global variables. @@ -1432,15 +1433,15 @@ def preparse_calculus(code): EXAMPLES:: sage: preparse("f(x) = x^3-x") - '__tmp__=var("x"); f = symbolic_expression(x**Integer(3)-x).function(x)' + '__tmp__ = var("x"); __tmpf__ = x**Integer(3)-x; f = symbolic_expression(__tmpf__).function(x)' sage: preparse("f(u,v) = u - v") - '__tmp__=var("u,v"); f = symbolic_expression(u - v).function(u,v)' + '__tmp__ = var("u,v"); __tmpf__ = u - v; f = symbolic_expression(__tmpf__).function(u,v)' sage: preparse("f(x) =-5") - '__tmp__=var("x"); f = symbolic_expression(-Integer(5)).function(x)' + '__tmp__ = var("x"); __tmpf__ =-Integer(5); f = symbolic_expression(__tmpf__).function(x)' sage: preparse("f(x) -= 5") 'f(x) -= Integer(5)' sage: preparse("f(x_1, x_2) = x_1^2 - x_2^2") - '__tmp__=var("x_1,x_2"); f = symbolic_expression(x_1**Integer(2) - x_2**Integer(2)).function(x_1,x_2)' + '__tmp__ = var("x_1,x_2"); __tmpf__ = x_1**Integer(2) - x_2**Integer(2); f = symbolic_expression(__tmpf__).function(x_1,x_2)' For simplicity, this function assumes all statements begin and end with a semicolon:: @@ -1468,20 +1469,16 @@ def preparse_calculus(code): sage: from sage.repl.preparse import preparse_file sage: preparse_file("f(1)=x") - Traceback (most recent call last): - ... - ValueError: Argument names should be valid python identifiers. + '_sage_const_1 = Integer(1)\n__tmp__ = var("_sage_const_1"); __tmpf__=x; f = symbolic_expression(__tmpf__).function(_sage_const_1)' sage: from sage.repl.preparse import preparse_file sage: preparse_file("f(x,1)=2") - Traceback (most recent call last): - ... - ValueError: Argument names should be valid python identifiers. + '_sage_const_1 = Integer(1); _sage_const_2 = Integer(2)\n__tmp__ = var("x,_sage_const_1"); __tmpf__=_sage_const_2 ; f = symbolic_expression(__tmpf__).function(x,_sage_const_1)' Check support for unicode characters (:trac:`29278`):: sage: preparse("μ(x) = x^2") - '__tmp__=var("x"); μ = symbolic_expression(x**Integer(2)).function(x)' + '__tmp__ = var("x"); __tmpμ__ = x**Integer(2); μ = symbolic_expression(__tmpμ__).function(x)' Check that the parameter list can span multiple lines (:trac:`30928`):: @@ -1491,7 +1488,7 @@ def preparse_calculus(code): ....: c, ....: d) = a + b*2 + c*3 + d*4 ....: ''') - '\n__tmp__=var("a,b,c,d"); f = symbolic_expression(a + b*Integer(2) + c*Integer(3) + d*Integer(4)).function(a,b,c,d)\n' + '\n__tmp__ = var("a,b,c,d"); __tmpf__ = a + b*Integer(2) + c*Integer(3) + d*Integer(4); f = symbolic_expression(__tmpf__).function(a,b,c,d)\n' """ new_code = [] @@ -1597,7 +1594,7 @@ def preparse_generators(code): sage: preparse("R. = ZZ[]") "R = ZZ['x']; (x,) = R._first_ngens(1)" sage: preparse("R. = ZZ[]") - "R = ZZ['x, y']; (x, y,) = R._first_ngens(2)" + "R = ZZ['x', 'y']; (x, y,) = R._first_ngens(2)" Names given not the same as generator names:: @@ -1620,7 +1617,7 @@ def preparse_generators(code): sage: preparse("R. = a+b") 'R = a+b; (x, y,) = R._first_ngens(2)' sage: preparse("A.=FreeAlgebra(ZZ,3)") - "A = FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)" + "A=FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)" Ensure we do not eat too much:: @@ -1645,7 +1642,7 @@ def preparse_generators(code): Check support for unicode characters (:trac:`29278`):: sage: preparse('Ω.<λ,μ> = QQ[]') - "Ω = QQ['λ, μ']; (λ, μ,) = Ω._first_ngens(2)" + "Ω = QQ['λ', 'μ']; (λ, μ,) = Ω._first_ngens(2)" """ new_code = [] last_end = 0 @@ -1688,6 +1685,14 @@ def preparse_generators(code): return ''.join(new_code) +def preparse_gen(code): + return re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', code) + +def preparse_exponentiation(code): + # Use ^ for exponentiation and ^^ for xor + # (A side effect is that **** becomes xor as well.) + return code.replace('^', '**').replace('****', '^') + quote_state = None def preparse(line, reset=True, do_time=False, ignore_prompts=False, @@ -1718,7 +1723,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, sage: preparse("ZZ. = ZZ['y']") "ZZ = ZZ['y']; (x,) = ZZ._first_ngens(1)" sage: preparse("ZZ. = ZZ[]") - "ZZ = ZZ['x, y']; (x, y,) = ZZ._first_ngens(2)" + "ZZ = ZZ['x', 'y']; (x, y,) = ZZ._first_ngens(2)" sage: preparse("ZZ. = ZZ['u,v']") "ZZ = ZZ['u,v']; (x, y,) = ZZ._first_ngens(2)" sage: preparse("ZZ. = QQ[2^(1/3)]") @@ -1745,7 +1750,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, 'a * BackslashOperator() * b \\' sage: preparse("time R. = ZZ[]", do_time=True) - '__time__=cputime(); __wall__=walltime(); R = ZZ[\'x\']; print("Time: CPU %.2f s, Wall: %.2f s"%(cputime(__time__), walltime(__wall__))); (x,) = R._first_ngens(1)' + '__time__ = cputime(); __wall__ = walltime(); R = ZZ[\'x\']; print("Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__))); (x,) = R._first_ngens(1)' TESTS: @@ -1757,7 +1762,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, Check support for backslash line continuation (:trac:`30928`):: sage: preparse("f(x) = x \\\n+ 1") - '__tmp__=var("x"); f = symbolic_expression(x + Integer(1)).function(x)' + '__tmp__ = var("x"); __tmpf__ = x \\\n+ Integer(1); f = symbolic_expression(__tmpf__).function(x)' Check that multi-line strings starting with a comment are still preparsed (:trac:`31043`):: @@ -1765,8 +1770,37 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, sage: print(preparse('''# some comment ....: f(x) = x + 1''')) # some comment - __tmp__=var("x"); f = symbolic_expression(x + Integer(1)).function(x) + __tmp__ = var("x"); __tmpf__ = x + Integer(1); f = symbolic_expression(__tmpf__).function(x) + TESTS:: + + sage: from sage.repl.preparse import preparse + sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000)) + sage: _ = preparse(lots_of_numbers) + sage: print(preparse("type(100r), type(100)")) + type(100), type(Integer(100)) + + Check that :trac:`4312` is fixed:: + + sage: file_contents = ''' + ....: @parallel(8) + ....: def f(p): + ....: print(p) + ....: t = cputime() + ....: M = ModularSymbols(p^2,sign=1) + ....: w = M.atkin_lehner_operator(p) + ....: K = (w-1).kernel() + ....: N = K.new_subspace() + ....: D = N.decomposition()''' + sage: t = tmp_filename(ext=".sage") + sage: with open(t, 'w') as f: + ....: f.write(file_contents) + 198 + sage: load(t) + sage: list(f([11,17])) + 11 + 17 + [(((11,), {}), None), (((17,), {}), None)] """ global quote_state if reset: @@ -1807,43 +1841,37 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, # Generators # R.0 -> R.gen(0) - L = re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', L) + L = preparse_gen(L) # Use ^ for exponentiation and ^^ for xor - # (A side effect is that **** becomes xor as well.) - L = L.replace('^', '**').replace('****', '^') - - # Combine lines that use backslash continuation - L = L.replace('\\\n', '') + L = preparse_exponentiation(L) - # Make it easy to match statement ends - L = ';%s;' % L.replace('\n', ';\n;') + from IPython.core.inputtransformer2 import TransformerManager + from sage.repl.interpreter import SageTokenTransformers - if do_time: - # Separate time statement - L = re.sub(r';(\s*)time +(\w)', r';time;\1\2', L) + T = TransformerManager() + T.token_transformers = SageTokenTransformers - # Construction with generators - # R.<...> = obj() - # R.<...> = R[] - L = preparse_generators(L) + if not L.endswith('\n'): + cell = L + '\n' # Ensure the cell has a trailing newline + else: + cell = L - # Calculus functions - # f(x,y) = x^3 - sin(y) - L = preparse_calculus(L) + lines = cell.splitlines(keepends=True) + lines = T.do_token_transforms(lines) + output = ''.join(lines) - # Backslash - L = re.sub(r'''\\\s*([^\t ;#])''', r' * BackslashOperator() * \1', L) + if L[-1:] != "\n" and output[-1:] == "\n": + # Strip trailing newline, if input did not have it. + L = output[:-1] + else: + L = output if do_time: - # Time keyword - L = re.sub(r';time;(\s*)(\S[^;]*)', - r';\1__time__=cputime(); __wall__=walltime(); \2; print(' + - '"Time: CPU %%.2f s, Wall: %%.2f s"%%(cputime(__time__), walltime(__wall__)))', - L) - - # Remove extra ;'s - L = L.replace(';\n;', '\n')[1:-1] + L = re.sub(r'^(\s*)time (\S[^;\n]*)', + r'__time__ = cputime(); __wall__ = walltime(); \2; print(' + + r'"Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__)))', + L, flags=re.MULTILINE) line = L % literals @@ -1856,7 +1884,9 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, def preparse_file(contents, globals=None, numeric_literals=True): """ - Preparses input, attending to numeric literals and load/attach + Preparse ``contents`` which is input from a file such as ``.sage`` files. + + Special attentions are given to numeric literals and load/attach file directives. .. note:: Temporarily, if @parallel is in the input, then @@ -2017,7 +2047,6 @@ def re_no_keyword(pattern, code): return code % literals - def _strip_quotes(s): """ Strips one set of outer quotes. From e587a83332e29a1ebc8847f57973e32653f70278 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 20:49:09 +0900 Subject: [PATCH 265/355] Cleaning up rebasing. --- src/sage/rings/lazy_series.py | 385 +++++++++++++++++----------------- 1 file changed, 193 insertions(+), 192 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index b07b38a78ff..370ce8f1daa 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -87,12 +87,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.rings.infinity import infinity from sage.structure.element import Element, parent -from sage.rings.integer_ring import ZZ from sage.structure.richcmp import op_EQ, op_NE +from sage.functions.other import factorial from sage.arith.power import generic_power +from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.data_structures.stream import ( @@ -1302,12 +1302,10 @@ def exp(self): ... ValueError: can only compose with a positive valuation series - sage: L. = LazyTaylorSeriesRing(QQ) - sage: exp(x+y)[4].factor() + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: exp(x+y)[4].factor() # not tested (1/24) * (x + y)^4 - - sage: L. = LazyTaylorSeriesRing(SR) - sage: exp(x/(1-y)).finite_part(3) + sage: exp(x/(1-y)).finite_part(3) # not tested 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 TESTS:: @@ -1315,10 +1313,8 @@ def exp(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: exp(z)[0:6] == exp(x).series(x, 6).coefficients(sparse=False) True - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.functions.other import factorial + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: 1/factorial(ZZ(n)), valuation=0) return f(self) @@ -1332,8 +1328,9 @@ def log(self): sage: L. = LazyLaurentSeriesRing(QQ) sage: log(1/(1-z)) z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: log((1 + x/(1-y))).finite_part(3) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: log((1 + x/(1-y))).finite_part(3) # not tested 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x TESTS:: @@ -1346,9 +1343,8 @@ def log(self): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) return f(self-1) @@ -1365,24 +1361,22 @@ def sin(self): sage: sin(z) z - 1/6*z^3 + 1/120*z^5 - 1/5040*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: sin(x/(1-y)).finite_part(3) - (-1/6)*x^3 + x*y^2 + x*y + x - sage: sin(1 + z) Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sin(x/(1-y)).finite_part(3) # not tested + (-1/6)*x^3 + x*y^2 + x*y + x + TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: sin(z)[0:6] == sin(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)), valuation=1) @@ -1398,8 +1392,8 @@ def cos(self): sage: cos(z) 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: cos(x/(1-y)).finite_part(4) + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: cos(x/(1-y)).finite_part(4) # not tested 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 TESTS:: @@ -1407,10 +1401,8 @@ def cos(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: cos(z)[0:6] == cos(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)), valuation=0) @@ -1426,8 +1418,8 @@ def tan(self): sage: tan(z) z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: tan(x/(1-y)).finite_part(5) + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: tan(x/(1-y)).finite_part(5) # not tested 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x TESTS:: @@ -1435,9 +1427,8 @@ def tan(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: tan(z)[0:6] == tan(x).series(x, 6).coefficients(sparse=False) True - """ - return self.sin()/self.cos() + return self.sin() / self.cos() def cot(self): r""" @@ -1449,7 +1440,7 @@ def cot(self): sage: cot(z) z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) - sage: L. = LazyLaurentSeriesRing(SR) + sage: L. = LazyLaurentSeriesRing(QQ) sage: cot(x/(1-x)).finite_part(4) x^-1 - 1 - 1/3*x - 1/3*x^2 - 16/45*x^3 - 2/5*x^4 @@ -1458,9 +1449,8 @@ def cot(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: cot(z)[0:6] == cot(x).series(x, 6).coefficients(sparse=False) True - """ - return ~ self.tan() + return ~self.tan() def csc(self): r""" @@ -1472,7 +1462,7 @@ def csc(self): sage: csc(z) z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) - sage: L. = LazyLaurentSeriesRing(SR) + sage: L. = LazyLaurentSeriesRing(QQ) sage: csc(x/(1-x)).finite_part(4) x^-1 - 1 + 1/6*x + 1/6*x^2 + 67/360*x^3 + 9/40*x^4 @@ -1481,9 +1471,8 @@ def csc(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: (z*csc(z))[0:6] == (x*csc(x)).series(x, 6).coefficients(sparse=False) True - """ - return ~ self.sin() + return ~self.sin() def sec(self): r""" @@ -1495,8 +1484,8 @@ def sec(self): sage: sec(z) 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: sec(x/(1-y)).finite_part(4) + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sec(x/(1-y)).finite_part(4) # not tested 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 TESTS:: @@ -1504,9 +1493,8 @@ def sec(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: sec(z)[0:6] == sec(x).series(x, 6).coefficients(sparse=False) True - """ - return ~ self.cos() + return ~self.cos() # inverse trigonometric functions @@ -1520,19 +1508,19 @@ def arcsin(self): sage: arcsin(z) z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: asin(x/(1-y)) - x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: asin(x/(1-y)) # not tested + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) + + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: asin(z)[0:6] == asin(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1549,18 +1537,24 @@ def arccos(self): sage: L. = LazyLaurentSeriesRing(RR) sage: arccos(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 - 0.166666666666667*z^3 + 0.000000000000000*z^4 - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + - 0.166666666666667*z^3 + 0.000000000000000*z^4 + - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) + + sage: L. = LazyLaurentSeriesRing(SR) + sage: arccos(z/(1-z)) + 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: arccos(x/(1-y)) - 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 + sage: L. = LazyTaylorSeriesRing(SR) # not tested + sage: arccos(x/(1-y)) # not tested + 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: acos(z)[0:6] == acos(x).series(x, 6).coefficients(sparse=False) True - """ from sage.symbolic.constants import pi return self.parent()(pi/2) - self.arcsin() @@ -1575,18 +1569,19 @@ def arctan(self): sage: arctan(z) z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: atan(x/(1-y)) - x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: atan(x/(1-y)) # not tested + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) + + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: atan(z)[0:6] == atan(x).series(x, 6).coefficients(sparse=False) True - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1605,18 +1600,24 @@ def arccot(self): sage: L. = LazyLaurentSeriesRing(RR) sage: arccot(z) - 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + 0.333333333333333*z^3 + 0.000000000000000*z^4 - 0.200000000000000*z^5 + O(1.00000000000000*z^7) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + + 0.333333333333333*z^3 + 0.000000000000000*z^4 + - 0.200000000000000*z^5 + O(1.00000000000000*z^7) + + sage: L. = LazyLaurentSeriesRing(SR) + sage: arccot(z/(1-z)) + 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: acot(x/(1-y)) - 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 + sage: L. = LazyTaylorSeriesRing(SR) # not tested + sage: acot(x/(1-y)) # not tested + 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: acot(z)[0:6] == acot(x).series(x, 6).coefficients(sparse=False) True - """ from sage.symbolic.constants import pi return self.parent()(pi/2) - self.arctan() @@ -1633,19 +1634,19 @@ def sinh(self): sage: sinh(z) z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: sinh(x/(1-y)) - x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sinh(x/(1-y)) # not tested + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) + + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: sinh(z)[0:6] == sinh(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), valuation=1) @@ -1661,19 +1662,18 @@ def cosh(self): sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: cosh(x/(1-y)) - 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: cosh(x/(1-y)) # not tested + 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: cosh(z)[0:6] == cosh(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), valuation=0) @@ -1689,20 +1689,20 @@ def tanh(self): sage: tanh(z) z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: tanh(x/(1-y)) - x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: tanh(x/(1-y)) # not tested + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) + + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: tanh(z)[0:6] == tanh(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial from sage.arith.misc import bernoulli - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1730,11 +1730,9 @@ def coth(self): sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: coth(z)[0:6] == coth(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial from sage.arith.misc import bernoulli - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1753,20 +1751,20 @@ def sech(self): sage: sech(z) 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: sech(x/(1-y)) - 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) + O(x,y)^7 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sech(x/(1-y)) # not tested + 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) + + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) + + O(x,y)^7 TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: sech(z)[0:6] == sech(x).series(x, 6).coefficients(sparse=False) True - """ - from sage.functions.other import factorial from sage.combinat.combinat import euler_number - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1785,7 +1783,7 @@ def csch(self): sage: csch(z) z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) - sage: L. = LazyLaurentSeriesRing(SR) + sage: L. = LazyLaurentSeriesRing(QQ) sage: csch(z/(1-z)) z^-1 - 1 - 1/6*z - 1/6*z^2 - 53/360*z^3 - 13/120*z^4 - 787/15120*z^5 + O(z^6) @@ -1796,9 +1794,8 @@ def csch(self): True """ - from sage.functions.other import factorial from sage.arith.misc import bernoulli - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1819,9 +1816,11 @@ def arcsinh(self): sage: asinh(z) z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: asinh(x/(1-y)) - x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: asinh(x/(1-y)) # not tested + x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) + + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) + + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: @@ -1830,8 +1829,7 @@ def arcsinh(self): True """ - from sage.functions.other import factorial - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) @@ -1851,9 +1849,10 @@ def arctanh(self): sage: atanh(z) z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(SR) - sage: atanh(x/(1-y)) - x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: atanh(x/(1-y)) # not tested + x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: @@ -1862,7 +1861,7 @@ def arctanh(self): True """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing + from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P(lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) return f(self) @@ -1892,8 +1891,7 @@ def hypergeometric(self, a, b): True """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.functions.other import factorial + from .lazy_series_ring import LazyLaurentSeriesRing from sage.arith.misc import rising_factorial P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def coeff(n, c): @@ -1907,103 +1905,23 @@ def coeff(n, c): # === powers === - def __pow__(self, n): - """ - Return the ``n``-th power of the series. - - INPUT: - - - ``n`` -- integer; the power to which to raise the series - - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: (1 - z)^-1 - 1 + z + z^2 + O(z^3) - sage: (1 - z)^0 - 1 - sage: (1 - z)^3 - 1 - 3*z + 3*z^2 - z^3 - sage: (1 - z)^-3 - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - We can create a really large power of a monomial, even with - the dense implementation:: - - sage: z^1000000 - z^1000000 - - Lazy Laurent series that have a sparse implementation can be - raised to the power ``n``:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) - - Lazy Laurent series that are known to be exact can be raised - to the power ``n``:: - - sage: z^2 - z^2 - sage: (1 - z)^2 - 1 - 2*z + z^2 - sage: (1 + z)^2 - 1 + 2*z + z^2 - - We also support the general case:: - - sage: L. = LazyLaurentSeriesRing(SR) - sage: (1 + z)^(1 + z) - 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) - - """ - if n == 0: - return self.parent().one() - - cs = self._coeff_stream - if (isinstance(cs, CoefficientStream_exact) - and not cs._constant and n in ZZ - and (n > 0 or len(cs._initial_coefficients) == 1)): - P = self.parent() - return P(self.finite_part() ** ZZ(n)) - # ret = cs.polynomial_part(P._laurent_poly_ring) ** ZZ(n) - # val = ret.valuation() - # deg = ret.degree() + 1 - # initial_coefficients = [ret[i] for i in range(val, deg)] - # return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, - # constant=cs._constant, degree=deg, valuation=val)) - - if n in ZZ: - return generic_power(self, n) - - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - from sage.functions.other import factorial - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) - return exp(self.log() * n) - def sqrt(self): """ Return ``self^(1/2)``. EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(SR) + sage: L. = LazyLaurentSeriesRing(QQ) sage: sqrt(1+z) 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) - sage: sqrt(1+x/(1-y)) - 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + O(x,y)^7 + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sqrt(1+x/(1-y)) # not tested + 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + + O(x,y)^7 This also works for Dirichlet series:: @@ -2013,7 +1931,6 @@ def sqrt(self): 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) sage: f*f - zeta O(1/(8^s)) - """ return self ** (1/ZZ(2)) @@ -2185,6 +2102,90 @@ def _mul_(self, other): return P.element_class(P, Stream_cauchy_mul(left, right)) + def __pow__(self, n): + """ + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: (1 - z)^-1 + 1 + z + z^2 + O(z^3) + sage: (1 - z)^0 + 1 + sage: (1 - z)^3 + 1 - 3*z + 3*z^2 - z^3 + sage: (1 - z)^-3 + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + We can create a really large power of a monomial, even with + the dense implementation:: + + sage: z^1000000 + z^1000000 + + Lazy Laurent series that have a sparse implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + Lazy Laurent series that are known to be exact can be raised + to the power ``n``:: + + sage: z^2 + z^2 + sage: (1 - z)^2 + 1 - 2*z + z^2 + sage: (1 + z)^2 + 1 + 2*z + z^2 + + We also support the general case:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: (1 + z)^(1 + z) + 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + + """ + if n == 0: + return self.parent().one() + + cs = self._coeff_stream + if (isinstance(cs, Stream_exact) + and not cs._constant and n in ZZ + and (n > 0 or len(cs._initial_coefficients) == 1)): + # # alternatively: + # return P(self.finite_part() ** ZZ(n)) + P = self.parent() + ret = cs._polynomial_part(P._laurent_poly_ring) ** ZZ(n) + val = ret.valuation() + deg = ret.degree() + 1 + initial_coefficients = [ret[i] for i in range(val, deg)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + constant=cs._constant, + degree=deg, order=val)) + if n in ZZ: + return generic_power(self, n) + + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + return exp(self.log() * n) + def __invert__(self): """ Return the multiplicative inverse of the element. From 5c5bb512c20932153b7ab0e450d1569fae44b366 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 20:54:33 +0900 Subject: [PATCH 266/355] Fixing bug with SR as base ring for Dirichlet series. --- src/sage/rings/lazy_series.py | 4 ++-- src/sage/rings/lazy_series_ring.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 370ce8f1daa..a4026272e80 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1926,8 +1926,8 @@ def sqrt(self): This also works for Dirichlet series:: sage: D = LazyDirichletSeriesRing(SR, "s") - sage: zeta = D(constant=1) - sage: f = sqrt(zeta) + sage: Z = D(constant=1) + sage: f = sqrt(Z) 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) sage: f*f - zeta O(1/(8^s)) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2c292d719c1..7ff7c45fe95 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1183,7 +1183,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No valuation = 1 x = BR(x) - if not isinstance(x, LazyDirichletSeries): + elif not isinstance(x, LazyDirichletSeries): if valuation is None: valuation = 1 From 5e59f1287d35e85576ef554518fb9f311bbcc9f2 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 28 Sep 2021 20:59:34 +0900 Subject: [PATCH 267/355] Add missing doctests --- src/sage/repl/preparse.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 3743f2c2e27..e538c626ce4 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1686,13 +1686,46 @@ def preparse_generators(code): def preparse_gen(code): + """ + Transform ``R.n`` to ``R.gen(n)``. + + INPUT: + + - ``code`` -- a string + + TESTS:: + + sage: from sage.repl.preparse import preparse_gen + sage: preparse_gen('R.0') + 'R.gen(0)' + sage: preparse_gen('R.1') + 'R.gen(1)' + """ return re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', code) + def preparse_exponentiation(code): - # Use ^ for exponentiation and ^^ for xor - # (A side effect is that **** becomes xor as well.) + """ + Transform ``a^n`` to ``a**n`` and ``a^^n`` to ``a^n`` + + Use ``^`` for exponentiation and ``^^`` for xor.` A side effect is that + ``****`` becomes xor as well. + + INPUT: + + - ``code`` -- a string + + TESTS:: + + sage: from sage.repl.preparse import preparse_exponentiation + sage: preparse_exponentiation('8^1') + '8**1' + sage: preparse_exponentiation('8^^1') + '8^1' + """ return code.replace('^', '**').replace('****', '^') + quote_state = None def preparse(line, reset=True, do_time=False, ignore_prompts=False, From 547b8b373a93ba276e6adc60ff9531145339873c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Sep 2021 21:01:32 +0900 Subject: [PATCH 268/355] Fixing up final issues with special functions for lazy series. --- src/sage/rings/lazy_series.py | 46 +++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index a4026272e80..23b0027456e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1441,7 +1441,7 @@ def cot(self): z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) sage: L. = LazyLaurentSeriesRing(QQ) - sage: cot(x/(1-x)).finite_part(4) + sage: cot(x/(1-x)).polynomial(4) x^-1 - 1 - 1/3*x - 1/3*x^2 - 16/45*x^3 - 2/5*x^4 TESTS:: @@ -1463,7 +1463,7 @@ def csc(self): z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) sage: L. = LazyLaurentSeriesRing(QQ) - sage: csc(x/(1-x)).finite_part(4) + sage: csc(x/(1-x)).polynomial(4) x^-1 - 1 + 1/6*x + 1/6*x^2 + 67/360*x^3 + 9/40*x^4 TESTS:: @@ -1905,6 +1905,36 @@ def coeff(n, c): # === powers === + def __pow__(self, n): + r""" + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES:: + + sage: D = LazyDirichletSeriesRing(QQ, 's') + sage: Z = D(constant=1) + sage: Z^2 + 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) + sage: f = Z^(1/3) + sage: f + 1 + 1/3/2^s + 1/3/3^s + 2/9/4^s + 1/3/5^s + 1/9/6^s + 1/3/7^s + O(1/(8^s)) + sage: f^2 + 1 + 2/3/2^s + 2/3/3^s + 5/9/4^s + 2/3/5^s + 4/9/6^s + 2/3/7^s + O(1/(8^s)) + sage: f^3 - Z + O(1/(8^s)) + """ + if n in ZZ: + return generic_power(self, n) + + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + return exp(self.log() * n) + def sqrt(self): """ Return ``self^(1/2)``. @@ -1928,8 +1958,9 @@ def sqrt(self): sage: D = LazyDirichletSeriesRing(SR, "s") sage: Z = D(constant=1) sage: f = sqrt(Z) + sage: f 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) - sage: f*f - zeta + sage: f*f - Z O(1/(8^s)) """ return self ** (1/ZZ(2)) @@ -2103,7 +2134,7 @@ def _mul_(self, other): return P.element_class(P, Stream_cauchy_mul(left, right)) def __pow__(self, n): - """ + r""" Return the ``n``-th power of the series. INPUT: @@ -2178,13 +2209,8 @@ def __pow__(self, n): return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, constant=cs._constant, degree=deg, order=val)) - if n in ZZ: - return generic_power(self, n) - from .lazy_series_ring import LazyLaurentSeriesRing - P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) - return exp(self.log() * n) + return super().__pow__(n) def __invert__(self): """ From 0ed2a8c9fa6f81cabe9ab6a1d17afb660f27ba7c Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 15:01:38 +0200 Subject: [PATCH 269/355] remove global quote_state --- src/sage/repl/interpreter.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 733dd4ed8f4..a23cc3d8c76 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -399,8 +399,6 @@ def run_cell(self, *args, **kwds): # Transformers used in the SageInputSplitter ################################################################### -quote_state = None - def SagePreparseTransformer(lines): r""" EXAMPLES:: @@ -511,9 +509,6 @@ def SagePreparseTransformer(lines): preparse_gen, preparse_exponentiation) - # Save the quote state. - global quote_state - quote_state = None new_lines = [] for i in range(len(lines)): From f06008b1b7d191d5c636a266783ffba8193b3ae7 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 28 Sep 2021 15:20:37 +0200 Subject: [PATCH 270/355] doctest interpretation of series argument --- src/sage/rings/lazy_series_ring.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2c292d719c1..4504182776f 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -255,6 +255,15 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(5, valuation=6/2) 5*z^3 + Checking that series are not interpreted as coefficients when + they can be interpreted as series:: + + sage: P. = ZZ[] + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: M. = LazyLaurentSeriesRing(QQ) + sage: L(M(s^2 + s^5), valuation=-4) + z^-4 + z^-1 + This gives zero:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') From 91070cc0757218c9a82eee6233f1830131d6d160 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 28 Sep 2021 15:24:10 +0200 Subject: [PATCH 271/355] doctest interpretation of Dirichlet series argument --- src/sage/rings/lazy_series_ring.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 4504182776f..8a627629063 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -264,6 +264,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(M(s^2 + s^5), valuation=-4) z^-4 + z^-1 + sage: D = LazyDirichletSeriesRing(ZZ, "s") + sage: E = LazyDirichletSeriesRing(QQ, "t") + sage: D(E([1,2,3])) + 1 + 2/2^s + 3/3^s + This gives zero:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') From 7cd7482f84b9841f3349046d75cd95d5b6aa7e7d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 16:23:26 +0200 Subject: [PATCH 272/355] special treatment of magics not needed anymore --- src/sage/repl/interpreter.py | 42 ++---------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index a23cc3d8c76..e60a435cef8 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -512,45 +512,7 @@ def SagePreparseTransformer(lines): quote_state = None new_lines = [] for i in range(len(lines)): - line = lines[i] - magic_or_system = '' - if not quote_state: - if line[:2] == '%%': - # Cell magic. Stop the preparse. - new_lines += lines[i:] - return new_lines - if line[:1] in ('%', '!'): - # Line magic or system call. - # Do not preparse this line. - new_lines.append(line) - continue - - # Magic or system assignments are a bit harder to detect. - # If we detect them, we remove the corresponding part. - pos_eq = line.find('=') - while pos_eq != -1: - remainder = line[pos_eq+1:].strip() - if remainder[:1] == '%': - # Probably a magic assignment. - from IPython.core.inputtransformer2 import make_tokens_by_line - from IPython.core.inputtransformer2 import MagicAssign - tokens = make_tokens_by_line([line]) - M = MagicAssign.find(tokens) - if M: - magic_or_system = line[M.start_col:] - line = line[:M.start_col] - elif remainder[:1] == '!': - # Probably a system assignment. - from IPython.core.inputtransformer2 import make_tokens_by_line - from IPython.core.inputtransformer2 import SystemAssign - tokens = make_tokens_by_line([line]) - M = SystemAssign.find(tokens) - if M: - magic_or_system = line[M.start_col:] - line = line[:M.start_col] - pos_eq = line.find('=', pos_eq + 1) - - L, literals, quote_state = strip_string_literals(line, quote_state) + L, literals, quote_state = strip_string_literals(lines[i], quote_state) # Ellipsis Range # [1..n] @@ -575,7 +537,7 @@ def SagePreparseTransformer(lines): # Use ^ for exponentiation and ^^ for xor L = preparse_exponentiation(L) - line = L % literals + magic_or_system + line = L % literals new_lines.append(line) from IPython.core.inputtransformer2 import TransformerManager From f1b3439f9204e4ae4fb9c33b47b6f6e8ad959f5f Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 16:31:25 +0200 Subject: [PATCH 273/355] remove code duplication --- src/sage/repl/interpreter.py | 65 +++--------------------------------- 1 file changed, 4 insertions(+), 61 deletions(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index e60a435cef8..8e6dcc9e5ba 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -424,17 +424,6 @@ def SagePreparseTransformer(lines): sage: SagePreparseTransformer(["def foo():\n", " return a + '''\n", " 2 - 3r\n", " '''"]) ['def foo():\n', " return a + '''\n", ' 2 - 3r\n', " '''"] - IPython magic is not yet preparsed:: - - sage: SagePreparseTransformer(["%time 2 + 2"]) - ['%time 2 + 2'] - sage: SagePreparseTransformer(["a = %time 2 + 2"]) - ['a = %time 2 + 2'] - sage: SagePreparseTransformer(["b = 2; a = %time 2 + 2"]) - ['b = Integer(2); a = %time Integer(2) + Integer(2)'] - sage: SagePreparseTransformer(["%%cython", "a = 2"]) - ['%%cython', 'a = 2'] - Preparses [0,2,..,n] notation:: sage: SagePreparseTransformer(["for i in [2 .. 5 ..a]"]) @@ -498,56 +487,10 @@ def SagePreparseTransformer(lines): ``sage.repl.interpreter.SagePreparseTransformer.has_side_effects = True`` """ - if not _do_preparse: - return lines - - from .preparse import (strip_string_literals, - parse_ellipsis, - implicit_mul, - implicit_mul_level, - preparse_numeric_literals, - preparse_gen, - preparse_exponentiation) - - quote_state = None - new_lines = [] - for i in range(len(lines)): - L, literals, quote_state = strip_string_literals(lines[i], quote_state) - - # Ellipsis Range - # [1..n] - try: - L = parse_ellipsis(L, preparse_step=False) - except SyntaxError: - pass - - if implicit_mul_level: - # Implicit Multiplication - # 2x -> 2*x - L = implicit_mul(L, level = implicit_mul_level) - - # Wrapping numeric literals - # 1 + 0.5 -> Integer(1) + RealNumber('0.5') - L = preparse_numeric_literals(L, quotes=quote_state.safe_delimiter()) - - # Generators - # R.0 -> R.gen(0) - L = preparse_gen(L) - - # Use ^ for exponentiation and ^^ for xor - L = preparse_exponentiation(L) - - line = L % literals - new_lines.append(line) - - from IPython.core.inputtransformer2 import TransformerManager - from sage.repl.interpreter import SageTokenTransformers - - T = TransformerManager() - T.token_transformers = SageTokenTransformers - - lines = T.do_token_transforms(new_lines) - + if _do_preparse: + # IPython ensures the input lines end with a newline, and it expects + # the same of the output lines. + lines = preparse(''.join(lines)).splitlines(keepends=True) return lines From 16e1617ca332483fbd9947bcc1ea97797cce32cf Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 16:44:15 +0200 Subject: [PATCH 274/355] remove helper functions --- src/sage/repl/interpreter.py | 64 +----------------------------------- src/sage/repl/preparse.py | 51 +++++----------------------- 2 files changed, 9 insertions(+), 106 deletions(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 8e6dcc9e5ba..9870c95bebd 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -497,67 +497,6 @@ def SagePreparseTransformer(lines): SagePromptTransformer = PromptStripper(prompt_re=re.compile(r'^(\s*(:?sage: |\.\.\.\.: ))+')) -class SageBackslashTransformer(TokenTransformBase): - r""" - Transform Sage's backslash operator. - - TESTS:: - - sage: from IPython import get_ipython - sage: ip = get_ipython() - sage: ip.transform_cell(r''' - ....: A\B''') - 'A * BackslashOperator() * B\n' - sage: ip.transform_cell(r''' - ....: a = (2, 3, \ - ....: 4)''') - 'a = (Integer(2), Integer(3), \\\n Integer(4))\n' - """ - priority = 20 - - @classmethod - def find(cls, tokens_by_line): - r""" - Find the first backslash operator. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageBackslashTransformer - sage: lines = ['for i in range(5):\n', r' C[i] = A[i] \ B[i]'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageBackslashTransformer.find(tokens) - sage: S.transform(lines) - ['for i in range(5):\n', ' C[i] = A[i] * BackslashOperator() * B[i]'] - """ - for line in tokens_by_line: - for token in line: - if token.string == '\\': - return cls(token.start) - - def transform(self, lines): - r""" - Transform the backslash operator. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageBackslashTransformer - sage: lines = [r'A = (B \ C) \ D'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageBackslashTransformer.find(tokens) - sage: while S: - ....: lines = S.transform(lines) - ....: tokens = make_tokens_by_line(lines) - ....: S = SageBackslashTransformer.find(tokens) - sage: lines - ['A = (B * BackslashOperator() * C) * BackslashOperator() * D'] - """ - start_line = lines[self.start_line][:self.start_col].rstrip() + ' * BackslashOperator() * ' \ - + lines[self.start_line][self.start_col + 1:].lstrip() - return lines[:self.start_line] + [start_line] + lines[self.start_line + 1:] - - class SageGenConstructionTransformer(TokenTransformBase): r""" Transform Sage's construction with generators. @@ -1040,8 +979,7 @@ def transform(self, lines): return lines_before + [line1] + lines_after -SageTokenTransformers = [SageBackslashTransformer, - SageGenConstructionTransformer, +SageTokenTransformers = [SageGenConstructionTransformer, SageCalculusTransformer] diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e538c626ce4..1fb2008ce8f 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1685,49 +1685,9 @@ def preparse_generators(code): return ''.join(new_code) -def preparse_gen(code): - """ - Transform ``R.n`` to ``R.gen(n)``. - - INPUT: - - - ``code`` -- a string - - TESTS:: - - sage: from sage.repl.preparse import preparse_gen - sage: preparse_gen('R.0') - 'R.gen(0)' - sage: preparse_gen('R.1') - 'R.gen(1)' - """ - return re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', code) - - -def preparse_exponentiation(code): - """ - Transform ``a^n`` to ``a**n`` and ``a^^n`` to ``a^n`` - - Use ``^`` for exponentiation and ``^^`` for xor.` A side effect is that - ``****`` becomes xor as well. - - INPUT: - - - ``code`` -- a string - - TESTS:: - - sage: from sage.repl.preparse import preparse_exponentiation - sage: preparse_exponentiation('8^1') - '8**1' - sage: preparse_exponentiation('8^^1') - '8^1' - """ - return code.replace('^', '**').replace('****', '^') - - quote_state = None + def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True): r""" @@ -1874,10 +1834,15 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, # Generators # R.0 -> R.gen(0) - L = preparse_gen(L) + L = re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', L) # Use ^ for exponentiation and ^^ for xor - L = preparse_exponentiation(L) + L = L.replace('^', '**').replace('****', '^') + + # Backslash + L = ';%s;' % L.replace('\n', ';\n;') + L = re.sub(r'''\\\s*([^\t ;#])''', r' * BackslashOperator() * \1', L) + L = L.replace(';\n;', '\n')[1:-1] from IPython.core.inputtransformer2 import TransformerManager from sage.repl.interpreter import SageTokenTransformers From 49a9dcbb0d3527a5fcf19d907b6ba25f5ef73a0a Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 16:49:28 +0200 Subject: [PATCH 275/355] fix 4312 and make doctest stable --- src/sage/repl/preparse.py | 47 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 1fb2008ce8f..dd0118485d7 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1772,28 +1772,6 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, sage: _ = preparse(lots_of_numbers) sage: print(preparse("type(100r), type(100)")) type(100), type(Integer(100)) - - Check that :trac:`4312` is fixed:: - - sage: file_contents = ''' - ....: @parallel(8) - ....: def f(p): - ....: print(p) - ....: t = cputime() - ....: M = ModularSymbols(p^2,sign=1) - ....: w = M.atkin_lehner_operator(p) - ....: K = (w-1).kernel() - ....: N = K.new_subspace() - ....: D = N.decomposition()''' - sage: t = tmp_filename(ext=".sage") - sage: with open(t, 'w') as f: - ....: f.write(file_contents) - 198 - sage: load(t) - sage: list(f([11,17])) - 11 - 17 - [(((11,), {}), None), (((17,), {}), None)] """ global quote_state if reset: @@ -1914,6 +1892,25 @@ def preparse_file(contents, globals=None, numeric_literals=True): sage: print(preparse_file("type(100r), type(100)")) _sage_const_100 = Integer(100) type(100 ), type(_sage_const_100 ) + + Check that :trac:`4312` is fixed:: + + sage: file_contents = ''' + ....: @parallel(8) + ....: def f(p): + ....: t = cputime() + ....: M = ModularSymbols(p^2,sign=1) + ....: w = M.atkin_lehner_operator(p) + ....: K = (w-1).kernel() + ....: N = K.new_subspace() + ....: D = N.decomposition()''' + sage: t = tmp_filename(ext=".sage") + sage: with open(t, 'w') as f: + ....: f.write(file_contents) + 185 + sage: load(t) + sage: sorted(list(f([11,17]))) + [(((11,), {}), None), (((17,), {}), None)] """ if not isinstance(contents, str): raise TypeError("contents must be a string") @@ -1921,12 +1918,6 @@ def preparse_file(contents, globals=None, numeric_literals=True): if globals is None: globals = {} - # This is a hack, since when we use @parallel to parallelize code, - # the numeric literals that are factored out do not get copied - # to the subprocesses properly. See trac #4545. - if '@parallel' in contents: - numeric_literals = False - if numeric_literals: contents, literals, state = strip_string_literals(contents) contents, nums = extract_numeric_literals(contents) From 561764f974923fcd74e7b66ffe29ff957a99d89b Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 28 Sep 2021 16:54:57 +0200 Subject: [PATCH 276/355] less differences to develop --- src/sage/repl/preparse.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index dd0118485d7..b9d898fc54e 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1755,7 +1755,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, Check support for backslash line continuation (:trac:`30928`):: sage: preparse("f(x) = x \\\n+ 1") - '__tmp__ = var("x"); __tmpf__ = x \\\n+ Integer(1); f = symbolic_expression(__tmpf__).function(x)' + '__tmp__ = var("x"); __tmpf__ = x + Integer(1); f = symbolic_expression(__tmpf__).function(x)' Check that multi-line strings starting with a comment are still preparsed (:trac:`31043`):: @@ -1815,8 +1815,12 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, L = re.sub(r'(\b[^\W\d]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', L) # Use ^ for exponentiation and ^^ for xor + # (A side effect is that **** becomes xor as well.) L = L.replace('^', '**').replace('****', '^') + # Combine lines that use backslash continuation + L = L.replace('\\\n', '') + # Backslash L = ';%s;' % L.replace('\n', ';\n;') L = re.sub(r'''\\\s*([^\t ;#])''', r' * BackslashOperator() * \1', L) From c36e61f43fc1f50b15b8cc7dfbd2bbb25d33c1e1 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 29 Sep 2021 00:56:30 +0900 Subject: [PATCH 277/355] Deprecate preparse_generators and preparse_calculus --- src/sage/repl/preparse.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index b9d898fc54e..b6aa09ac0b8 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -262,6 +262,7 @@ from types import SimpleNamespace +from sage.misc.superseded import deprecation from sage.repl.load import load_wrap implicit_mul_level = False @@ -1448,6 +1449,10 @@ def preparse_calculus(code): sage: from sage.repl.preparse import preparse_calculus sage: preparse_calculus(";f(t,s)=t^2;") + doctest:warning + ... + DeprecationWarning: The method preparse_calculus is deprecated; use sage.repl.intepreter.SageCalculusTransformer instead. + See https://trac.sagemath.org/31951 for details. ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);' sage: preparse_calculus(";f( t , s ) = t^2;") ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);' @@ -1491,6 +1496,8 @@ def preparse_calculus(code): '\n__tmp__ = var("a,b,c,d"); __tmpf__ = a + b*Integer(2) + c*Integer(3) + d*Integer(4); f = symbolic_expression(__tmpf__).function(a,b,c,d)\n' """ + deprecation(31951, "The method preparse_calculus is deprecated; use " + "sage.repl.intepreter.SageCalculusTransformer instead.") new_code = [] last_end = 0 # f ( vars ) = expr @@ -1632,6 +1639,10 @@ def preparse_generators(code): with a semicolon:: sage: preparse_generators("; R.=ZZ[];") + doctest:warning + ... + DeprecationWarning: The method preparse_generators is deprecated; use sage.repl.intepreter.SageGenConstructionTransformer instead. + See https://trac.sagemath.org/31951 for details. "; R = ZZ['x']; (x,) = R._first_ngens(1);" See :trac:`16731`:: @@ -1644,6 +1655,8 @@ def preparse_generators(code): sage: preparse('Ω.<λ,μ> = QQ[]') "Ω = QQ['λ', 'μ']; (λ, μ,) = Ω._first_ngens(2)" """ + deprecation(31951, "The method preparse_generators is deprecated; use " + "sage.repl.intepreter.SageGenConstructionTransformer instead.") new_code = [] last_end = 0 # obj .< gens > , other = constructor From 1c7445df37d65cf2460f575353f0f0bb6b82e7e2 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 28 Sep 2021 19:12:12 +0200 Subject: [PATCH 278/355] trac #22003: avoid enumeration of faces in num_faces when no embedding is provided --- src/sage/graphs/generic_graph.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 366d0868666..b2b3ee0b2e6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5964,11 +5964,16 @@ def num_faces(self, embedding=None): return len(self.faces(embedding)) if embedding is None: - # get_embedding() raises an error if no (valid) embedding is set - try: - embedding = self.get_embedding() - except: - pass + # Is self._embedding available ? + if self._check_embedding_validity(): + embedding = self._embedding + else: + if self.is_planar(): + # We use Euler's formula: V-E+F-C=1 + C = len(self.connected_components()) + return self.size() - self.order() + C + 1 + else: + raise ValueError("no embedding is provided and the graph is not planar") # We compute the number Fc of faces of each connected component c. # The number of faces of the graph is the sum of the Fc values minus the From 8f1d5eb8961acf2966f676c44e2c118032f2cbec Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 28 Sep 2021 19:29:06 +0200 Subject: [PATCH 279/355] trac #22003: more description --- src/sage/graphs/generic_graph.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b2b3ee0b2e6..a5349c7fcf0 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5799,6 +5799,16 @@ def faces(self, embedding=None): neighbors of each vertex. From this information one can define the faces of the embedding, which is what this method returns. + If no embedding is provided or stored as ``self._embedding``, this + method will compute the set of faces from the embedding returned by + :meth:`is_planar` (if the graph is, of course, planar). + + .. WARNING:: + + This method is not well defined when the graph is not connected. + Indeed, the result may contain several faces corresponding to the + external face. + INPUT: - ``embedding`` -- dictionary (default: ``None``); a combinatorial @@ -5911,6 +5921,17 @@ def num_faces(self, embedding=None): """ Return the number of faces of an embedded graph. + If no embedding is provided or stored as ``self._embedding``, this + method uses Euler's formula (see the :wikipedia:`Euler_characteristic`) + to determine the number of faces if the graph is planar. If the graph is + not planar, an error is raised. + + If an embedding is provided or stored as ``self._embedding``, this + method calls method :meth:`faces` to get the list of faces induced by + the embedding in each connected component of the graph. Then it returns + the sum of size of these lists minus the number of connected components + plus one to ensure that the external face is counted only once. + INPUT: - ``embedding`` -- dictionary (default: ``None``); a combinatorial From 0926d3986665111653e105657a8964695a8c676b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 11:17:44 -0700 Subject: [PATCH 280/355] build/pkgs/openssl/spkg-configure.m4: Reject openssl < 1.1.1 --- build/pkgs/openssl/spkg-configure.m4 | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/build/pkgs/openssl/spkg-configure.m4 b/build/pkgs/openssl/spkg-configure.m4 index 76158601461..df282945027 100644 --- a/build/pkgs/openssl/spkg-configure.m4 +++ b/build/pkgs/openssl/spkg-configure.m4 @@ -1,11 +1,25 @@ SAGE_SPKG_CONFIGURE([openssl], [ - AX_CHECK_OPENSSL([], [ + AX_CHECK_OPENSSL([ + AC_MSG_CHECKING([whether OpenSSL >= 1.1.1, as required by PEP 644]) + AC_COMPILE_IFELSE( + dnl Trac #32580: Need OpenSSL >= 1.1.1 for PEP 644 + dnl If M is the number from OPENSSL_VERSION_MAJOR + dnl NN is the number from OPENSSL_VERSION_MINOR + dnl PP is the number from OPENSSL_VERSION_PATCH + dnl -> OPENSSL_VERSION_NUMBER is 0xMNN00PP0L + [AC_LANG_PROGRAM([[ + #include + #if OPENSSL_VERSION_NUMBER < 0x10100010L + # error OpenSSL >= 1.1.1 is required according to PEP 644 + #endif + ]], [])], [ + AC_MSG_RESULT([yes]) + sage_spkg_install_openssl=no + ], [ + AC_MSG_RESULT([no]) + sage_spkg_install_openssl=yes + ]) + ], [dnl No openssl found sage_spkg_install_openssl=yes - AC_MSG_WARN([Because your system does not have a suitable OpenSSL library, -Sage will install a prerelease version of OpenSSL from the 3.0 alpha series. -The OpenSSL Project Team indicates that this prerelease version has been provided -for testing ONLY. It should NOT be used for security critical purposes. -We strongly recommend to install OpenSSL using the system package manager and -to re-run configure.]) ]) ]) From 82e08b5ddd72b5ab0f2299e7f3e9b026c3f5dc3c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 12:17:43 -0700 Subject: [PATCH 281/355] build/pkgs/openssl/spkg-configure.m4: Do not require openssl if system python3 is used --- build/pkgs/openssl/spkg-configure.m4 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/pkgs/openssl/spkg-configure.m4 b/build/pkgs/openssl/spkg-configure.m4 index df282945027..bc6e69e666e 100644 --- a/build/pkgs/openssl/spkg-configure.m4 +++ b/build/pkgs/openssl/spkg-configure.m4 @@ -22,4 +22,11 @@ SAGE_SPKG_CONFIGURE([openssl], [ ], [dnl No openssl found sage_spkg_install_openssl=yes ]) +], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_PYTHON3]) + dnl openssl is a dependency only of python3; so if we use system python3, + dnl we do not require it. (In particular, we do not need a specific version.) + AS_IF([test x$sage_spkg_install_python3 = xno], [ + sage_require_openssl=no + ]) ]) From ab6c1cdc3e674f520c3b2fba2dd74f8468bf88c7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 29 Sep 2021 12:54:07 +0900 Subject: [PATCH 282/355] More precise composition with complex numbers for Dirichlet series. --- src/sage/rings/lazy_series.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 337192bef75..41f5c95f18a 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2549,6 +2549,17 @@ def __call__(self, p): Return the series with the variable `s` replaced by a linear polynomial `a\cdot s + b`, for positive `a`. + When `f` is an exact Dirichlet series, we can write + + .. MATH:: + + f(s) = \sum_{n=1}^k a_n / n^s + C \zeta(s). + + Thus we can evaluate this for `p \in \CC` by using the analytic + continuation of the Riemann `\zeta` function for `p \in \CC` + with the real part of `p` at most `1`. In the case `p = 1`, + this will return `\infty` if `C \neq 0`. + EXAMPLES:: sage: D = LazyDirichletSeriesRing(QQ, "s") @@ -2566,6 +2577,10 @@ def __call__(self, p): zeta(5) sage: Z(1+I) zeta(I + 1) + sage: Z(0) + -1/2 + sage: Z(1) + Infinity sage: f = D([1,2,-3,-4], valuation=2); f 1/(2^s) + 2/3^s - 3/4^s - 4/5^s @@ -2574,22 +2589,26 @@ def __call__(self, p): sage: 1/2^2 + 2/3^2 + -3/4^2 + -4/5^2 449/3600 sage: f(0) - 0 + -4 + sage: f(1) + -23/60 sage: f(-2) -126 sage: f = D([4,2,-3,2]) sage: f(0) - 4 + 5 sage: f = D([1,2,-3,-4], constant=2) sage: bool(f(2) == -1 + -5/3^2 + -6/4^2 + 2*zeta(2)) True + sage: f(0) + -13 + sage: f(1) + Infinity """ P = self.parent() coeff_stream = self._coeff_stream - if not p: - return self[1] # Special behavior for finite series if isinstance(coeff_stream, Stream_exact): From 53bde1bc8e8012e6a77066f0a4a7d717fc97075a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 21:04:08 -0700 Subject: [PATCH 283/355] src/sage/repl/__init__.py: Reword comment --- src/sage/repl/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/repl/__init__.py b/src/sage/repl/__init__.py index 8590d1616f0..1357b584ef3 100644 --- a/src/sage/repl/__init__.py +++ b/src/sage/repl/__init__.py @@ -6,7 +6,8 @@ def load_ipython_extension(*args): # The above used to be in sage.__init__, allowing users to use "%load_ext sage". -# But we removed the __init__.py file in order to make sage a native namespace package. +# But we are clearing out the __init__.py file as a preparation for +# making sage a native namespace package. # # So we make "%load_ext sage" work by monkey-patching the function # into the sage package upon importing sage.repl. From 537502fd9352009dea458aefb65e12eca9a13a2d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 29 Sep 2021 11:00:41 +0200 Subject: [PATCH 284/355] leave doctest of 4545 for 4545 --- src/sage/repl/preparse.py | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index b6aa09ac0b8..dbd9aa8a0ff 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1909,25 +1909,6 @@ def preparse_file(contents, globals=None, numeric_literals=True): sage: print(preparse_file("type(100r), type(100)")) _sage_const_100 = Integer(100) type(100 ), type(_sage_const_100 ) - - Check that :trac:`4312` is fixed:: - - sage: file_contents = ''' - ....: @parallel(8) - ....: def f(p): - ....: t = cputime() - ....: M = ModularSymbols(p^2,sign=1) - ....: w = M.atkin_lehner_operator(p) - ....: K = (w-1).kernel() - ....: N = K.new_subspace() - ....: D = N.decomposition()''' - sage: t = tmp_filename(ext=".sage") - sage: with open(t, 'w') as f: - ....: f.write(file_contents) - 185 - sage: load(t) - sage: sorted(list(f([11,17]))) - [(((11,), {}), None), (((17,), {}), None)] """ if not isinstance(contents, str): raise TypeError("contents must be a string") @@ -1935,6 +1916,12 @@ def preparse_file(contents, globals=None, numeric_literals=True): if globals is None: globals = {} + # This is a hack, since when we use @parallel to parallelize code, + # the numeric literals that are factored out do not get copied + # to the subprocesses properly. See trac #4545. + if '@parallel' in contents: + numeric_literals = False + if numeric_literals: contents, literals, state = strip_string_literals(contents) contents, nums = extract_numeric_literals(contents) From 9344a7c69f89d2e37b7b6ab582be19cdddf141a1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 29 Sep 2021 11:04:01 +0200 Subject: [PATCH 285/355] mark 4545 as fixed --- src/sage/repl/preparse.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e5ac7f7ab73..87c2a900bd6 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1886,6 +1886,25 @@ def preparse_file(contents, globals=None, numeric_literals=True): sage: print(preparse_file("type(100r), type(100)")) _sage_const_100 = Integer(100) type(100 ), type(_sage_const_100 ) + + Check that :trac:`4545` is fixed:: + + sage: file_contents = ''' + ....: @parallel(8) + ....: def f(p): + ....: t = cputime() + ....: M = ModularSymbols(p^2,sign=1) + ....: w = M.atkin_lehner_operator(p) + ....: K = (w-1).kernel() + ....: N = K.new_subspace() + ....: D = N.decomposition()''' + sage: t = tmp_filename(ext=".sage") + sage: with open(t, 'w') as f: + ....: f.write(file_contents) + 185 + sage: load(t) + sage: sorted(list(f([11,17]))) + [(((11,), {}), None), (((17,), {}), None)] """ if not isinstance(contents, str): raise TypeError("contents must be a string") @@ -1893,12 +1912,6 @@ def preparse_file(contents, globals=None, numeric_literals=True): if globals is None: globals = {} - # This is a hack, since when we use @parallel to parallelize code, - # the numeric literals that are factored out do not get copied - # to the subprocesses properly. See trac #4545. - if '@parallel' in contents: - numeric_literals = False - if numeric_literals: contents, literals, state = strip_string_literals(contents) contents, nums = extract_numeric_literals(contents) From 4e2e8b85ee02476a51574d1e04e87b0e6c0eaa00 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 29 Sep 2021 11:20:42 +0200 Subject: [PATCH 286/355] Trac #29581: new location of imaginary unit --- .../manifolds/differentiable/characteristic_cohomology_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 2bf2a2b8d77..9b0ffe0bca5 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1429,7 +1429,7 @@ def get_local(self, cmat): [2-form on the 2-dimensional Lorentzian manifold M] """ from sage.symbolic.constants import pi - from sage.libs.pynac.pynac import I + from sage.rings.imaginary_unit import I dom = cmat[0][0]._domain rk = len(cmat) From b0a4794fae8dc44c5a8ec38e3213099295205296 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 29 Sep 2021 14:14:19 +0200 Subject: [PATCH 287/355] trac #32561: review comments --- src/sage/graphs/generators/random.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index b89139cd351..927f9681aa7 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -583,7 +583,7 @@ def RandomBoundedToleranceGraph(n): representation by using the function `ToleranceGraph`. This representation is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random - positive value less then or equal to the length of the interval `I_i`. The + positive value less than or equal to the length of the interval `I_i`. The width of the representation is limited to `n^2 * 2^n`. .. NOTE:: @@ -626,7 +626,9 @@ def RandomBoundedToleranceGraph(n): tolrep = [] for _ in range(n): l = randint(0, W - 1) - r = randint(l + 1, W) + r = randint(0, W) + if l >= r: + l, r = r, l + 1 tolrep.append((l, r, randint(1, r - l))) return ToleranceGraph(tolrep) From 44f8cfa8d960c1ec2db3a097f95728efcc86fcf4 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 29 Sep 2021 15:53:37 +0200 Subject: [PATCH 288/355] Trac #29581: import I from symbolic.constants --- .../differentiable/characteristic_cohomology_class.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 9b0ffe0bca5..8ac01c82d8b 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1428,8 +1428,7 @@ def get_local(self, cmat): sage: algorithm.get_local(cmat) [2-form on the 2-dimensional Lorentzian manifold M] """ - from sage.symbolic.constants import pi - from sage.rings.imaginary_unit import I + from sage.symbolic.constants import pi, I dom = cmat[0][0]._domain rk = len(cmat) From de28c72a9f65ed6681d05d3b9a954bd8f266c9a7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 16:18:33 -0700 Subject: [PATCH 289/355] build/pkgs/liblzma: Add symlink for package-version.txt --- build/pkgs/liblzma/package-version.txt | 1 + 1 file changed, 1 insertion(+) create mode 120000 build/pkgs/liblzma/package-version.txt diff --git a/build/pkgs/liblzma/package-version.txt b/build/pkgs/liblzma/package-version.txt new file mode 120000 index 00000000000..814cca4c8bc --- /dev/null +++ b/build/pkgs/liblzma/package-version.txt @@ -0,0 +1 @@ +../xz/package-version.txt \ No newline at end of file From 48ab22e2b30c6bc312b8cfaf7bf9eb73d1fd4865 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 30 Sep 2021 12:26:42 +0900 Subject: [PATCH 290/355] Minor fixes and edits for patchbot complaints --- src/sage/repl/interpreter.py | 17 +++++----- src/sage/repl/preparse.py | 60 ++++++++++++------------------------ 2 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 9870c95bebd..205eaf0f884 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -424,7 +424,7 @@ def SagePreparseTransformer(lines): sage: SagePreparseTransformer(["def foo():\n", " return a + '''\n", " 2 - 3r\n", " '''"]) ['def foo():\n', " return a + '''\n", ' 2 - 3r\n', " '''"] - Preparses [0,2,..,n] notation:: + Preparses ``[0,2,..,n]`` notation:: sage: SagePreparseTransformer(["for i in [2 .. 5 ..a]"]) ['for i in (ellipsis_range(Integer(2) ,Ellipsis, Integer(5) ,Ellipsis,a))'] @@ -554,7 +554,7 @@ class SageGenConstructionTransformer(TokenTransformBase): ....: K. = QQ[2^(1/3), 2^(1/2)]''') 'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)\n' - Just the .<> notation:: + Just the ``.<>`` notation:: sage: ip.transform_cell(''' ....: R. = ZZx''') @@ -861,9 +861,13 @@ def __init__(self, del_start, del_end, insert_pos, name, variables): INPUT: - ``del_start`` -- start of the name of the function + - ``del_end`` -- end of the ``)`` + - ``insert_pos`` -- position to insert the new command + - ``name`` -- name of the field or similar + - ``variables`` -- names of the variables TESTS:: @@ -902,12 +906,11 @@ def find(cls, tokens_by_line): """ for line in tokens_by_line: name = None - gens = [] for i, token in enumerate(line[:-1]): if token.string == ')' and line[i+1].string == '=': # Find matching '(' variables = [] - ix = i-1 + ix = i - 1 while ix >= 1: if line[ix].string == '(': break @@ -922,13 +925,13 @@ def find(cls, tokens_by_line): # Incorrect syntax or first token is '('. break - if line[ix-1].type != tokenize.NAME: + if line[ix - 1].type != tokenize.NAME: # A tuple assignment. break - name = line[ix-1].string + name = line[ix - 1].string - del_start = line[ix-1].start + del_start = line[ix - 1].start del_end = token.end # Find the position to insert the declaration of the generators. diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index dbd9aa8a0ff..62b8afc9ea1 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -2,46 +2,6 @@ """ The Sage Preparser -AUTHORS: - - - William Stein (2006-02-19) - - - Fixed bug when loading .py files. - - - William Stein (2006-03-09) - - - Fixed crash in parsing exponentials. - - Precision of real literals now determined by digits of input - (like Mathematica). - - - Joe Wetherell (2006-04-14) - - - Added MAGMA-style constructor preparsing. - - - Bobby Moretti (2007-01-25) - - - Added preliminary function assignment notation. - - - Robert Bradshaw (2007-09-19) - - - Added strip_string_literals, containing_block utility - functions. Arrr! - - Added [1,2,..,n] notation. - - - Robert Bradshaw (2008-01-04) - - - Implicit multiplication (off by default). - - - Robert Bradshaw (2008-09-23) - - - Factor out constants. - - - Robert Bradshaw (2000-01) - - - Simplify preparser by making it modular and using regular - expressions. - - Bug fixes, complex numbers, and binary input. - EXAMPLES: Preparsing:: @@ -245,6 +205,26 @@ sage: f'''1{ f"2{ f'4{ 2^3 }4' }2" }1''' '1248421' +AUTHORS: + +- William Stein (2006-02-19): fixed bug when loading .py files + +- William Stein (2006-03-09): fixed crash in parsing exponentials; precision of + real literals now determined by digits of input (like Mathematica) + +- Joe Wetherell (2006-04-14): added MAGMA-style constructor preparsing + +- Bobby Moretti (2007-01-25): added preliminary function assignment notation + +- Robert Bradshaw (2007-09-19): added strip_string_literals, containing_block + utility functions. Arrr!; added [1,2,..,n] notation + +- Robert Bradshaw (2008-01-04): implicit multiplication (off by default) + +- Robert Bradshaw (2008-09-23): factor out constants + +- Robert Bradshaw (2000-01): simplify preparser by making it modular and using + regular expressions; bug fixes, complex numbers, and binary input """ # **************************************************************************** From 1fd3689f9d175146c816d69f87f805abde120b57 Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Sun, 13 Dec 2020 20:15:36 +0100 Subject: [PATCH 291/355] adding more efficient way of stating a letter at an n-th position of a fixed point --- src/sage/combinat/words/morphic.py | 109 +++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/sage/combinat/words/morphic.py diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py new file mode 100644 index 00000000000..5147f0e11cd --- /dev/null +++ b/src/sage/combinat/words/morphic.py @@ -0,0 +1,109 @@ +from sage.combinat.words.word_datatypes import WordDatatype +from sage.rings.all import Infinity +from sage.modules.free_module_element import vector +import itertools + + +class WordDatatype_morphic(WordDatatype): + r""" + Datatype for a word defined by a callable. + """ + def __init__(self, parent, morphism, letter, coding=None): + r""" + INPUT: + + - ``parent`` - a parent + - ``morphism`` - a word morphism + - ``letter`` - a starting letter + - ``coding`` - dict (default: ``None``), if ``None`` + the identity map is used for the coding + + EXAMPLES:: + + sage: f = lambda n : 'x' if n % 2 == 0 else 'y' + sage: w = Word(f, length=9, caching=False); w + word: xyxyxyxyx + sage: type(w) + + sage: w.length() + 9 + + :: + + sage: w = Word(f, caching=False); w + word: xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy... + sage: type(w) + + sage: w.length() is None + False + sage: w.length() + +Infinity + + TESTS:: + + sage: from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable + sage: WordDatatype_callable(Words(),lambda n:n%3) + + sage: WordDatatype_callable(Words([0,1,2]),lambda n:n%3) + + """ + self._len = Infinity + self._parent = parent + # for hashing + self._hash = None + + self._morphism = morphism + self._letter = letter + self._alphabet = self._morphism.domain().alphabet() + if coding == None: + self._coding = {a:a for a in self._alphabet} + else: + self._coding = coding + + + def representation(self, n): + """ + EXAMPLES:: + + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: w = WordDatatype_morphic(W,m,'a') + sage: w.representation(5) + [1, 0, 0, 0] + """ + letters_to_int = {a:i for (i,a) in enumerate(self._alphabet)} + position = letters_to_int[self._letter] + M = self._morphism.incidence_matrix() + vMk = vector([1]*len(self._alphabet)) + length_of_images = [vMk] + while vMk[position] <= n: + vMk = vMk*M + length_of_images.append(vMk) + length_of_images.pop() + k = len(length_of_images) + letter_k = self._letter + n_k = n + path = [] + while k > 0: + m_letter_k = self._morphism(letter_k) + S = 0 + j = 0 + while S <= n_k: + a = m_letter_k[j] + i = letters_to_int[a] + pile_length = length_of_images[k-1][i] + S += pile_length + j += 1 + path.append(j-1) + n_k -= S - pile_length + letter_k = a + k -= 1 + return path + def __getitem__(self, key): + letter = self._letter + for a in self.representation(key): + letter = (self._morphism(letter))[a] + if key == 0: + return self._coding[letter] + return self._coding[letter] From 26b79cbbfe18c64dbbdc8acc760c1d65bccc3f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Tue, 5 Jan 2021 16:33:28 +0100 Subject: [PATCH 292/355] linking morphic.py file to the sage words library --- src/sage/combinat/words/morphic.py | 98 ++++++++++++++++++++++++++++- src/sage/combinat/words/morphism.py | 76 ++-------------------- src/sage/combinat/words/word.py | 86 +++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 74 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 5147f0e11cd..c04313efa0e 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -1,8 +1,25 @@ +# -*- coding: utf-8 -*- +r""" +Morphic words + +This modules implements morphic words (letter-to-letter coding of fixed +point of a morphism). + +AUTHORS: + +- Jana Lepsova (January 2021): initial version + +EXAMPLES: + +Creation of a morphism:: + + sage: n = WordMorphism(...) + +""" + from sage.combinat.words.word_datatypes import WordDatatype from sage.rings.all import Infinity from sage.modules.free_module_element import vector -import itertools - class WordDatatype_morphic(WordDatatype): r""" @@ -60,7 +77,6 @@ def __init__(self, parent, morphism, letter, coding=None): else: self._coding = coding - def representation(self, n): """ EXAMPLES:: @@ -100,10 +116,86 @@ def representation(self, n): letter_k = a k -= 1 return path + def __getitem__(self, key): + """ + EXAMPLES:: + + sage: print('add doc + examples here') + """ letter = self._letter for a in self.representation(key): letter = (self._morphism(letter))[a] if key == 0: return self._coding[letter] return self._coding[letter] + + def __iter__(self): + r""" + Returns an iterator of the letters of the fixed point of ``self`` + starting with ``letter``. + + If w is the iterated word, then this iterator: outputs the elements + of morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i. + + INPUT: + + - ``self`` - an endomorphism, must be prolongable on + letter + + - ``letter`` - a letter in the domain of ``self`` + + OUTPUT: + + - iterator of the fixed point + + EXAMPLES:: + + sage: m = WordMorphism('a->abc,b->,c->') + sage: list(m._fixed_point_iterator('a')) + ['a', 'b', 'c'] + sage: print('update the examples here') + + The morphism must be prolongable on the letter or the iterator will + be empty:: + + sage: list(m._fixed_point_iterator('b')) + [] + + The morphism must be an endomorphism:: + + sage: m = WordMorphism('a->ac,b->aac') + sage: list(m._fixed_point_iterator('a')) + Traceback (most recent call last): + ... + KeyError: 'c' + + We check that :trac:`8595` is fixed:: + + sage: s = WordMorphism({('a', 1):[('a', 1), ('a', 2)], ('a', 2):[('a', 1)]}) + sage: it = s._fixed_point_iterator(('a',1)) + sage: next(it) + ('a', 1) + + This shows that ticket :trac:`13668` has been resolved:: + + sage: s = WordMorphism({1:[1,2],2:[2,3],3:[4],4:[5],5:[6],6:[7],7:[8],8:[9],9:[10],10:[1]}) + sage: (s^7).fixed_points() + [word: 1223234234523456234567234567823456789234..., + word: 2,3,4,5,6,7,8,9,10,1,1,2,1,2,2,3,1,2,2,3,2,3,4,1,2,2,3,2,3,4,2,3,4,5,1,2,2,3,2,3,...] + sage: (s^7).reversal().fixed_points() + [] + """ + from itertools import chain + w = iter(self._morphism.image(self._letter)) + while True: + try: + for a in self._morphism.image(next(w)): + yield self._coding[a] + else: + next_w = next(w) + w = chain([next_w], w, self._morphism.image(next_w)) + except StopIteration: + return + + diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index bc6a540c2d0..c690528cf3e 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -89,8 +89,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from itertools import chain - from sage.misc.callable_dict import CallableDict from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method @@ -1728,73 +1726,6 @@ def is_uniform(self, k=None): else: return all(w.length() == k for w in self.images()) - def _fixed_point_iterator(self, letter): - r""" - Returns an iterator of the letters of the fixed point of ``self`` - starting with ``letter``. - - If w is the iterated word, then this iterator: outputs the elements - of morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i. - - INPUT: - - - ``self`` - an endomorphism, must be prolongable on - letter - - - ``letter`` - a letter in the domain of ``self`` - - OUTPUT: - - - iterator of the fixed point - - EXAMPLES:: - - sage: m = WordMorphism('a->abc,b->,c->') - sage: list(m._fixed_point_iterator('a')) - ['a', 'b', 'c'] - - The morphism must be prolongable on the letter or the iterator will - be empty:: - - sage: list(m._fixed_point_iterator('b')) - [] - - The morphism must be an endomorphism:: - - sage: m = WordMorphism('a->ac,b->aac') - sage: list(m._fixed_point_iterator('a')) - Traceback (most recent call last): - ... - KeyError: 'c' - - We check that :trac:`8595` is fixed:: - - sage: s = WordMorphism({('a', 1):[('a', 1), ('a', 2)], ('a', 2):[('a', 1)]}) - sage: it = s._fixed_point_iterator(('a',1)) - sage: next(it) - ('a', 1) - - This shows that ticket :trac:`13668` has been resolved:: - - sage: s = WordMorphism({1:[1,2],2:[2,3],3:[4],4:[5],5:[6],6:[7],7:[8],8:[9],9:[10],10:[1]}) - sage: (s^7).fixed_points() - [word: 1223234234523456234567234567823456789234..., - word: 2,3,4,5,6,7,8,9,10,1,1,2,1,2,2,3,1,2,2,3,2,3,4,1,2,2,3,2,3,4,2,3,4,5,1,2,2,3,2,3,...] - sage: (s^7).reversal().fixed_points() - [] - """ - w = iter(self.image(letter)) - while True: - try: - for a in self.image(next(w)): - yield a - else: - next_w = next(w) - w = chain([next_w], w, self.image(next_w)) - except StopIteration: - return - - def fixed_point(self, letter): r""" Returns the fixed point of ``self`` beginning by the given ``letter``. @@ -1886,8 +1817,11 @@ def fixed_point(self, letter): parent = self.codomain() if self.is_growing(letter): - parent = parent.shift() - return parent(self._fixed_point_iterator(letter)) + from sage.combinat.words.word import InfiniteWord_morphic + return InfiniteWord_morphic(parent.shift(), self, letter) + else: + from sage.combinat.words.word import FiniteWord_morphic + return FiniteWord_morphic(parent, self, letter) def fixed_points(self): r""" diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 2ab59314376..b7854a8976d 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -34,6 +34,7 @@ WordDatatype_iter, WordDatatype_callable_with_caching, WordDatatype_callable) +from .morphic import WordDatatype_morphic from sage.monoids.free_monoid_element import FreeMonoidElement # TODO. Word needs to be replaced by Word. Consider renaming @@ -687,3 +688,88 @@ class Word_iter(WordDatatype_iter, Word_class): """ pass +##### Morphic Words ##### +class Word_morphic(WordDatatype_morphic, Word_class): + r""" + Morphic word of unknown length (finite or infinite). + + For such word `w`, type ``w.`` and hit TAB key to see the list of + functions defined on `w`. + + Words behave like a Python list : they can be sliced using + square braquets to define for example a prefix or a factor. + + EXAMPLES:: + + sage: w = 34 + sage: w + word: 1149114911491149114911491149114911491149... + + TESTS: + + Pickle is not supported for word of unknown length defined by an iterator:: + + sage: dumps(w) + + sage: + Traceback (most recent call last): + ... + TypeError: can...t...pickle...generator...object... + """ + pass + +class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): + r""" + Finite morphic word. + + For such word `w`, type ``w.`` and hit TAB key to see the list of + functions defined on `w`. + + EXAMPLES:: + + sage: print('update') + + TESTS:: + + sage: print('update') + sage: w = 22222 + sage: type(w) + + sage: z = loads(dumps(w)) + sage: w == z + True + sage: type(z) + + """ + pass + +class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): + r""" + Morphic word of infinite length. + + For such word `w`, type ``w.`` and hit TAB key to see the list of + functions defined on `w`. + + Infinite words behave like a Python list : they can be sliced using + square braquets to define for example a prefix or a factor. + + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w + + TESTS: + + Pickle is not supported for infinite word defined by an iterator:: + + sage: dumps(w) + + + sage: dumps(w) + Traceback (most recent call last): + ... + TypeError: can...t...pickle...generator...object... + """ + pass + From a3b025cbf649124df3402d5c2c696e80237ca203 Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Tue, 16 Feb 2021 16:29:52 +0100 Subject: [PATCH 293/355] 31378: incomplete changes --- src/sage/combinat/words/morphic.py | 41 ++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index c04313efa0e..3e9318174c9 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -17,11 +17,11 @@ """ -from sage.combinat.words.word_datatypes import WordDatatype +from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable from sage.rings.all import Infinity from sage.modules.free_module_element import vector -class WordDatatype_morphic(WordDatatype): +class WordDatatype_morphic(WordDatatype_callable): r""" Datatype for a word defined by a callable. """ @@ -37,25 +37,27 @@ def __init__(self, parent, morphism, letter, coding=None): EXAMPLES:: - sage: f = lambda n : 'x' if n % 2 == 0 else 'y' - sage: w = Word(f, length=9, caching=False); w - word: xyxyxyxyx - sage: type(w) - - sage: w.length() - 9 - + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w + word: abaababaabaababaababaabaababaabaababaaba... + sage: w[555:1000] + word: abaababaabaababaababaabaababaabaababaaba... + :: - sage: w = Word(f, caching=False); w - word: xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy... - sage: type(w) - - sage: w.length() is None - False - sage: w.length() - +Infinity + sage: m = WordMorphism('a->abc,b->baba,c->ca') + sage: m.fixed_point('a') + word: abcbabacababaabcbabaabccaabcbabaabcbabaa... + sage: w = m.fixed_point('a') + sage: w[7] + 'c' + sage: w[2:7] + word: cbaba + sage: w[500:503] + word: caa + TESTS:: sage: from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable @@ -66,6 +68,7 @@ def __init__(self, parent, morphism, letter, coding=None): """ self._len = Infinity self._parent = parent + # self._func = callable # for hashing self._hash = None @@ -117,7 +120,7 @@ def representation(self, n): k -= 1 return path - def __getitem__(self, key): + def _func(self, key): """ EXAMPLES:: From 1dbffb1cbcfdea739b594eb4b5904f128e901bc8 Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Thu, 18 Feb 2021 12:58:10 +0100 Subject: [PATCH 294/355] fixed doctests in morphic.py --- src/sage/combinat/words/morphic.py | 89 ++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 3e9318174c9..8d4fccdc4a5 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -13,7 +13,7 @@ Creation of a morphism:: - sage: n = WordMorphism(...) + sage: m = WordMorphism('a->abc,b->baba,c->ca') """ @@ -81,13 +81,36 @@ def __init__(self, parent, morphism, letter, coding=None): self._coding = coding def representation(self, n): - """ + r""" + Return the representation of the integer n in the numeration system + associated to the morphism. + + INPUT: + + - ``n`` -- nonnegative integer + + OUTPUT: + + list + EXAMPLES:: - sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w.representation(5) + [1, 0, 0, 0] + + TESTS: + + Accessing this method from an instance of the current class (no using + the inherited word classes):: + sage: m = WordMorphism('a->ab,b->a') sage: W = m.domain() - sage: w = WordDatatype_morphic(W,m,'a') + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: w = WordDatatype_morphic(W, m, 'a') + sage: type(w) + sage: w.representation(5) [1, 0, 0, 0] """ @@ -122,9 +145,40 @@ def representation(self, n): def _func(self, key): """ + Returns a letter of a fixed point of a morphism on position ``key``. + + INPUT: + + - ``self`` - a fixed point of a morphism + - ``key`` - an integer, the position + + OUTPUT: + + - a letter + EXAMPLES:: - sage: print('add doc + examples here') + sage: m = WordMorphism("a->ab,b->a") + sage: w = m.fixed_point("a") + sage: w[0] + 'a' + sage: w[5] + 'a' + sage: w[10000] + 'a' + + TESTS: + + Accessing this method from an instance of the current class (no using + the inherited word classes):: + + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: w = WordDatatype_morphic(W, m, 'a') + sage: w._func(5) + 'a' + """ letter = self._letter for a in self.representation(key): @@ -154,29 +208,40 @@ def __iter__(self): EXAMPLES:: + sage: m = WordMorphism("a->ab,b->a") + sage: w = m.fixed_point("a") + sage: it = iter(w) + sage: [next(it) for _ in range(10)] + ['a', 'b', 'a', 'a', 'b', 'a', 'b', 'a', 'a', 'b'] + + Works with erasing morphisms:: + sage: m = WordMorphism('a->abc,b->,c->') - sage: list(m._fixed_point_iterator('a')) + sage: w = m.fixed_point("a") + sage: list(w) ['a', 'b', 'c'] - sage: print('update the examples here') The morphism must be prolongable on the letter or the iterator will be empty:: - sage: list(m._fixed_point_iterator('b')) - [] + sage: list(m.fixed_point("b")) + Traceback (most recent call last): + ... + TypeError: self must be prolongable on b The morphism must be an endomorphism:: sage: m = WordMorphism('a->ac,b->aac') - sage: list(m._fixed_point_iterator('a')) + sage: w = m.fixed_point('a') Traceback (most recent call last): ... - KeyError: 'c' + TypeError: self (=a->ac, b->aac) is not an endomorphism We check that :trac:`8595` is fixed:: sage: s = WordMorphism({('a', 1):[('a', 1), ('a', 2)], ('a', 2):[('a', 1)]}) - sage: it = s._fixed_point_iterator(('a',1)) + sage: w = s.fixed_point(('a', 1)) + sage: it = iter(w) sage: next(it) ('a', 1) From 0914f3c171906aaea7c4df42ada6ef14fa9f18ce Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Sat, 20 Feb 2021 12:36:21 +0100 Subject: [PATCH 295/355] fixing some of the errors in word.py --- src/sage/combinat/words/word.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index b7854a8976d..dedadb4b6a4 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -9,6 +9,7 @@ - Sébastien Labbé - Franco Saliola + """ #***************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , @@ -727,19 +728,24 @@ class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): EXAMPLES:: - sage: print('update') + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w + word: ab + TESTS:: - sage: print('update') - sage: w = 22222 + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w + word: ab sage: type(w) - + sage: z = loads(dumps(w)) - sage: w == z - True - sage: type(z) - + Traceback (most recent call last): + ... + ValueError: not a correct value for length (+Infinity) """ pass @@ -758,18 +764,15 @@ class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): sage: m = WordMorphism('a->ab,b->a') sage: w = m.fixed_point('a') sage: w + word: abaababaabaababaababaabaababaabaababaaba... TESTS: Pickle is not supported for infinite word defined by an iterator:: - sage: dumps(w) - - sage: dumps(w) Traceback (most recent call last): ... TypeError: can...t...pickle...generator...object... """ pass - From 83d5aa2da0b5254cd580eb7d23c643f7c13bc539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Fri, 2 Apr 2021 10:29:04 +0200 Subject: [PATCH 296/355] 31378: fixing doctests in word.py --- src/sage/combinat/words/morphic.py | 83 +++++++++++++++++++++++++---- src/sage/combinat/words/morphism.py | 6 ++- src/sage/combinat/words/word.py | 47 +++------------- 3 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 8d4fccdc4a5..1d614480810 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -25,7 +25,7 @@ class WordDatatype_morphic(WordDatatype_callable): r""" Datatype for a word defined by a callable. """ - def __init__(self, parent, morphism, letter, coding=None): + def __init__(self, parent, morphism, letter, coding=None, length=Infinity): r""" INPUT: @@ -34,6 +34,8 @@ def __init__(self, parent, morphism, letter, coding=None): - ``letter`` - a starting letter - ``coding`` - dict (default: ``None``), if ``None`` the identity map is used for the coding + - ``length`` - integer or ``'finite'`` or ``Infinity`` or + ``'unknown'`` (default: ``Infinity``) the length of the word EXAMPLES:: @@ -43,6 +45,8 @@ def __init__(self, parent, morphism, letter, coding=None): word: abaababaabaababaababaabaababaabaababaaba... sage: w[555:1000] word: abaababaabaababaababaabaababaabaababaaba... + sage: w.length() + +Infinity :: @@ -57,20 +61,27 @@ def __init__(self, parent, morphism, letter, coding=None): sage: w[500:503] word: caa - - TESTS:: + When the morphic word is finite:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w + word: ab + sage: w.length() + 2 - sage: from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable - sage: WordDatatype_callable(Words(),lambda n:n%3) - - sage: WordDatatype_callable(Words([0,1,2]),lambda n:n%3) - """ - self._len = Infinity self._parent = parent # self._func = callable # for hashing self._hash = None + + if length is Infinity: + self._len = Infinity + elif length is None or length == 'unknown' or length == 'finite': + self._len = None + else: + self._len = length self._morphism = morphism self._letter = letter @@ -80,6 +91,46 @@ def __init__(self, parent, morphism, letter, coding=None): else: self._coding = coding + def __reduce__(self): + r""" + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w.__reduce__() + (, + (Infinite words over {'a', 'b'}, + WordMorphism: a->ab, b->a, + 'a', + {'a': 'a', 'b': 'b'}, + +Infinity)) + + Below is the behavior for words of finite length. When the word is + finite and reaches its end, it then learns its length:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w.__reduce__() + (, + (Finite words over {'a', 'b'}, + WordMorphism: a->ab, b->, + 'a', + {'a': 'a', 'b': 'b'}, + None)) + sage: w.length() + 2 + sage: w.__reduce__() + (, + (Finite words over {'a', 'b'}, + WordMorphism: a->ab, b->, + 'a', + {'a': 'a', 'b': 'b'}, + 2)) + + """ + return self.__class__, (self._parent, self._morphism, self._letter, + self._coding, self._len) + def representation(self, n): r""" Return the representation of the integer n in the numeration system @@ -100,6 +151,16 @@ def representation(self, n): sage: w.representation(5) [1, 0, 0, 0] + When the morphic word is finite:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w.representation(0) + [] + sage: w.representation(1) + [1] + sage: w.representation(2) # not tested: infinite loop + TESTS: Accessing this method from an instance of the current class (no using @@ -169,8 +230,8 @@ def _func(self, key): TESTS: - Accessing this method from an instance of the current class (no using - the inherited word classes):: + Accessing this method from an instance of the current class + (without using the inherited word classes):: sage: m = WordMorphism('a->ab,b->a') sage: W = m.domain() diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index c690528cf3e..8c7d88b7d33 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1818,10 +1818,12 @@ def fixed_point(self, letter): parent = self.codomain() if self.is_growing(letter): from sage.combinat.words.word import InfiniteWord_morphic - return InfiniteWord_morphic(parent.shift(), self, letter) + return InfiniteWord_morphic(parent.shift(), self, letter, + coding=None, length=Infinity) else: from sage.combinat.words.word import FiniteWord_morphic - return FiniteWord_morphic(parent, self, letter) + return FiniteWord_morphic(parent, self, letter, + coding=None, length='finite') def fixed_points(self): r""" diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index dedadb4b6a4..4762a5b55d6 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -690,35 +690,6 @@ class Word_iter(WordDatatype_iter, Word_class): pass ##### Morphic Words ##### -class Word_morphic(WordDatatype_morphic, Word_class): - r""" - Morphic word of unknown length (finite or infinite). - - For such word `w`, type ``w.`` and hit TAB key to see the list of - functions defined on `w`. - - Words behave like a Python list : they can be sliced using - square braquets to define for example a prefix or a factor. - - EXAMPLES:: - - sage: w = 34 - sage: w - word: 1149114911491149114911491149114911491149... - - TESTS: - - Pickle is not supported for word of unknown length defined by an iterator:: - - sage: dumps(w) - - sage: - Traceback (most recent call last): - ... - TypeError: can...t...pickle...generator...object... - """ - pass - class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): r""" Finite morphic word. @@ -738,14 +709,11 @@ class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): sage: m = WordMorphism("a->ab,b->") sage: w = m.fixed_point("a") - sage: w - word: ab sage: type(w) - sage: z = loads(dumps(w)) - Traceback (most recent call last): - ... - ValueError: not a correct value for length (+Infinity) + sage: loads(dumps(w)) + word: ab + """ pass @@ -768,11 +736,10 @@ class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): TESTS: - Pickle is not supported for infinite word defined by an iterator:: + Pickle is supported:: + + sage: loads(dumps(w)) + word: abaababaabaababaababaabaababaabaababaaba... - sage: dumps(w) - Traceback (most recent call last): - ... - TypeError: can...t...pickle...generator...object... """ pass From e4818d317e142422854aa0d2db67bd3ede75aca5 Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Thu, 15 Apr 2021 11:58:11 +0200 Subject: [PATCH 297/355] trying to repair the finite fixed point problem, something changed in word_infinite_datatypes.py, however --- src/sage/combinat/words/morphic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 1d614480810..bcf4f6a0bce 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -181,6 +181,8 @@ def representation(self, n): vMk = vector([1]*len(self._alphabet)) length_of_images = [vMk] while vMk[position] <= n: + if vMk == vMk*M: + raise ValueError('The morphism has a finite fixed point of length {}.'.format(vMk[position])) vMk = vMk*M length_of_images.append(vMk) length_of_images.pop() From 45efaeb17be51d752c72695a5f101c14bcb15ab1 Mon Sep 17 00:00:00 2001 From: Jana Lepsova Date: Thu, 6 May 2021 11:17:02 +0200 Subject: [PATCH 298/355] 31378: fix comment 13 --- src/sage/combinat/words/morphic.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index bcf4f6a0bce..1a0f77db1cb 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -67,6 +67,8 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: w = m.fixed_point("a") sage: w word: ab + sage: w[0] + 'a' sage: w.length() 2 @@ -153,13 +155,18 @@ def representation(self, n): When the morphic word is finite:: - sage: m = WordMorphism("a->ab,b->") + sage: m = WordMorphism("a->ab,b->,c->cdab,d->dcab") sage: w = m.fixed_point("a") sage: w.representation(0) [] sage: w.representation(1) [1] - sage: w.representation(2) # not tested: infinite loop + sage: w.representation(2) + Traceback (most recent call last): + ... + IndexError: Index (=2) out of range, the fixed point is finite and has length 2. + + TESTS: @@ -181,9 +188,10 @@ def representation(self, n): vMk = vector([1]*len(self._alphabet)) length_of_images = [vMk] while vMk[position] <= n: - if vMk == vMk*M: - raise ValueError('The morphism has a finite fixed point of length {}.'.format(vMk[position])) - vMk = vMk*M + vMk_next = vMk*M + if vMk[position] == vMk_next[position]: + raise IndexError('Index (={}) out of range, the fixed point is finite and has length {}.'.format(n,vMk[position])) + vMk = vMk_next length_of_images.append(vMk) length_of_images.pop() k = len(length_of_images) From 67b8c647636e906339c5715bb148d3b00df0d558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 6 May 2021 11:57:12 +0200 Subject: [PATCH 299/355] 31378: fixed remaining issue, added doctests --- src/sage/combinat/words/morphic.py | 61 ++++++++++++++++++++--------- src/sage/combinat/words/morphism.py | 9 ++++- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 1a0f77db1cb..eb865baeceb 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -11,9 +11,23 @@ EXAMPLES: -Creation of a morphism:: +Creation of the fixed point of a morphism:: sage: m = WordMorphism('a->abc,b->baba,c->ca') + sage: w = m.fixed_point('a') + sage: w + word: abcbabacababaabcbabaabccaabcbabaabcbabaa... + sage: w.length() + +Infinity + +Computing the n-th letter of a fixed point is fast as it is using the +abstract numeration system associated to the morphism and the starting +letter, see chapter 3 of the book [Valérie Berthé and Michel Rigo, editors. +Combinatorics, automata, and number theory, volume 135. Cambridge: +Cambridge University Press, 2010]:: + + sage: w[10000000] + 'b' """ @@ -23,7 +37,8 @@ class WordDatatype_morphic(WordDatatype_callable): r""" - Datatype for a word defined by a callable. + Datatype for a morphic word defined by a morphism, a starting letter + and a coding. """ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): r""" @@ -72,6 +87,29 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: w.length() 2 + Using the coding argument:: + + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: coding = {'a':'x', 'b':'y'} + sage: w = WordDatatype_morphic(W, m, 'a', coding=coding) + sage: [w[i] for i in range(10)] + ['x', 'y', 'x', 'x', 'y', 'x', 'y', 'x', 'x', 'y'] + + TESTS:: + + sage: m = WordMorphism('a->abcd,b->bbc,c->cddd,d->cba') + sage: w = m.fixed_point('a') + sage: it = iter(w) + sage: for _ in range(10000): _ = next(it) + sage: L = [next(it) for _ in range(10)]; L + ['d', 'd', 'd', 'c', 'd', 'd', 'd', 'c', 'b', 'a'] + sage: w[10000:10010] + word: dddcdddcba + sage: list(w[10000:10010]) == L + True + """ self._parent = parent # self._func = callable @@ -107,21 +145,11 @@ def __reduce__(self): {'a': 'a', 'b': 'b'}, +Infinity)) - Below is the behavior for words of finite length. When the word is - finite and reaches its end, it then learns its length:: + Below is the behavior for words of finite length:: sage: m = WordMorphism("a->ab,b->") sage: w = m.fixed_point("a") sage: w.__reduce__() - (, - (Finite words over {'a', 'b'}, - WordMorphism: a->ab, b->, - 'a', - {'a': 'a', 'b': 'b'}, - None)) - sage: w.length() - 2 - sage: w.__reduce__() (, (Finite words over {'a', 'b'}, WordMorphism: a->ab, b->, @@ -166,8 +194,6 @@ def representation(self, n): ... IndexError: Index (=2) out of range, the fixed point is finite and has length 2. - - TESTS: Accessing this method from an instance of the current class (no using @@ -186,14 +212,13 @@ def representation(self, n): position = letters_to_int[self._letter] M = self._morphism.incidence_matrix() vMk = vector([1]*len(self._alphabet)) - length_of_images = [vMk] + length_of_images = [] while vMk[position] <= n: + length_of_images.append(vMk) vMk_next = vMk*M if vMk[position] == vMk_next[position]: raise IndexError('Index (={}) out of range, the fixed point is finite and has length {}.'.format(n,vMk[position])) vMk = vMk_next - length_of_images.append(vMk) - length_of_images.pop() k = len(length_of_images) letter_k = self._letter n_k = n diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 8c7d88b7d33..746dbb2a97f 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1822,8 +1822,13 @@ def fixed_point(self, letter): coding=None, length=Infinity) else: from sage.combinat.words.word import FiniteWord_morphic - return FiniteWord_morphic(parent, self, letter, - coding=None, length='finite') + w = FiniteWord_morphic(parent, self, letter, + coding=None, length='finite') + # since FiniteWord_morphic uses the method __getitem__ + # from FiniteWord_callable, the length must be precomputed + # for __getitem__ to work properly + w.length() + return w def fixed_points(self): r""" From aeb9935c6290d08f27d9c0347e5d830f13474229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 6 May 2021 12:07:05 +0200 Subject: [PATCH 300/355] 31378: adding reference in the good place --- src/doc/en/reference/references/index.rst | 3 +++ src/sage/combinat/words/morphic.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index c022be01e1e..a9442ec1b35 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1132,6 +1132,9 @@ REFERENCES: *The Whirlpool hashing function*; in First Open NESSIE Workshop, (2000). +.. [BR2010] Valérie Berthé and Michel Rigo, editors. Combinatorics, automata, + and number theory, volume 135. Cambridge: Cambridge University Press, 2010. + .. [Br2016] *Bresenham's Line Algorithm*, Python, 26 December 2016. http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index eb865baeceb..ec83acc744f 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -22,9 +22,7 @@ Computing the n-th letter of a fixed point is fast as it is using the abstract numeration system associated to the morphism and the starting -letter, see chapter 3 of the book [Valérie Berthé and Michel Rigo, editors. -Combinatorics, automata, and number theory, volume 135. Cambridge: -Cambridge University Press, 2010]:: +letter, see chapter 3 of the book [BR2010]_:: sage: w[10000000] 'b' From 7a4af939eb2dbe7a2f2f3d3426b1242991e5b66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 24 Jun 2021 11:04:06 +0200 Subject: [PATCH 301/355] 31378: Returns -> Return --- src/sage/combinat/words/morphic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index ec83acc744f..5ed0c8bb001 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -239,7 +239,7 @@ def representation(self, n): def _func(self, key): """ - Returns a letter of a fixed point of a morphism on position ``key``. + Return a letter of a fixed point of a morphism on position ``key``. INPUT: @@ -283,7 +283,7 @@ def _func(self, key): def __iter__(self): r""" - Returns an iterator of the letters of the fixed point of ``self`` + Return an iterator of the letters of the fixed point of ``self`` starting with ``letter``. If w is the iterated word, then this iterator: outputs the elements From 79c2834778aaa5238e530fd61e7fadb3cea2db23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 24 Jun 2021 11:05:07 +0200 Subject: [PATCH 302/355] 31378: fix ref duplicate [BR2010] -> [BR2010b] --- src/doc/en/reference/references/index.rst | 55 ++++++++++++----------- src/sage/combinat/words/morphic.py | 2 +- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index a9442ec1b35..9268a94badc 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1070,6 +1070,27 @@ REFERENCES: *Reverse-Engineering the S-Box of Streebog, Kuznyechik and STRIBOBr1*; in EuroCrypt'16, pp. 372-402. +.. [Br1910] Bruckner, "Uber die Ableitung der allgemeinen Polytope und + die nach Isomorphismus verschiedenen Typen der allgemeinen + Achtzelle (Oktatope)", Verhand. Konik. Akad. Wetenschap, + Erste Sectie, 10 (1910) + +.. [Br2000] Kenneth S. Brown, *Semigroups, rings, and Markov chains*, + :arxiv:`math/0006145v1`. + + +.. [BR2000a] \P. Barreto and V. Rijmen, + *The ANUBIS Block Cipher*; in + First Open NESSIE Workshop, (2000). + +.. [BR2000b] \P. Barreto and V. Rijmen, + *The Khazad legacy-level Block Cipher*; in + First Open NESSIE Workshop, (2000). + +.. [BR2000c] \P. Barreto and V. Rijmen, + *The Whirlpool hashing function*; in + First Open NESSIE Workshop, (2000). + .. [BR2010] Matthew Baker and Robert Rumely. Potential theory and dynamics on the Berkovich projective line. Mathematical Surveys and Monographs, Volumne 159. 2010. @@ -1078,6 +1099,13 @@ REFERENCES: *Noncommutative Rational Series With Applications*. Cambridge, 2010. +.. [BR2010b] Valérie Berthé and Michel Rigo, editors. Combinatorics, automata, + and number theory, volume 135. Cambridge: Cambridge University Press, 2010. + +.. [Br2016] *Bresenham's Line Algorithm*, Python, 26 December 2016. + http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm + + .. [Brandes01] Ulrik Brandes, A faster algorithm for betweenness centrality, Journal of Mathematical Sociology 25.2 (2001): 163-177, @@ -1111,33 +1139,6 @@ REFERENCES: .. [Bro2016] \A.E. Brouwer, Personal communication, 2016. -.. [Br1910] Bruckner, "Uber die Ableitung der allgemeinen Polytope und - die nach Isomorphismus verschiedenen Typen der allgemeinen - Achtzelle (Oktatope)", Verhand. Konik. Akad. Wetenschap, - Erste Sectie, 10 (1910) - -.. [Br2000] Kenneth S. Brown, *Semigroups, rings, and Markov chains*, - :arxiv:`math/0006145v1`. - - -.. [BR2000a] \P. Barreto and V. Rijmen, - *The ANUBIS Block Cipher*; in - First Open NESSIE Workshop, (2000). - -.. [BR2000b] \P. Barreto and V. Rijmen, - *The Khazad legacy-level Block Cipher*; in - First Open NESSIE Workshop, (2000). - -.. [BR2000c] \P. Barreto and V. Rijmen, - *The Whirlpool hashing function*; in - First Open NESSIE Workshop, (2000). - -.. [BR2010] Valérie Berthé and Michel Rigo, editors. Combinatorics, automata, - and number theory, volume 135. Cambridge: Cambridge University Press, 2010. - -.. [Br2016] *Bresenham's Line Algorithm*, Python, 26 December 2016. - http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm - .. [Bro1982] \A. Brouwer, *Polarities of G. Higman's symmetric design and a strongly regular graph on 176 vertices*, diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 5ed0c8bb001..b87f3a5868d 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -22,7 +22,7 @@ Computing the n-th letter of a fixed point is fast as it is using the abstract numeration system associated to the morphism and the starting -letter, see chapter 3 of the book [BR2010]_:: +letter, see chapter 3 of the book [BR2010b]_:: sage: w[10000000] 'b' From 7e2b1deabdaf20a8e78629ed69a356af4c4b0846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 30 Sep 2021 11:17:03 +0200 Subject: [PATCH 303/355] 32438: added documentation for option 'backward' --- src/sage/graphs/generic_graph.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6d98c543f5f..2b29a816127 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -20656,7 +20656,12 @@ def graphviz_string(self, **options): - ``"label_style"`` (``"string"`` or ``"latex"``) - ``"edge_string"`` (``"--"`` or ``"->"``) - ``"dir"`` (``"forward"``, ``"back"``, ``"both"`` or ``"none"``) - - ``"backward"`` (boolean) + - ``"backward"`` (boolean), instead of defining the edge in the + graphviz string as ``u -> v`` it draws it as ``v -> u + [dir=back]`` and instead of ``u -> v [dir=back]`` it draws it as + ``v -> u``, this changes the way it is drawn by Graphviz's dot + program: vertex ``v`` will be *above* vertex ``u`` instead of + below. Here we state that the graph should be laid out so that edges starting from ``1`` are going backward (e.g. going up instead of From 88984334157b63794b4f52c111a48be5a547b8a1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 30 Sep 2021 11:28:09 +0200 Subject: [PATCH 304/355] simpler fix, by replacing only statement ending \n and # with ;\n; and ;#; --- src/doc/en/developer/coding_in_python.rst | 2 +- src/sage/repl/interpreter.py | 557 +--------------------- src/sage/repl/preparse.py | 132 ++--- 3 files changed, 91 insertions(+), 600 deletions(-) diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 3e3143bf09c..1d8b7c1d3bf 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -238,7 +238,7 @@ replacements are made: sage: R. = QQ[] sage: preparse('R. = QQ[]') - "R = QQ['x', 'y']; (x, y,) = R._first_ngens(2)" + "R = QQ['x, y']; (x, y,) = R._first_ngens(2)" - Integer and real literals are Sage integers and Sage floating point numbers. For example, in pure Python these would be an attribute diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 205eaf0f884..71dbe429fdd 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -146,15 +146,12 @@ from sage.repl.configuration import sage_ipython_config, SAGE_EXTENSION from IPython.core.interactiveshell import InteractiveShell -from IPython.core.prefilter import PrefilterTransformer -from IPython.core.crashhandler import CrashHandler -from IPython.core.inputtransformer2 import (PromptStripper, - TokenTransformBase, - tokenize) - from IPython.terminal.interactiveshell import TerminalInteractiveShell +from IPython.core.inputtransformer2 import PromptStripper +from IPython.core.prefilter import PrefilterTransformer from IPython.terminal.embed import InteractiveShellEmbed from IPython.terminal.ipapp import TerminalIPythonApp, IPAppCrashHandler +from IPython.core.crashhandler import CrashHandler # TODO: This global variable _do_preparse should be associated with an @@ -399,59 +396,18 @@ def run_cell(self, *args, **kwds): # Transformers used in the SageInputSplitter ################################################################### + def SagePreparseTransformer(lines): r""" EXAMPLES:: sage: from sage.repl.interpreter import SagePreparseTransformer - sage: SagePreparseTransformer(['1+1r+2.3^2.3r\n']) + sage: spt = SagePreparseTransformer + sage: spt(['1+1r+2.3^2.3r\n']) ["Integer(1)+1+RealNumber('2.3')**2.3\n"] sage: preparser(False) - sage: SagePreparseTransformer(['2.3^2\n']) + sage: spt(['2.3^2\n']) ['2.3^2\n'] - sage: preparser(True) - - Numbers are parsed as Sage's numbers unless an ``r`` is appended:: - - sage: from sage.repl.interpreter import SagePreparseTransformer - sage: SagePreparseTransformer(["2+2r + 4"]) - ['Integer(2)+2 + Integer(4)'] - sage: SagePreparseTransformer(["def foo():\n", " return 2"]) - ['def foo():\n', ' return Integer(2)'] - - Multiline-strings are left as they are:: - - sage: SagePreparseTransformer(["def foo():\n", " return a + '''\n", " 2 - 3r\n", " '''"]) - ['def foo():\n', " return a + '''\n", ' 2 - 3r\n', " '''"] - - Preparses ``[0,2,..,n]`` notation:: - - sage: SagePreparseTransformer(["for i in [2 .. 5 ..a]"]) - ['for i in (ellipsis_range(Integer(2) ,Ellipsis, Integer(5) ,Ellipsis,a))'] - sage: SagePreparseTransformer(["for i in (2 .. 5r)"]) - ['for i in (ellipsis_iter(Integer(2) ,Ellipsis, 5))'] - - Preparses generator access:: - - sage: SagePreparseTransformer(["K = QuadraticField(2)\n", "print(K.0)"]) - ['K = QuadraticField(Integer(2))\n', 'print(K.gen(0))'] - - Preparses implicit multiplication:: - - sage: SagePreparseTransformer(["2a"]) - ['2a'] - sage: implicit_multiplication(True) - sage: SagePreparseTransformer(["2a"]) - ['Integer(2)*a'] - sage: implicit_multiplication(False) - - Replaces ``^`` by exponentiation and ``^^`` as bitwise xor:: - - sage: SagePreparseTransformer(["x^2"]) - ['x**Integer(2)'] - sage: SagePreparseTransformer(["x^^2"]) - ['x^Integer(2)'] - TESTS: @@ -461,14 +417,14 @@ def SagePreparseTransformer(lines): sage: preparser(True) sage: bad_syntax = "R. = QQ{]" sage: preparse(bad_syntax) - 'R = QQ{]; (t,) = R._first_ngens(1)' + Traceback (most recent call last): + ... + SyntaxError: Mismatched ']' sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: shell.run_cell(bad_syntax) - File "...", line 1 - R = QQ{]; (t,) = R._first_ngens(1) - ^ - SyntaxError: invalid syntax + File "", line unknown + SyntaxError: Mismatched ']' sage: shell.quit() @@ -497,495 +453,6 @@ def SagePreparseTransformer(lines): SagePromptTransformer = PromptStripper(prompt_re=re.compile(r'^(\s*(:?sage: |\.\.\.\.: ))+')) -class SageGenConstructionTransformer(TokenTransformBase): - r""" - Transform Sage's construction with generators. - - TESTS:: - - sage: from IPython import get_ipython - sage: ip = get_ipython() - - Vanilla:: - - sage: ip.transform_cell(''' - ....: R. = ZZ['x']''') - "R = ZZ['x']; (x,) = R._first_ngens(1)\n" - sage: ip.transform_cell(''' - ....: R. = ZZ['x,y']''') - "R = ZZ['x,y']; (x, y,) = R._first_ngens(2)\n" - - No square brackets:: - - sage: ip.transform_cell(''' - ....: R. = PolynomialRing(ZZ, 'x')''') - "R = PolynomialRing(ZZ, 'x', names=('x',)); (x,) = R._first_ngens(1)\n" - sage: ip.transform_cell(''' - ....: R. = PolynomialRing(ZZ, 'x,y')''') - "R = PolynomialRing(ZZ, 'x,y', names=('x', 'y',)); (x, y,) = R._first_ngens(2)\n" - - Names filled in:: - - sage: ip.transform_cell(''' - ....: R. = ZZ[]''') - "R = ZZ['x']; (x,) = R._first_ngens(1)\n" - sage: ip.transform_cell(''' - ....: R. = ZZ[]''') - "R = ZZ['x', 'y']; (x, y,) = R._first_ngens(2)\n" - - Names given not the same as generator names:: - - sage: ip.transform_cell(''' - ....: R. = ZZ['y']''') - "R = ZZ['y']; (x,) = R._first_ngens(1)\n" - sage: ip.transform_cell(''' - ....: R. = ZZ['u,v']''') - "R = ZZ['u,v']; (x, y,) = R._first_ngens(2)\n" - - Number fields:: - - sage: ip.transform_cell(''' - ....: K. = QuadraticField(2)''') - "K = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1)\n" - sage: ip.transform_cell(''' - ....: K. = QQ[2^(1/3)]''') - 'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(1)\n' - sage: ip.transform_cell(''' - ....: K. = QQ[2^(1/3), 2^(1/2)]''') - 'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)\n' - - Just the ``.<>`` notation:: - - sage: ip.transform_cell(''' - ....: R. = ZZx''') - 'R = ZZx; (x,) = R._first_ngens(1)\n' - sage: ip.transform_cell(''' - ....: R. = a+b''') - 'R = a+b; (x, y,) = R._first_ngens(2)\n' - sage: ip.transform_cell(''' - ....: A.=FreeAlgebra(ZZ,3)''') - "A=FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)\n" - - Ensure we do not eat too much:: - - sage: ip.transform_cell(''' - ....: R. = ZZ;2''') - 'R = ZZ; (x, y,) = R._first_ngens(2);Integer(2)\n' - sage: ip.transform_cell(''' - ....: R. = ZZ['x,y'];2''') - "R = ZZ['x,y']; (x, y,) = R._first_ngens(2);Integer(2)\n" - sage: ip.transform_cell(''' - ....: F., f, g = S.field_extension()''') - "F, f, g = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)\n" - - Multiple lines:: - - sage: ip.transform_cell(''' - ....: K. = some_large_field( - ....: input1, - ....: input2, - ....: intput3)''') - "K = some_large_field(\n input1,\n input2,\n intput3, names=('a', 'b', 'c',)); (a, b, c,) = K._first_ngens(3)\n" - sage: ip.transform_cell(''' - ....: def foo(L): - ....: K.= L - ....: return K, a, b, c''') - 'def foo(L):\n K= L; (a, b, c,) = K._first_ngens(3)\n return K, a, b, c\n' - sage: ip.transform_cell(''' - ....: def foo(L, M): - ....: K1., K2. = L, M - ....: return a,b,c,d,e''') - 'def foo(L, M):\n K1, K2 = L, M; (d, e,) = K2._first_ngens(2); (a, b, c,) = K1._first_ngens(3)\n return a,b,c,d,e\n' - sage: ip.transform_cell(''' - ....: def p in primes(2, 20): - ....: K. = QuadraticField(p); print(a)''') - "def p in primes(Integer(2), Integer(20)):\n K = QuadraticField(p, names=('a',)); (a,) = K._first_ngens(1); print(a)\n" - - See :trac:`16731`:: - - sage: ip.transform_cell(''' - ....: R. = ''') - 'R = ; (x,) = R._first_ngens(1)\n' - - Check support for unicode characters (:trac:`29278`):: - - sage: ip.transform_cell(''' - ....: Ω.<λ,μ> = QQ[]''') - "Ω = QQ['λ', 'μ']; (λ, μ,) = Ω._first_ngens(2)\n" - - Check that :trac:`30953` is fixed:: - - sage: K. = QuadraticField(2 + # some comment - ....: 1); K, a - (Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878?, - a) - """ - priority = 25 - - def __init__(self, del_start, del_end, keyword_pos, argument_pos, insert_pos, name, gens): - """ - INPUT: - - - ``del_start`` -- start of the ``<`` - - - ``del_end`` -- end of the ``>`` - - - ``keyword_pos`` -- position to insert generator names as keyword or ``None`` - - - ``argument_pos`` -- position to insert generator names as arguments or ``None`` - - - ``names_pos`` -- position to insert the additional command to declare the generators - - - ``name`` -- name of the field or similar - - - ``gens`` -- names of the generators - - TESTS:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageGenConstructionTransformer - sage: lines = ['K. = QQ[]'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageGenConstructionTransformer.find(tokens) # indirect doctest - sage: S.transform(lines) - ["K = QQ['a', 'b']; (a, b,) = K._first_ngens(2)"] - """ - super().__init__(del_start) - self.name = name - self.gens = gens - - # Shift from 1-index to 0-indexed. - self.del_start = (del_start[0] - 1, del_start[1]) - self.del_end = (del_end[0] - 1, del_end[1]) - self.insert_pos = (insert_pos[0] - 1, insert_pos[1]) - self.keyword_pos = (keyword_pos[0] - 1, keyword_pos[1]) if keyword_pos is not None else None - self.argument_pos = (argument_pos[0] - 1, argument_pos[1]) if argument_pos is not None else None - - @classmethod - def find(cls, tokens_by_line): - r""" - Find the first construction with generators. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageGenConstructionTransformer - sage: lines = ['for p in primes(2, 20):\n', ' K. = QuadraticField(p)\n', ' print(a)'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageGenConstructionTransformer.find(tokens) - sage: S.transform(lines) - ['for p in primes(2, 20):\n', - " K = QuadraticField(p, names=('a',)); (a,) = K._first_ngens(1)\n", - ' print(a)'] - """ - for line in tokens_by_line: - name = None - gens = [] - for i, token in enumerate(line[2:], 2): - if token.string == '<' and line[i-1].string == '.' and token.start == line[i-1].end and line[i-2].type == tokenize.NAME: - if name is None: - name = line[i-2].string - del_start = line[i-1].start - else: - # Do not transform syntax errors. - break - elif token.string == '<': - # Do not transform syntax errors. - break - elif name is None: - continue - elif token.type == tokenize.NAME: - gens.append(token.string) - elif token.string[:1] == '>': - del_end = (token.start[0], token.start[1] + 1) - - if del_end[0] != del_start[0]: - # The generators must be written in one line. - break - if gens == []: - # At least one generator needed. - break - - # Find the position to insert the declaration of the generators. - ix = i + 1 - while not line[ix].string == ';' and not line[ix].type == tokenize.NEWLINE and ix + 1 < len(line): - ix += 1 - while line[ix - 1].type == tokenize.COMMENT: - ix -= 1 - insert_pos = line[ix].start - - # See if the names of the generators need to be given as keyword or argument. - keyword_pos = None - argument_pos = None - ix -= 1 - while line[ix].type in {tokenize.COMMENT, tokenize.NL}: - ix -= 1 - if line[ix].string == ')': - keyword_pos = True - elif line[ix].string == ']': - while line[ix-1].string == ']': - ix -= 1 - argument_pos = True - - if argument_pos or keyword_pos: - ix -= 1 - while line[ix].type in {tokenize.COMMENT, tokenize.NL}: - ix -= 1 - if keyword_pos: - keyword_pos = line[ix].end - else: - if line[ix].string == '[': - argument_pos = line[ix].end - else: - argument_pos = None - - return cls(del_start, del_end, keyword_pos, argument_pos, insert_pos, name, gens) - elif token.string != ',': - # Do not transform syntax errors. - break - - def transform(self, lines): - r""" - Transform the first construction with generators. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageGenConstructionTransformer - sage: lines = ['F., f, g = S.field_extension()'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageGenConstructionTransformer.find(tokens) - sage: S.transform(lines) - ["F, f, g = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)"] - """ - lines = [l for l in lines] - - new_command = '; (' + ', '.join(self.gens) + ',) = ' + self.name \ - + "._first_ngens({})".format(len(self.gens)) - lines[self.insert_pos[0]] = lines[self.insert_pos[0]][:self.insert_pos[1]] \ - + new_command \ - + lines[self.insert_pos[0]][self.insert_pos[1]:] - - if self.argument_pos or self.keyword_pos: - names = "'" + "', '".join(self.gens) + "'" - if self.keyword_pos: - names_pos = self.keyword_pos - names = "names=(" + names - if len(self.gens): - names += "," - names += ")" - else: - names_pos = self.argument_pos - if lines[names_pos[0]][names_pos[1] - 1] not in ('(', '['): - names = ", " + names - lines[names_pos[0]] = lines[names_pos[0]][:names_pos[1]] + names \ - + lines[names_pos[0]][names_pos[1]:] - - lines[self.del_start[0]] = lines[self.del_start[0]][:self.del_start[1]] \ - + lines[self.del_start[0]][self.del_end[1]:] - - return lines - - -class SageCalculusTransformer(TokenTransformBase): - r""" - Supports calculus-like function assignment, e.g., transforms:: - - f(x,y,z) = sin(x^3 - 4*y) + y^x - - into:: - - __tmp__=var("x,y,z") - f = symbolic_expression(sin(x**3 - 4*y) + y**x).function(x,y,z) - - TESTS: - - sage: from IPython import get_ipython - sage: ip = get_ipython() - sage: ip.transform_cell(''' - ....: f(x) = x^3 - x''') - '__tmp__ = var("x"); __tmpf__ = x**Integer(3) - x; f = symbolic_expression(__tmpf__).function(x)\n' - sage: ip.transform_cell(''' - ....: f(u,v) = u - v''') - '__tmp__ = var("u,v"); __tmpf__ = u - v; f = symbolic_expression(__tmpf__).function(u,v)\n' - sage: ip.transform_cell(''' - ....: f(x) =-5''') - '__tmp__ = var("x"); __tmpf__ =-Integer(5); f = symbolic_expression(__tmpf__).function(x)\n' - sage: ip.transform_cell(''' - ....: f(x) -= 5''') - 'f(x) -= Integer(5)\n' - sage: ip.transform_cell(''' - ....: f(x_1, x_2) = x_1^2 - x_2^2''') - '__tmp__ = var("x_1,x_2"); __tmpf__ = x_1**Integer(2) - x_2**Integer(2); f = symbolic_expression(__tmpf__).function(x_1,x_2)\n' - - sage: ip.transform_cell(''' - ....: f(t,s)=t^2''') - '__tmp__ = var("t,s"); __tmpf__=t**Integer(2); f = symbolic_expression(__tmpf__).function(t,s)\n' - - - sage: ip.transform_cell(''' - ....: f(x, y) = x^3 - y''') - '__tmp__ = var("x,y"); __tmpf__ = x**Integer(3) - y; f = symbolic_expression(__tmpf__).function(x,y)\n' - sage: ip.transform_cell(''' - ....: μ(x,y) = (x^3 - - ....: y)''') - '__tmp__ = var("x,y"); __tmpμ__ = (x**Integer(3) -\n y); μ = symbolic_expression(__tmpμ__).function(x,y)\n' - sage: ip.transform_cell(''' - ....: f(x, - ....: y) = (x^3 - - ....: y)''') - '__tmp__ = var("x,y"); __tmpf__ = (x**Integer(3) -\n y); f = symbolic_expression(__tmpf__).function(x,y)\n' - sage: ip.transform_cell(''' - ....: def foo: - ....: f(x, - ....: y) = (x^3 - - ....: y); return f''') - 'def foo:\n __tmp__ = var("x,y"); __tmpf__ = (x**Integer(3) -\n y); f = symbolic_expression(__tmpf__).function(x,y); return f\n' - - Check that :trac:`30953` is fixed:: - - sage: f(x) = (x + - ....: 1); f - x |--> x + 1 - sage: f(x, # Some comment - ....: y, - ....: z) = (x + # Some comment - ....: y + - ....: z); f - (x, y, z) |--> x + y + z - """ - priority = 30 - - def __init__(self, del_start, del_end, insert_pos, name, variables): - """ - INPUT: - - - ``del_start`` -- start of the name of the function - - - ``del_end`` -- end of the ``)`` - - - ``insert_pos`` -- position to insert the new command - - - ``name`` -- name of the field or similar - - - ``variables`` -- names of the variables - - TESTS:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageCalculusTransformer - sage: lines = ['f(z,zz) = z + zz\n'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageCalculusTransformer.find(tokens) # indirect doctest - sage: S.transform(lines) - ['__tmp__ = var("z,zz"); __tmpf__ = z + zz; f = symbolic_expression(__tmpf__).function(z,zz)\n'] - """ - super().__init__(del_start) - self.name = name - self.variables= variables - - # Shift from 1-index to 0-indexed. - self.del_end = (del_end[0] - 1, del_end[1]) - self.insert_pos = (insert_pos[0] - 1, insert_pos[1]) - - @classmethod - def find(cls, tokens_by_line): - r""" - Find the first calculus-like function assignment. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageCalculusTransformer - sage: lines = ['for i in range(2,20)):\n', ' f(x) = i*x\n'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageCalculusTransformer.find(tokens) - sage: S.transform(lines) - ['for i in range(2,20)):\n', - ' __tmp__ = var("x"); __tmpf__ = i*x; f = symbolic_expression(__tmpf__).function(x)\n'] - """ - for line in tokens_by_line: - name = None - for i, token in enumerate(line[:-1]): - if token.string == ')' and line[i+1].string == '=': - # Find matching '(' - variables = [] - ix = i - 1 - while ix >= 1: - if line[ix].string == '(': - break - elif line[ix].string == ',': - pass - elif line[ix].type == tokenize.NAME: - variables = [line[ix].string] + variables - elif line[ix].type not in {tokenize.NL, tokenize.COMMENT}: - ix = 1 - ix -= 1 - else: - # Incorrect syntax or first token is '('. - break - - if line[ix - 1].type != tokenize.NAME: - # A tuple assignment. - break - - name = line[ix - 1].string - - del_start = line[ix - 1].start - del_end = token.end - - # Find the position to insert the declaration of the generators. - ix = i + 1 - while (not line[ix].string == ';' - and not line[ix].type == tokenize.NEWLINE - and ix + 1 < len(line)): - ix += 1 - while line[ix - 1].type == tokenize.COMMENT: - ix -= 1 - insert_pos = line[ix].start - - return cls(del_start, del_end, insert_pos, name, variables) - - - def transform(self, lines): - r""" - Find the first calculus-like function assignment. - - EXAMPLES:: - - sage: from IPython.core.inputtransformer2 import make_tokens_by_line - sage: from sage.repl.interpreter import SageCalculusTransformer - sage: lines = ['f(x,y,z) = sqrt(x) - y^z\n'] - sage: tokens = make_tokens_by_line(lines) - sage: S = SageCalculusTransformer.find(tokens) - sage: S.transform(lines) - ['__tmp__ = var("x,y,z"); __tmpf__ = sqrt(x) - y^z; f = symbolic_expression(__tmpf__).function(x,y,z)\n'] - """ - start_line, start_col = self.start_line, self.start_col - - lines = [l for l in lines] - - tmpf = '__tmp{}__'.format(self.name) - variables = ','.join(self.variables) - line2 = '; {} = symbolic_expression({}).function({})'.format(self.name, tmpf, variables) - - lines[self.insert_pos[0]] = lines[self.insert_pos[0]][:self.insert_pos[1]] \ - + line2 \ - + lines[self.insert_pos[0]][self.insert_pos[1]:] - - line1 = lines[start_line][:start_col] + '__tmp__ = var("{}")'.format(variables) + "; " + tmpf - line1 += lines[self.del_end[0]][self.del_end[1]:] - - lines_before = lines[:start_line] - lines_after = lines[self.del_end[0] + 1:] - - return lines_before + [line1] + lines_after - - -SageTokenTransformers = [SageGenConstructionTransformer, - SageCalculusTransformer] - - ################### # Interface shell # ################### diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 62b8afc9ea1..6d6b858a7e2 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -100,7 +100,7 @@ expression:: sage: preparse('a(x) =- 5') - '__tmp__ = var("x"); __tmpa__ =- Integer(5); a = symbolic_expression(__tmpa__).function(x)' + '__tmp__=var("x"); a = symbolic_expression(- Integer(5)).function(x)' sage: f(x)=-x sage: f(10) -10 @@ -223,7 +223,7 @@ - Robert Bradshaw (2008-09-23): factor out constants -- Robert Bradshaw (2000-01): simplify preparser by making it modular and using +- Robert Bradshaw (2009-01): simplify preparser by making it modular and using regular expressions; bug fixes, complex numbers, and binary input """ @@ -242,7 +242,6 @@ from types import SimpleNamespace -from sage.misc.superseded import deprecation from sage.repl.load import load_wrap implicit_mul_level = False @@ -1414,25 +1413,21 @@ def preparse_calculus(code): EXAMPLES:: sage: preparse("f(x) = x^3-x") - '__tmp__ = var("x"); __tmpf__ = x**Integer(3)-x; f = symbolic_expression(__tmpf__).function(x)' + '__tmp__=var("x"); f = symbolic_expression(x**Integer(3)-x).function(x)' sage: preparse("f(u,v) = u - v") - '__tmp__ = var("u,v"); __tmpf__ = u - v; f = symbolic_expression(__tmpf__).function(u,v)' + '__tmp__=var("u,v"); f = symbolic_expression(u - v).function(u,v)' sage: preparse("f(x) =-5") - '__tmp__ = var("x"); __tmpf__ =-Integer(5); f = symbolic_expression(__tmpf__).function(x)' + '__tmp__=var("x"); f = symbolic_expression(-Integer(5)).function(x)' sage: preparse("f(x) -= 5") 'f(x) -= Integer(5)' sage: preparse("f(x_1, x_2) = x_1^2 - x_2^2") - '__tmp__ = var("x_1,x_2"); __tmpf__ = x_1**Integer(2) - x_2**Integer(2); f = symbolic_expression(__tmpf__).function(x_1,x_2)' + '__tmp__=var("x_1,x_2"); f = symbolic_expression(x_1**Integer(2) - x_2**Integer(2)).function(x_1,x_2)' For simplicity, this function assumes all statements begin and end with a semicolon:: sage: from sage.repl.preparse import preparse_calculus sage: preparse_calculus(";f(t,s)=t^2;") - doctest:warning - ... - DeprecationWarning: The method preparse_calculus is deprecated; use sage.repl.intepreter.SageCalculusTransformer instead. - See https://trac.sagemath.org/31951 for details. ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);' sage: preparse_calculus(";f( t , s ) = t^2;") ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);' @@ -1454,16 +1449,20 @@ def preparse_calculus(code): sage: from sage.repl.preparse import preparse_file sage: preparse_file("f(1)=x") - '_sage_const_1 = Integer(1)\n__tmp__ = var("_sage_const_1"); __tmpf__=x; f = symbolic_expression(__tmpf__).function(_sage_const_1)' + Traceback (most recent call last): + ... + ValueError: Argument names should be valid python identifiers. sage: from sage.repl.preparse import preparse_file sage: preparse_file("f(x,1)=2") - '_sage_const_1 = Integer(1); _sage_const_2 = Integer(2)\n__tmp__ = var("x,_sage_const_1"); __tmpf__=_sage_const_2 ; f = symbolic_expression(__tmpf__).function(x,_sage_const_1)' + Traceback (most recent call last): + ... + ValueError: Argument names should be valid python identifiers. Check support for unicode characters (:trac:`29278`):: sage: preparse("μ(x) = x^2") - '__tmp__ = var("x"); __tmpμ__ = x**Integer(2); μ = symbolic_expression(__tmpμ__).function(x)' + '__tmp__=var("x"); μ = symbolic_expression(x**Integer(2)).function(x)' Check that the parameter list can span multiple lines (:trac:`30928`):: @@ -1473,15 +1472,19 @@ def preparse_calculus(code): ....: c, ....: d) = a + b*2 + c*3 + d*4 ....: ''') - '\n__tmp__ = var("a,b,c,d"); __tmpf__ = a + b*Integer(2) + c*Integer(3) + d*Integer(4); f = symbolic_expression(__tmpf__).function(a,b,c,d)\n' + '\n__tmp__=var("a,b,c,d"); f = symbolic_expression(a + b*Integer(2) + c*Integer(3) + d*Integer(4)).function(a,b,c,d)\n' + Check that :trac:`30953` is fixed:: + + sage: preparse(''' + ....: f(x) = (x + (x*x) + # some comment with matching ) + ....: 1); f''') + '\n__tmp__=var("x"); f = symbolic_expression((x + (x*x) + # some comment with matching )\n Integer(1))).function(x); f' """ - deprecation(31951, "The method preparse_calculus is deprecated; use " - "sage.repl.intepreter.SageCalculusTransformer instead.") new_code = [] last_end = 0 # f ( vars ) = expr - for m in re.finditer(r";(\s*)([^\W\d]\w*) *\(([^()]+)\) *= *([^;#=][^;#]*)", code): + for m in re.finditer(r";(\s*)([^\W\d]\w*) *\(([^()]+)\) *= *([^;#=][^;]*)", code): ident, func, vars, expr = m.groups() # Semicolons are removed in order to allow the vars to span multiple lines. # (preparse having converted all \n into ;\n;) @@ -1581,7 +1584,7 @@ def preparse_generators(code): sage: preparse("R. = ZZ[]") "R = ZZ['x']; (x,) = R._first_ngens(1)" sage: preparse("R. = ZZ[]") - "R = ZZ['x', 'y']; (x, y,) = R._first_ngens(2)" + "R = ZZ['x, y']; (x, y,) = R._first_ngens(2)" Names given not the same as generator names:: @@ -1604,7 +1607,7 @@ def preparse_generators(code): sage: preparse("R. = a+b") 'R = a+b; (x, y,) = R._first_ngens(2)' sage: preparse("A.=FreeAlgebra(ZZ,3)") - "A=FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)" + "A = FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)" Ensure we do not eat too much:: @@ -1619,10 +1622,6 @@ def preparse_generators(code): with a semicolon:: sage: preparse_generators("; R.=ZZ[];") - doctest:warning - ... - DeprecationWarning: The method preparse_generators is deprecated; use sage.repl.intepreter.SageGenConstructionTransformer instead. - See https://trac.sagemath.org/31951 for details. "; R = ZZ['x']; (x,) = R._first_ngens(1);" See :trac:`16731`:: @@ -1633,14 +1632,26 @@ def preparse_generators(code): Check support for unicode characters (:trac:`29278`):: sage: preparse('Ω.<λ,μ> = QQ[]') - "Ω = QQ['λ', 'μ']; (λ, μ,) = Ω._first_ngens(2)" + "Ω = QQ['λ, μ']; (λ, μ,) = Ω._first_ngens(2)" + + Check that :trac:`30953` is fixed:: + + sage: preparse(''' + ....: K. = QuadraticField(2 + + ....: 1)''') + "\nK = QuadraticField(Integer(2) +\n Integer(1), names=('a',)); (a,) = K._first_ngens(1)" + sage: preparse(''' + ....: K. = QuadraticField(2 + (1 + 1) + # some comment + ....: 1)''') + "\nK = QuadraticField(Integer(2) + (Integer(1) + Integer(1)) + # some comment\n Integer(1), names=('a',)); (a,) = K._first_ngens(1)" + sage: preparse(''' + ....: K. = QuadraticField(2) # some comment''') + "\nK = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1)# some comment" """ - deprecation(31951, "The method preparse_generators is deprecated; use " - "sage.repl.intepreter.SageGenConstructionTransformer instead.") new_code = [] last_end = 0 # obj .< gens > , other = constructor - for m in re.finditer(r";(\s*)([^\W\d]\w*)\.<([^>]+)> *((?:,[\w, ]+)?)= *([^;#]+)", code): + for m in re.finditer(r";(\s*)([^\W\d]\w*)\.<([^>]+)> *((?:,[\w, ]+)?)= *([^;]+)", code): ident, obj, gens, other_objs, constructor = m.groups() gens = [v.strip() for v in gens.split(',')] constructor = constructor.rstrip() @@ -1709,7 +1720,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, sage: preparse("ZZ. = ZZ['y']") "ZZ = ZZ['y']; (x,) = ZZ._first_ngens(1)" sage: preparse("ZZ. = ZZ[]") - "ZZ = ZZ['x', 'y']; (x, y,) = ZZ._first_ngens(2)" + "ZZ = ZZ['x, y']; (x, y,) = ZZ._first_ngens(2)" sage: preparse("ZZ. = ZZ['u,v']") "ZZ = ZZ['u,v']; (x, y,) = ZZ._first_ngens(2)" sage: preparse("ZZ. = QQ[2^(1/3)]") @@ -1748,7 +1759,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, Check support for backslash line continuation (:trac:`30928`):: sage: preparse("f(x) = x \\\n+ 1") - '__tmp__ = var("x"); __tmpf__ = x + Integer(1); f = symbolic_expression(__tmpf__).function(x)' + '__tmp__=var("x"); f = symbolic_expression(x + Integer(1)).function(x)' Check that multi-line strings starting with a comment are still preparsed (:trac:`31043`):: @@ -1756,7 +1767,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, sage: print(preparse('''# some comment ....: f(x) = x + 1''')) # some comment - __tmp__ = var("x"); __tmpf__ = x + Integer(1); f = symbolic_expression(__tmpf__).function(x) + __tmp__=var("x"); f = symbolic_expression(x + Integer(1)).function(x) TESTS:: @@ -1814,38 +1825,51 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, # Combine lines that use backslash continuation L = L.replace('\\\n', '') - # Backslash - L = ';%s;' % L.replace('\n', ';\n;') - L = re.sub(r'''\\\s*([^\t ;#])''', r' * BackslashOperator() * \1', L) - L = L.replace(';\n;', '\n')[1:-1] + # Make it easy to match statement ends + ends = [] + counta = 0 + countb = 0 + countb = 0 + for i in range(len(L)): + if L[i] in ('[', ']'): + counta += 1 if L[i] == '[' else -1 + elif L[i] in ('(', ')'): + countb += 1 if L[i] == '(' else -1 + elif L[i] in ('\n', '#'): + if counta == countb == 0: + ends.append(i) + while ends: + i = ends.pop() + L = L[:i] + ';%s;' % L[i] + L[i+1:] + L = ';' + L + ';' - from IPython.core.inputtransformer2 import TransformerManager - from sage.repl.interpreter import SageTokenTransformers + if do_time: + # Separate time statement + L = re.sub(r';(\s*)time +(\w)', r';time;\1\2', L) - T = TransformerManager() - T.token_transformers = SageTokenTransformers + # Construction with generators + # R.<...> = obj() + # R.<...> = R[] + L = preparse_generators(L) - if not L.endswith('\n'): - cell = L + '\n' # Ensure the cell has a trailing newline - else: - cell = L + # Calculus functions + # f(x,y) = x^3 - sin(y) + L = preparse_calculus(L) - lines = cell.splitlines(keepends=True) - lines = T.do_token_transforms(lines) - output = ''.join(lines) - - if L[-1:] != "\n" and output[-1:] == "\n": - # Strip trailing newline, if input did not have it. - L = output[:-1] - else: - L = output + # Backslash + L = re.sub(r'''\\\s*([^\t ;#])''', r' * BackslashOperator() * \1', L) if do_time: - L = re.sub(r'^(\s*)time (\S[^;\n]*)', - r'__time__ = cputime(); __wall__ = walltime(); \2; print(' + + # Time keyword + L = re.sub(r';time;(\s*)(\S[^;\n]*)', + r';\1__time__ = cputime(); __wall__ = walltime(); \2; print(' + r'"Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__)))', L, flags=re.MULTILINE) + # Remove extra ;'s + L = L.replace(';#;', '#') + L = L.replace(';\n;', '\n')[1:-1] + line = L % literals return line From 94d4bc40960fcf679156e591a5d2cc8a917866cd Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 30 Sep 2021 11:51:47 +0200 Subject: [PATCH 305/355] remove wrong : --- src/sage/rings/lazy_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 23b0027456e..ae235a41c1f 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1871,7 +1871,7 @@ def hypergeometric(self, a, b): Return the `{}_{p}F_{q}`-hypergeometric function `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. - INPUT:: + INPUT: - ``a`` -- the first parameter of the hypergeometric function - ``b`` -- the second parameter of the hypergeometric function From 041aeaadca1846bf8cda58da7f2e3c35267ab23c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 30 Sep 2021 21:20:33 +0900 Subject: [PATCH 306/355] A fix --- src/sage/repl/preparse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 6d6b858a7e2..ce85446ae3f 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1829,7 +1829,6 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, ends = [] counta = 0 countb = 0 - countb = 0 for i in range(len(L)): if L[i] in ('[', ']'): counta += 1 if L[i] == '[' else -1 From 9570d010e586a079d25e18ef98ed611ceebcc13a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 30 Sep 2021 17:05:00 +0200 Subject: [PATCH 307/355] trac #32559: doctest input parameters --- src/sage/graphs/generators/families.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index fcf07d8829c..91003aae159 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2117,12 +2117,27 @@ def HyperStarGraph(n, k): sage: g.plot() # long time Graphics object consisting of 51 graphics primitives + TESTS:: + + sage: graphs.HyperStarGraph(-1, 1) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 + sage: graphs.HyperStarGraph(1, -1) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 + sage: graphs.HyperStarGraph(1, 2) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 + AUTHORS: - Michael Yurko (2009-09-01) """ if n < 0 or k < 0 or k > n: - raise ValueError("parameters n and k must be non-negative integers" + raise ValueError("parameters n and k must be non-negative integers " "satisfying n >= k >= 0") if not n: adj = {} From 29278b4198d5bcb7fc312cdb33433925a130ce00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 30 Sep 2021 17:43:58 +0200 Subject: [PATCH 308/355] 31378: removing trailing whitespaces in morphic.py file --- src/sage/combinat/words/morphic.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index b87f3a5868d..3311872c50c 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -45,7 +45,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): - ``parent`` - a parent - ``morphism`` - a word morphism - ``letter`` - a starting letter - - ``coding`` - dict (default: ``None``), if ``None`` + - ``coding`` - dict (default: ``None``), if ``None`` the identity map is used for the coding - ``length`` - integer or ``'finite'`` or ``Infinity`` or ``'unknown'`` (default: ``Infinity``) the length of the word @@ -60,7 +60,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): word: abaababaabaababaababaabaababaabaababaaba... sage: w.length() +Infinity - + :: sage: m = WordMorphism('a->abc,b->baba,c->ca') @@ -120,7 +120,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): self._len = None else: self._len = length - + self._morphism = morphism self._letter = letter self._alphabet = self._morphism.domain().alphabet() @@ -128,7 +128,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): self._coding = {a:a for a in self._alphabet} else: self._coding = coding - + def __reduce__(self): r""" EXAMPLES:: @@ -143,7 +143,7 @@ def __reduce__(self): {'a': 'a', 'b': 'b'}, +Infinity)) - Below is the behavior for words of finite length:: + Below is the behavior for words of finite length:: sage: m = WordMorphism("a->ab,b->") sage: w = m.fixed_point("a") @@ -171,9 +171,9 @@ def representation(self, n): OUTPUT: list - + EXAMPLES:: - + sage: m = WordMorphism('a->ab,b->a') sage: w = m.fixed_point('a') sage: w.representation(5) @@ -196,13 +196,13 @@ def representation(self, n): Accessing this method from an instance of the current class (no using the inherited word classes):: - + sage: m = WordMorphism('a->ab,b->a') sage: W = m.domain() sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: w = WordDatatype_morphic(W, m, 'a') sage: type(w) - + sage: w.representation(5) [1, 0, 0, 0] """ @@ -217,7 +217,7 @@ def representation(self, n): if vMk[position] == vMk_next[position]: raise IndexError('Index (={}) out of range, the fixed point is finite and has length {}.'.format(n,vMk[position])) vMk = vMk_next - k = len(length_of_images) + k = len(length_of_images) letter_k = self._letter n_k = n path = [] @@ -251,7 +251,7 @@ def _func(self, key): - a letter EXAMPLES:: - + sage: m = WordMorphism("a->ab,b->a") sage: w = m.fixed_point("a") sage: w[0] @@ -265,19 +265,19 @@ def _func(self, key): Accessing this method from an instance of the current class (without using the inherited word classes):: - + sage: m = WordMorphism('a->ab,b->a') sage: W = m.domain() sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: w = WordDatatype_morphic(W, m, 'a') sage: w._func(5) 'a' - + """ letter = self._letter for a in self.representation(key): letter = (self._morphism(letter))[a] - if key == 0: + if key == 0: return self._coding[letter] return self._coding[letter] From 5f8fe4e3be144d16f75c0ea680fcccc1a648e656 Mon Sep 17 00:00:00 2001 From: sheerluck Date: Thu, 30 Sep 2021 20:21:28 +0200 Subject: [PATCH 309/355] make sure that random multi-filtration is exhaustive --- src/sage/schemes/toric/sheaf/klyachko.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 9119f240532..097f6193fb0 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -24,9 +24,9 @@ sage: V_sum = G_sum.wedge(2) * K # long time sage: V_sum.cohomology(dim=True, weight=(0,0,0,0)) # long time (0, 0, 18, 16, 1) - sage: Gtilde = G_sum.random_deformation() # not tested, known bug (see :trac:`29956`) - sage: V = Gtilde.wedge(2) * K # long time # not tested, known bug (see :trac:`29956`) - sage: V.cohomology(dim=True, weight=(0,0,0,0)) # long time # not tested, known bug (see :trac:`29956`) + sage: Gtilde = G_sum.random_deformation() + sage: V = Gtilde.wedge(2) * K # long time + sage: V.cohomology(dim=True, weight=(0,0,0,0)) # long time (0, 0, 3, 0, 0) REFERENCES: @@ -947,9 +947,11 @@ def random_deformation(self, epsilon=None): sage: V = P1.sheaves.line_bundle(H) + P1.sheaves.line_bundle(-H) sage: V.cohomology(dim=True, weight=(0,)) (1, 0) - sage: Vtilde = V.random_deformation() # not tested, known bug (see :trac:`29956`) - sage: Vtilde.cohomology(dim=True, weight=(0,)) # not tested, known bug (see :trac:`29956`) + sage: Vtilde = V.random_deformation() + sage: Vtilde.cohomology(dim=True, weight=(0,)) (1, 0) """ filt = self._filt.random_deformation(epsilon) + while not filt.is_exhaustive(): + filt = self._filt.random_deformation(epsilon) return self.__class__(self.variety(), filt, check=True) From c40df1aadaf0521c52d613474c1b86b80d330d25 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 30 Sep 2021 20:33:30 +0200 Subject: [PATCH 310/355] fix doctest --- .../en/thematic_tutorials/geometry/tips.rst | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/doc/en/thematic_tutorials/geometry/tips.rst b/src/doc/en/thematic_tutorials/geometry/tips.rst index f1fad488ddd..458e0741906 100644 --- a/src/doc/en/thematic_tutorials/geometry/tips.rst +++ b/src/doc/en/thematic_tutorials/geometry/tips.rst @@ -81,20 +81,20 @@ the latex presentation, there is a method for that! sage: print(TCube.Hrepresentation_str(latex=True)) \begin{array}{rcl} - -6 \, x_{0} - 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} - 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} + 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} + 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - -2 \, x_{0} & \geq & -1 \\ - -2 \, x_{1} & \geq & -1 \\ - -2 \, x_{2} & \geq & -1 \\ - 6 \, x_{0} + 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - 2 \, x_{2} & \geq & -1 \\ - 2 \, x_{1} & \geq & -1 \\ - 2 \, x_{0} & \geq & -1 \\ - 6 \, x_{0} - 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - 6 \, x_{0} - 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - 6 \, x_{0} + 6 \, x_{1} - 6 \, x_{2} & \geq & -7 + -6x_{0} - 6x_{1} - 6x_{2} & \geq & -7 \\ + -6x_{0} - 6x_{1} + 6x_{2} & \geq & -7 \\ + -6x_{0} + 6x_{1} - 6x_{2} & \geq & -7 \\ + -6x_{0} + 6x_{1} + 6x_{2} & \geq & -7 \\ + -2x_{0} & \geq & -1 \\ + -2x_{1} & \geq & -1 \\ + -2x_{2} & \geq & -1 \\ + 6x_{0} + 6x_{1} + 6x_{2} & \geq & -7 \\ + 2x_{2} & \geq & -1 \\ + 2x_{1} & \geq & -1 \\ + 2x_{0} & \geq & -1 \\ + 6x_{0} - 6x_{1} - 6x_{2} & \geq & -7 \\ + 6x_{0} - 6x_{1} + 6x_{2} & \geq & -7 \\ + 6x_{0} + 6x_{1} - 6x_{2} & \geq & -7 \end{array} sage: Latex_repr = LatexExpr(TCube.Hrepresentation_str(latex=True)) From 38c0d54e761b242b381ea9d4899be9ed40ac4236 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:09:32 -0700 Subject: [PATCH 311/355] build/pkgs/openssl/spkg-configure.m4: Fix OPENSSL_VERSION_NUMBER format --- build/pkgs/openssl/spkg-configure.m4 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build/pkgs/openssl/spkg-configure.m4 b/build/pkgs/openssl/spkg-configure.m4 index bc6e69e666e..650c046667b 100644 --- a/build/pkgs/openssl/spkg-configure.m4 +++ b/build/pkgs/openssl/spkg-configure.m4 @@ -3,13 +3,18 @@ SAGE_SPKG_CONFIGURE([openssl], [ AC_MSG_CHECKING([whether OpenSSL >= 1.1.1, as required by PEP 644]) AC_COMPILE_IFELSE( dnl Trac #32580: Need OpenSSL >= 1.1.1 for PEP 644 + dnl From https://www.openssl.org/docs/man3.0/man3/OPENSSL_VERSION_NUMBER.html: dnl If M is the number from OPENSSL_VERSION_MAJOR dnl NN is the number from OPENSSL_VERSION_MINOR dnl PP is the number from OPENSSL_VERSION_PATCH dnl -> OPENSSL_VERSION_NUMBER is 0xMNN00PP0L + dnl From https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_VERSION_NUMBER.html + dnl FF is "fix" + dnl S is "status" (f = release) + dnl -> OPENSSL_VERSION_NUMBER is 0xMNNFFPPSL [AC_LANG_PROGRAM([[ #include - #if OPENSSL_VERSION_NUMBER < 0x10100010L + #if OPENSSL_VERSION_NUMBER < 0x10101000L # error OpenSSL >= 1.1.1 is required according to PEP 644 #endif ]], [])], [ From 6e214ae79a4788ff2911699fd35b579a86165b95 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 30 Sep 2021 08:39:23 -0400 Subject: [PATCH 312/355] Trac #31553: work around space symbols in maxima_lib's "retrieve" function. Our custom "undoing_true_false_printing_patch" maxima patch is a roadblock for using the system copy of maxima. The goal of the patch is to eliminate some line breaks that appear unexpectedly when maxima asks the user a question; so without the patch, we get, for example, Is x an even\ number? This turns out to be caused by certain space characters being represented by symbols rather than strings. This commit updates our copy of maxima's "retrieve" function (which preprocesses said questions) to (a) mirror the latest upstream implementation, and (b) convert those symbols to strings. Afterwards, it removes the custom patch that is no longer necessary. Thanks to Nils Bruin for figuring out what the real problem was here. --- .../undoing_true_false_printing_patch.patch | 19 ------- src/sage/interfaces/maxima_lib.py | 51 +++++++++---------- 2 files changed, 24 insertions(+), 46 deletions(-) delete mode 100644 build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch diff --git a/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch b/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch deleted file mode 100644 index 535134b01b6..00000000000 --- a/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/src/grind.lisp b/src/grind.lisp -index 4ae73a3..86b80e6 100644 ---- a/src/grind.lisp -+++ b/src/grind.lisp -@@ -295,12 +295,12 @@ - (msz nil l r) - (do ((nl) (w 0)) - ((null (cdr x)) -- (setq nl (cons (if (stringp (car x)) -+ (setq nl (cons (if (atom (car x)) - (msz (makestring (car x)) l r) - (msize (car x) l r lop rop)) - nl)) - (cons (+ w (caar nl)) (nreverse nl))) -- (setq nl (cons (if (stringp (car x)) -+ (setq nl (cons (if (atom (car x)) - (msz (makestring (car x)) l r) - (msize (car x) l r lop rop)) - nl) diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index d52685990aa..6b911df28d3 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -113,42 +113,39 @@ ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539) ecl_eval("(setf $errormsg nil)") -# the following is a direct adaptation of the definition of "retrieve" -# in the Maxima file macsys.lisp. This routine is normally responsible -# for displaying a question and returning the answer. We change it to -# throw an error in which the text of the question is included. We do -# this by running exactly the same code as in the original definition -# of "retrieve", but with *standard-output* redirected to a string. +# The following is an adaptation of the "retrieve" function in maxima +# itself. This routine is normally responsible for displaying a +# question and returning the answer. Our version throws an error in +# which the text of the question is included. This is accomplished by +# redirecting *standard-output* to a string. +# +# After an update in Trac 31553, this routine also preprocesses the +# text to replace space symbols with strings. This prevents those +# symbols from being turned into ugly newlines -- a problem that we +# used to avoid with a custom patch. ecl_eval(r""" (defun retrieve (msg flag &aux (print? nil)) (declare (special msg flag print?)) + (setq msg (mapcar #'(lambda (x) (if (eq x '| |) " " x)) msg)) (or (eq flag 'noprint) (setq print? t)) (error (concatenate 'string "Maxima asks: " (string-trim '(#\Newline) (with-output-to-string (*standard-output*) (cond ((not print?) - (setq print? t) - (princ *prompt-prefix*) - (princ *prompt-suffix*) - ) - ((null msg) - (princ *prompt-prefix*) - (princ *prompt-suffix*) - ) - ((atom msg) - (format t "~a~a~a" *prompt-prefix* msg *prompt-suffix*) - ) - ((eq flag t) - (princ *prompt-prefix*) - (mapc #'princ (cdr msg)) - (princ *prompt-suffix*) - ) - (t - (princ *prompt-prefix*) - (displa msg) - (princ *prompt-suffix*) - ) + (setq print? t) + (format-prompt t "")) + ((null msg) + (format-prompt t "")) + ((atom msg) + (format-prompt t "~A" msg) + (mterpri)) + ((eq flag t) + (format-prompt t "~{~A~}" (cdr msg)) + (mterpri)) + (t + (format-prompt t "~M" msg) + (mterpri)) )))) ) ) From a3245b8c3f02b066178b8f12b4f052cbc8b689b3 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 1 Oct 2021 13:38:30 -0400 Subject: [PATCH 313/355] fix failing doctests --- src/sage/modular/quasimodform/element.py | 2 +- src/sage/modular/quasimodform/ring.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index a5d18385fca..38d0e0c6e86 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -368,7 +368,7 @@ def to_polynomial(self, names='E2, E4, E6'): P = self.parent().polynomial_ring(names) g0, g1 = self.parent().modular_forms_subring().polynomial_ring(names='x').gens() E2, E4, E6 = P.gens() - return sum(f.to_polynomial().subs({g0:E4, g1:E6}) * E2 ** exp for exp, f in enumerate(self._coefficients)) + return sum(f.to_polynomial().subs({g0:E4, g1:E6}) * E2 ** exp for exp, f in enumerate(self._polynomial.coefficients(sparse=False))) def weights_list(self): r""" diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 3cbf94a7ec8..8845d090765 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -75,7 +75,7 @@ from sage.modular.modform.space import ModularFormsSpace from sage.modular.modform.ring import ModularFormsRing -from sage.rings.all import Integer, QQ +from sage.rings.all import Integer, QQ, ZZ from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing From 94727df4dbfa1e03c09e89cb87c2433232318962 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 1 Oct 2021 11:35:21 -0700 Subject: [PATCH 314/355] trac 30778: patch sageinspect to not print warning when skipfile returns True. --- src/sage/misc/sageinspect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index b9691bbb628..44805bc0b5a 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2062,10 +2062,10 @@ def sage_getdoc(obj, obj_name='', embedded=False): r = sage_getdoc_original(obj) s = sage.misc.sagedoc.format(r, embedded=embedded) f = sage_getfile(obj) - if f: + if f and os.path.exists(f): from sage.doctest.control import skipfile skip = skipfile(f) - if skip: + if isinstance(skip, str): warn = """WARNING: the enclosing module is marked '{}', so doctests may not pass.""".format(skip) s = warn + "\n\n" + s From b8fb254c5e702be38dc2d2457357af1d7a0baaf0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 19:14:57 -0700 Subject: [PATCH 315/355] src/setup.cfg.m4, src/pyproject.toml.m4: Add memory_allocator --- src/pyproject.toml.m4 | 1 + src/setup.cfg.m4 | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pyproject.toml.m4 b/src/pyproject.toml.m4 index 1d610ab0149..125da7ac1cc 100644 --- a/src/pyproject.toml.m4 +++ b/src/pyproject.toml.m4 @@ -18,5 +18,6 @@ requires = [ numpy \ pkgconfig \ pplpy \ + memory_allocator \ ')] build-backend = "setuptools.build_meta" diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 60ff8b757a6..655f7628882 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -43,6 +43,7 @@ dnl From build/pkgs/sagelib/dependencies numpy \ pkgconfig \ pplpy \ + memory_allocator \ | sed "2,\$s/^/ /;"')dnl dnl From Makefile.in: SAGERUNTIME esyscmd(`sage-get-system-packages install-requires \ From 727885b7cbc67c7493898c939a82e28b0ba524bf Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 2 Oct 2021 10:31:29 +0100 Subject: [PATCH 316/355] a fix for #32486 avoid computing (symbolically!) L_2 norm, use L_1 norm in non-max rank case --- src/sage/modules/diamond_cutting.py | 4 ++-- src/sage/modules/free_module_integer.py | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index db33d13a77a..458d98ca539 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -258,7 +258,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): artificial_length = None if dim[0] < dim[1]: # introduce "artificial" basis points (representing infinity) - artificial_length = max(abs(v) for v in basis).ceil() * 2 + artificial_length = max(v.norm(1) for v in basis).ceil() * 2 additional_vectors = identity_matrix(dim[1]) * artificial_length basis = basis.stack(additional_vectors) # LLL-reduce to get quadratic matrix @@ -277,7 +277,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): # twice the length of longest vertex in Q is a safe choice if radius is None: - radius = 2 * max(abs(v) ** 2 for v in basis) + radius = 2 * max(v.norm(1) ** 2 for v in basis) V = diamond_cut(Q, basis, radius, verbose=verbose) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index a3b201657a6..a1e8a05fb50 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -756,6 +756,13 @@ def closest_vector(self, t): sage: u = vector([-423434678248195, -18882583298608161305227077482]) sage: L.closest_vector(u) in L True + + Check that the example, of non-maximal rank, from :trac:`32486` works:: + + from sage.modules.free_module_integer import IntegerLattice + L = IntegerLattice([[-1, 0, 1],[1,0,2]]) + L.closest_vector((1,1,1)) + (2, 0, 1) """ voronoi_cell = self.voronoi_cell() From 1f37015af5390ef9721375a2bee402053df1db25 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 18 Jul 2021 16:47:36 -0700 Subject: [PATCH 317/355] fast_float: No longer allow old=False --- src/sage/ext/fast_eval.pyx | 39 ++++++++------------------------------ 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index d4e736b83ec..6185da8b8d1 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -40,27 +40,6 @@ wraps a callable Python function. These may be combined with the standard Python arithmetic operators, and support many of the basic math functions such ``sqrt``, ``exp``, and trig functions. -EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float - sage: f = fast_float(sqrt(x^7+1), 'x', old=True) - sage: f(1) - 1.4142135623730951 - sage: f.op_list() - ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)'] - -To interpret that last line, we load argument 0 (``x`` in this case) onto -the stack, push the constant 2.0 onto the stack, call the pow function -(which takes 2 arguments from the stack), push the constant 1.0, add the -top two arguments of the stack, and then call sqrt. - -Here we take ``sin`` of the first argument and add it to ``f``:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: g = fast_float_arg(0).sin() - sage: (f+g).op_list() - ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)', 'load 0', 'call sin(1)', 'add'] - TESTS: This used to segfault because of an assumption that assigning None to a @@ -1332,8 +1311,6 @@ def fast_float_func(f, *args): return FastDoubleFunc('callable', f, *args) -new_fast_float=True - def fast_float(f, *vars, old=None, expect_one_var=False): """ Tries to create a function that evaluates f quickly using @@ -1347,7 +1324,7 @@ def fast_float(f, *vars, old=None, expect_one_var=False): - ``f`` -- an expression - ``vars`` -- the names of the arguments - - ``old`` -- use the original algorithm for fast_float + - ``old`` -- deprecated, do not use - ``expect_one_var`` -- don't give deprecation warning if ``vars`` is omitted, as long as expression has only one var @@ -1369,8 +1346,11 @@ def fast_float(f, *vars, old=None, expect_one_var=False): sage: f(1,2) 1.0 """ - if old is None: - old = not new_fast_float + if old: + raise ValueError("the old implementation of fast_float has been removed") + if old is not None: + from sage.misc.superseded import deprecation + deprecation(32234, "passing old=False to fast_float is deprecated") if isinstance(f, (tuple, list)): return tuple([fast_float(x, *vars, expect_one_var=expect_one_var) for x in f]) @@ -1385,11 +1365,8 @@ def fast_float(f, *vars, old=None, expect_one_var=False): vars = vars[:i] + (v,) + vars[i+1:] try: - if old: - return f._fast_float_(*vars) - else: - return fast_callable(f, vars=vars, domain=float, - expect_one_var=expect_one_var) + return fast_callable(f, vars=vars, domain=float, + expect_one_var=expect_one_var) except AttributeError: pass From 7f2549877b23ef34d81cf14e59a1f45d32c44e6b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 21 Jul 2021 15:21:51 -0400 Subject: [PATCH 318/355] Trac #32234: migrate _fast_float_() method calls to fast_callable. Symbolic expressions have two ways to convert themselves into a (faster) callable object. The old way is encapsulated in a _fast_float_() method based on sage.ext.fast_eval, and the newer way uses fast_callable() from sage.ext.fast_callable. This commit updates three files to use the new method. The conversion was mechanical, f._fast_float_(varlist) -> fast_callable(f, vars=varlist). --- src/sage/calculus/integration.pyx | 3 ++- src/sage/numerical/optimize.py | 15 ++++++++------- src/sage/symbolic/expression.pyx | 6 ++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 56456173632..156e6c5140a 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -315,7 +315,8 @@ def numerical_integral(func, a, b=None, else: if ell.is_numeric() and not ell.is_zero(): raise ValueError('integral does not converge at infinity') - func = func._fast_float_(v) + func = fast_callable(func, vars=[v]) + if isinstance(func, FastDoubleFunc): F.function = c_ff diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 7aa17dc48af..6686b269ed5 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -505,23 +505,24 @@ def minimize_constrained(func,cons,x0,gradient=None,algorithm='default', **args) (805.985..., 1005.985...) """ from sage.symbolic.expression import Expression + from sage.ext.fast_eval import fast_callable import numpy from scipy import optimize function_type = type(lambda x,y: x+y) if isinstance(func, Expression): var_list = func.variables() - var_names = [str(_) for _ in var_list] - fast_f = func._fast_float_(*var_names) + fast_f = fast_callable(func, vars=var_list) f = lambda p: fast_f(*p) gradient_list = func.gradient() - fast_gradient_functions = [gi._fast_float_(*var_names) for gi in gradient_list] + fast_gradient_functions = [ fast_callable(gi, vars=var_list) + for gi in gradient_list ] gradient = lambda p: numpy.array([ a(*p) for a in fast_gradient_functions]) if isinstance(cons, Expression): - fast_cons = cons._fast_float_(*var_names) + fast_cons = fast_callable(cons, vars=var_list) cons = lambda p: numpy.array([fast_cons(*p)]) elif isinstance(cons, list) and isinstance(cons[0], Expression): - fast_cons = [ci._fast_float_(*var_names) for ci in cons] + fast_cons = [fast_callable(ci, vars=var_list) for ci in cons] cons = lambda p: numpy.array([a(*p) for a in fast_cons]) else: f = func @@ -778,9 +779,9 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N raise ValueError("length of initial_guess does not coincide with the number of parameters") if isinstance(model, Expression): + from sage.ext.fast_eval import fast_callable var_list = variables + parameters - var_names = [str(_) for _ in var_list] - func = model._fast_float_(*var_names) + func = fast_callable(model, vars=var_list) else: func = model diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index de4720f90a7..a06c91c0f84 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12561,11 +12561,13 @@ cdef class Expression(CommutativeRingElement): - William Stein (2007-12-07) """ from sage.numerical.optimize import find_local_minimum + from sage.ext.fast_callable import fast_callable if var is None: var = self.default_variable() - return find_local_minimum(self._fast_float_(var), - a=a, b=b, tol=tol, maxfun=maxfun ) + + f = fast_callable(self, vars=[var]) + return find_local_minimum(f, a=a, b=b, tol=tol, maxfun=maxfun) ################### # Fast Evaluation # From 7da45d29ab7c1699814cec2632afe5d6c32eabf0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 14:47:13 -0700 Subject: [PATCH 319/355] src/sage/symbolic/function.pyx: Remove _fast_float_ method and handling of FastDoubleFunc --- src/sage/symbolic/function.pyx | 52 ---------------------------------- 1 file changed, 52 deletions(-) diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 7feef512673..d2c7d8e468f 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -153,7 +153,6 @@ from sage.structure.coerce cimport (coercion_model, from sage.structure.richcmp cimport richcmp from sage.misc.fpickle import pickle_function, unpickle_function -from sage.ext.fast_eval import FastDoubleFunc # List of functions which ginac allows us to define custom behavior for. # Changing the order of this list could cause problems unpickling old pickles. @@ -516,16 +515,6 @@ cdef class Function(SageObject): if self._nargs > 0 and len(args) != self._nargs: raise TypeError("Symbolic function %s takes exactly %s arguments (%s given)" % (self._name, self._nargs, len(args))) - # support fast_float - if self._nargs == 1: - if isinstance(args[0], FastDoubleFunc): - try: - method = getattr(args[0], self._name) - except AttributeError: - raise TypeError("cannot handle fast float arguments") - else: - return method() - # if the given input is a symbolic expression, we don't convert it back # to a numeric type at the end from .ring import SR @@ -729,47 +718,6 @@ cdef class Function(SageObject): """ return self._conversions.get('maxima', self._name) - def _fast_float_(self, *vars): - """ - Returns an object which provides fast floating point evaluation of - self. - - See sage.ext.fast_eval? for more information. - - EXAMPLES:: - - sage: sin._fast_float_() - - sage: sin._fast_float_()(0) - 0.0 - - :: - - sage: ff = cos._fast_float_(); ff - - sage: ff.is_pure_c() - True - sage: ff(0) - 1.0 - - :: - - sage: ff = erf._fast_float_() - sage: ff.is_pure_c() - False - sage: ff(1.5) # tol 1e-15 - 0.9661051464753108 - sage: erf(1.5) - 0.966105146475311 - """ - import sage.ext.fast_eval as fast_float - - args = [fast_float.fast_float_arg(n) for n in range(self.number_of_arguments())] - try: - return self(*args) - except TypeError as err: - return fast_float.fast_float_func(self, *args) - def _fast_callable_(self, etb): r""" Given an ExpressionTreeBuilder, return an Expression representing From 027b4fc3cf0684b3762bdfffb669212ff5e0e7cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 14:49:16 -0700 Subject: [PATCH 320/355] src/sage/symbolic/expression_conversions.py: Remove _fast_float_, FastFloatConverter --- src/sage/symbolic/expression_conversions.py | 218 -------------------- 1 file changed, 218 deletions(-) diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index f7e26daa6fc..98d2820a361 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -123,17 +123,6 @@ def _fast_callable_(self, etb): """ return fast_callable(self, etb) - def _fast_float_(self, *vars): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import FakeExpression - sage: import operator; x,y = var('x,y') - sage: f = FakeExpression([x, y], operator.truediv) - sage: fast_float(f, 'x', 'y').op_list() - [('load_arg', 0), ('load_arg', 1), 'div', 'return'] - """ - return fast_float(self, *vars) class Converter(object): def __init__(self, use_fake_div=False): @@ -1695,213 +1684,6 @@ def laurent_polynomial(ex, base_ring=None, ring=None): return converter.ring(res) -############## -# Fast Float # -############## - -class FastFloatConverter(Converter): - def __init__(self, ex, *vars): - """ - Returns an object which provides fast floating point - evaluation of the symbolic expression *ex*. This is an class - used internally and is not meant to be used directly. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: x,y,z = var('x,y,z') - sage: f = 1 + sin(x)/x + sqrt(z^2+y^2)/cosh(x) - sage: ff = f._fast_float_('x', 'y', 'z') - sage: f(x=1.0,y=2.0,z=3.0).n() - 4.1780638977... - sage: ff(1.0,2.0,3.0) - 4.1780638977... - - Using ``_fast_float_`` without specifying the variable names is - no longer possible:: - - sage: f = x._fast_float_() - Traceback (most recent call last): - ... - ValueError: please specify the variable names - - Using ``_fast_float_`` on a function which is the identity is - now supported (see :trac:`10246`):: - - sage: f = symbolic_expression(x).function(x) - sage: f._fast_float_(x) - - sage: f(22) - 22 - """ - self.ex = ex - - if not vars: - try: - vars = ex.arguments() - except AttributeError: - vars = ex.variables() - - if vars: - raise ValueError('please specify the variable names') - - self.vars = vars - - import sage.ext.fast_eval as fast_float - self.ff = fast_float - - Converter.__init__(self, use_fake_div=True) - - def relation(self, ex, operator): - """ - EXAMPLES:: - - sage: ff = fast_float(x == 2, 'x') - sage: ff(2) - 0.0 - sage: ff(4) - 2.0 - sage: ff = fast_float(x < 2, 'x') - Traceback (most recent call last): - ... - NotImplementedError - """ - if operator is not _operator.eq: - raise NotImplementedError - return self(ex.lhs() - ex.rhs()) - - def pyobject(self, ex, obj): - """ - EXAMPLES:: - - sage: f = SR(2)._fast_float_() - sage: f(3) - 2.0 - """ - try: - return obj._fast_float_(*self.vars) - except AttributeError: - return self.ff.fast_float_constant(float(obj)) - - def symbol(self, ex): - r""" - EXAMPLES:: - - sage: f = x._fast_float_('x', 'y') - sage: f(1,2) - 1.0 - sage: f = x._fast_float_('y', 'x') - sage: f(1,2) - 2.0 - """ - if self.vars == (): - return self.ff.fast_float_arg(0) - - vars = list(self.vars) - name = repr(ex) - if name in vars: - return self.ff.fast_float_arg(vars.index(name)) - svars = [repr(x) for x in vars] - if name in svars: - return self.ff.fast_float_arg(svars.index(name)) - - if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x - name = repr(SR(ex)) # this gets back just the 'output' of the function - if name in svars: - return self.ff.fast_float_arg(svars.index(name)) - - try: - return self.ff.fast_float_constant(float(ex)) - except TypeError: - raise NotImplementedError("free variable: %s" % repr(ex)) - - def arithmetic(self, ex, operator): - """ - EXAMPLES:: - - sage: x,y = var('x,y') - sage: f = x*x-y - sage: ff = f._fast_float_('x','y') - sage: ff(2,3) - 1.0 - - sage: a = x + 2*y - sage: f = a._fast_float_('x', 'y') - sage: f(1,0) - 1.0 - sage: f(0,1) - 2.0 - - sage: f = sqrt(x)._fast_float_('x'); f.op_list() - ['load 0', 'call sqrt(1)'] - - sage: f = (1/2*x)._fast_float_('x'); f.op_list() - ['load 0', 'push 0.5', 'mul'] - """ - operands = ex.operands() - if operator is _operator.neg: - return operator(self(operands[0])) - - from sage.rings.all import Rational - if operator is _operator.pow and operands[1] == Rational(((1,2))): - from sage.functions.all import sqrt - return sqrt(self(operands[0])) - fops = map(self, operands) - if operator == add_vararg: - operator = _operator.add - elif operator == mul_vararg: - operator = _operator.mul - return reduce(operator, fops) - - def composition(self, ex, operator): - """ - EXAMPLES:: - - sage: f = sqrt(x)._fast_float_('x') - sage: f(2) - 1.41421356237309... - sage: y = var('y') - sage: f = sqrt(x+y)._fast_float_('x', 'y') - sage: f(1,1) - 1.41421356237309... - - :: - - sage: f = sqrt(x+2*y)._fast_float_('x', 'y') - sage: f(2,0) - 1.41421356237309... - sage: f(0,1) - 1.41421356237309... - """ - f = operator - g = [self(_) for _ in ex.operands()] - try: - return f(*g) - except TypeError: - from sage.functions.other import abs_symbolic - if f is abs_symbolic: - return abs(*g) # special case - else: - return self.ff.fast_float_func(f, *g) - -def fast_float(ex, *vars): - """ - Returns an object which provides fast floating point evaluation of - the symbolic expression *ex*. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import fast_float - sage: f = sqrt(x+1) - sage: ff = fast_float(f, 'x') - sage: ff(1.0) - 1.4142135623730951 - """ - return FastFloatConverter(ex, *vars)() - ################# # Fast Callable # ################# From f47d0bef1ce1d4747848d45df539bb1ee2b47dab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 14:55:10 -0700 Subject: [PATCH 321/355] Remove more _fast_float_ methods --- src/sage/functions/hypergeometric.py | 18 ------ src/sage/functions/piecewise.py | 19 ------ .../rings/polynomial/multi_polynomial.pyx | 59 ------------------ .../rings/polynomial/polynomial_element.pyx | 60 ------------------- src/sage/symbolic/expression.pyx | 18 ------ 5 files changed, 174 deletions(-) diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 846f2c486db..0a9a2ae8030 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -389,24 +389,6 @@ def _tderivative_(self, a, b, z, *args, **kwargs): hypergeometric([c + 1 for c in a], [c + 1 for c in b], z)) class EvaluationMethods(object): - def _fast_float_(self, *args): - """ - Do not support the old ``fast_float``. - - OUTPUT: - - This method raises ``NotImplementedError``; use the newer - ``fast_callable`` implementation. - - EXAMPLES:: - - sage: f = hypergeometric([], [], x) - sage: f._fast_float_() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError def _fast_callable_(self, a, b, z, etb): """ diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 861dbf25cde..bc25aad5cd1 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -469,25 +469,6 @@ def __call__(self, parameters, variable, value=None, **kwds): substitution[variable] = value return self.subs(substitution) - def _fast_float_(self, *args): - """ - Do not support the old ``fast_float`` - - OUTPUT: - - This method raises ``NotImplementedError`` so that - plotting uses the newer `fast_callable` implementation. - - EXAMPLES:: - - sage: f = piecewise([([0,0], sin(x)), ((0,2), cos(x))]) - sage: f._fast_float_() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - def _fast_callable_(self, parameters, variable, etb): """ Override the ``fast_callable`` diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 8106cf5f7a5..7ecb1fb97ff 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -254,65 +254,6 @@ cdef class MPolynomial(CommutativeRingElement): d = self.dict() return R(dict([(k, c) for k, c in d.iteritems() if k[ind] < n])) - def _fast_float_(self, *vars): - """ - Returns a quickly-evaluating function on floats. - - EXAMPLES:: - - sage: K. = QQ[] - sage: f = (x+2*y+3*z^2)^2 + 42 - sage: f(1, 10, 100) - 901260483 - sage: ff = f._fast_float_() - sage: ff(0, 0, 1) - 51.0 - sage: ff(0, 1, 0) - 46.0 - sage: ff(1, 10, 100) - 901260483.0 - sage: ff_swapped = f._fast_float_('z', 'y', 'x') - sage: ff_swapped(100, 10, 1) - 901260483.0 - sage: ff_extra = f._fast_float_('x', 'A', 'y', 'B', 'z', 'C') - sage: ff_extra(1, 7, 10, 13, 100, 19) - 901260483.0 - - Currently, we use a fairly unoptimized method that evaluates one - monomial at a time, with no sharing of repeated computations and - with useless additions of 0 and multiplications by 1:: - - sage: g = (x*y**2*z)._fast_float_() - sage: list(g) - ['push 0.0', 'push 1.0', 'load 0', 'load 1', 'dup', 'mul', - 'mul', 'load 2', 'mul', 'mul', 'add'] - - TESTS:: - - sage: from sage.ext.fast_eval import fast_float - sage: list(fast_float(K(0), old=True)) - ['push 0.0'] - sage: list(fast_float(K(17), old=True)) - ['push 0.0', 'push 17.0', 'add'] - sage: list(fast_float(y, old=True)) - ['push 0.0', 'push 1.0', 'load 1', 'mul', 'add'] - """ - from sage.ext.fast_eval import fast_float_arg, fast_float_constant - my_vars = self.parent().variable_names() - vars = list(vars) - if len(vars) == 0: - indices = list(xrange(len(my_vars))) - else: - indices = [vars.index(v) for v in my_vars] - x = [fast_float_arg(i) for i in indices] - - n = len(x) - expr = fast_float_constant(0) - for m, c in self.dict().iteritems(): - monom = prod([ x[i]**m[i] for i in range(n) if m[i] != 0], fast_float_constant(c)) - expr = expr + monom - return expr - def _fast_callable_(self, etb): """ Given an ExpressionTreeBuilder, return an Expression representing diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index dabc030c828..f3b41d9515a 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -842,66 +842,6 @@ cdef class Polynomial(CommutativeAlgebraElement): # For testing return self._compiled - def _fast_float_(self, *vars): - """ - Return a quickly-evaluating function on floats. - - EXAMPLES:: - - sage: R. = QQ[] - sage: f = t^3-t - sage: ff = f._fast_float_() - sage: ff(10) - 990.0 - - Horner's method is used:: - - sage: f = (t+10)^3; f - t^3 + 30*t^2 + 300*t + 1000 - sage: list(f._fast_float_()) - ['load 0', 'push 30.0', 'add', 'load 0', 'mul', 'push 300.0', 'add', 'load 0', 'mul', 'push 1000.0', 'add'] - - TESTS:: - - sage: f = t + 2 - t - sage: ff = f._fast_float_() - sage: ff(3) - 2.0 - sage: list(f._fast_float_()) - ['push 2.0'] - - sage: f = t - t - sage: ff = f._fast_float_() - sage: ff(3) - 0.0 - sage: list(f._fast_float_()) - ['push 0.0'] - """ - from sage.ext.fast_eval import fast_float_arg, fast_float_constant - var = self._parent._names[0] - if not vars: - x = fast_float_arg(0) - elif var in vars: - x = fast_float_arg(list(vars).index(var)) - else: - raise ValueError("free variable: %s" % var) - cdef int i, d = self.degree() - expr = x - if d == -1: - return fast_float_constant(0) - coeff = self.get_unsafe(d) - if d == 0: - return fast_float_constant(coeff) - if coeff != 1: - expr *= fast_float_constant(coeff) - for i from d > i >= 0: - coeff = self.get_unsafe(i) - if coeff: - expr += fast_float_constant(coeff) - if i > 0: - expr *= x - return expr - def _fast_callable_(self, etb): r""" Given an ExpressionTreeBuilder, return an Expression representing diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index a06c91c0f84..b0374f26cd4 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12572,24 +12572,6 @@ cdef class Expression(CommutativeRingElement): ################### # Fast Evaluation # ################### - def _fast_float_(self, *vars): - """ - Return an object which provides fast floating point - evaluation of this symbolic expression. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: f = sqrt(x+1) - sage: ff = f._fast_float_('x') - sage: ff(1.0) - 1.4142135623730951 - sage: type(_) - <... 'float'> - """ - from sage.symbolic.expression_conversions import fast_float - return fast_float(self, *vars) def _fast_callable_(self, etb): """ From 4ab65a9a00d982c3bf02ccd3c926efcae5281a31 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 15:05:29 -0700 Subject: [PATCH 322/355] src/sage/ext/fast_eval.pyx: Remove everything except fast_float, is_fast_float --- src/sage/ext/fast_eval.pxd | 30 - src/sage/ext/fast_eval.pyx | 1249 +----------------------------------- 2 files changed, 1 insertion(+), 1278 deletions(-) diff --git a/src/sage/ext/fast_eval.pxd b/src/sage/ext/fast_eval.pxd index f88495fa158..e69de29bb2d 100644 --- a/src/sage/ext/fast_eval.pxd +++ b/src/sage/ext/fast_eval.pxd @@ -1,30 +0,0 @@ -from cpython.object cimport PyObject - -cdef union double_op_params: - PyObject* func - double (*f)(double) - double (*ff)(double, double) - double c - int n - -cdef struct fast_double_op: - char type - double_op_params params - -cdef class FastDoubleFunc: - cdef readonly int max_height - cdef readonly int nargs - cdef readonly int nops - cdef fast_double_op* ops - - cdef double* argv - cdef double* stack - - # need to keep this around because structs can't contain (ref-counted) python objects - cdef py_funcs - - cdef int allocate_stack(FastDoubleFunc self) except -1 - cdef double _call_c(FastDoubleFunc self, double* argv) except? -2 - cpdef bint is_pure_c(self) - cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func) - cdef FastDoubleFunc unop(FastDoubleFunc self, char type) diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index 6185da8b8d1..c00b52dd134 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -66,1249 +66,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from cysignals.memory cimport sig_malloc, sig_free - from sage.ext.fast_callable import fast_callable, Wrapper -from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool - -cimport cython -from cpython.ref cimport Py_INCREF -from cpython.object cimport PyObject_CallObject -from cpython.int cimport PyInt_AS_LONG -from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM - - -cdef extern from "math.h": - double sqrt(double) - double pow(double, double) - - double ceil(double) - double floor(double) - - double sin(double) - double cos(double) - double tan(double) - - double asin(double) - double acos(double) - double atan(double) - double atan2(double, double) - - double sinh(double) - double cosh(double) - double tanh(double) - - double asinh(double) - double acosh(double) - double atanh(double) - - double exp(double) - double log(double) - double log10(double) - double log2_ "log2"(double) - - -# This is only needed on Cygwin since log2 is a macro. -# If we don't do this the cygwin GCC gets very confused. -cdef inline double log2(double x): - return log2_(x) - -cdef extern from *: - void* memcpy(void* dst, void* src, size_t len) - -cdef inline int max(int a, int b): - return a if a > b else b - -cdef inline int min(int a, int b): - return a if a < b else b - -cdef enum: -# stack - LOAD_ARG # push input argument n onto the stack - PUSH_CONST - POP - POP_N - DUP - -# basic arithmetic - ADD - SUB - MUL - DIV - NEG - ABS - INVERT - POW - -# basic comparison - LT - LE - EQ - NE - GT - GE - -# functional - ONE_ARG_FUNC - TWO_ARG_FUNC - PY_FUNC - - -# These two dictionaries are for printable and machine independent representation. - -op_names = { - LOAD_ARG: 'load', - PUSH_CONST: 'push', - POP: 'pop', - POP_N: 'popn', - DUP: 'dup', - - ADD: 'add', - SUB: 'sub', - MUL: 'mul', - DIV: 'div', - NEG: 'neg', - ABS: 'abs', - INVERT: 'invert', - POW: 'pow', - - - LT: 'lt', - LE: 'le', - EQ: 'eq', - NE: 'ne', - GT: 'gt', - GE: 'ge', - - - ONE_ARG_FUNC: 'call', - TWO_ARG_FUNC: 'call', - PY_FUNC: 'py_call', -} - -cfunc_names = { - &sqrt: 'sqrt', - &pow: 'pow', - - &ceil: 'ceil', - &floor: 'floor', - - &sin: 'sin', - &cos: 'cos', - &tan: 'tan', - - &asin: 'asin', - &atan: 'atan', - &atan2: 'atan2', - - &sinh: 'sinh', - &cosh: 'cosh', - &tanh: 'tanh', - - &asinh: 'asinh', - &acosh: 'acosh', - &atanh: 'atanh', - - &exp: 'exp', - &log: 'log', - &log2: 'log2', - &log10: 'log10', - -} - -cdef reverse_map(m): - r = {} - for key, value in m.iteritems(): - r[value] = key - return r - -# With all the functionality around the op struct, perhaps there should be -# a wrapper class, though we still wish to operate on pure structs for speed. - -cdef op_to_string(fast_double_op op): - s = op_names[op.type] - if op.type in [LOAD_ARG, POP_N]: - s += " %s" % op.params.n - elif op.type == PUSH_CONST: - s += " %s" % op.params.c - elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - try: - cname = cfunc_names[op.params.func] - except KeyError: - cname = "0x%x" % op.params.func - s += " %s(%s)" % (cname, 1 if op.type == ONE_ARG_FUNC else 2) - elif op.type == PY_FUNC: - n, func = (op.params.func) - s += " %s(%s)" % (func, n) - return s - -cdef op_to_tuple(fast_double_op op): - s = op_names[op.type] - if op.type in [LOAD_ARG, POP_N]: - param = op.params.n - elif op.type == PUSH_CONST: - param = op.params.c - elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - param_count = 1 if op.type == ONE_ARG_FUNC else 2 - try: - param = param_count, cfunc_names[op.params.func] - except KeyError: - raise ValueError("Unknown C function: 0x%x" - % op.params.func) - elif op.type == PY_FUNC: - param = (op.params.func) - else: - param = None - if param is None: - return (s,) - else: - return s, param - -def _unpickle_FastDoubleFunc(nargs, max_height, op_list): - cdef FastDoubleFunc self = FastDoubleFunc.__new__(FastDoubleFunc) - self.nops = len(op_list) - self.nargs = nargs - self.max_height = max_height - self.ops = sig_malloc(sizeof(fast_double_op) * self.nops) - self.allocate_stack() - cfunc_addresses = reverse_map(cfunc_names) - op_enums = reverse_map(op_names) - cdef size_t address - cdef int i = 0, type - for op in op_list: - self.ops[i].type = type = op_enums[op[0]] - if type in [LOAD_ARG, POP_N]: - self.ops[i].params.n = op[1] - elif type == PUSH_CONST: - self.ops[i].params.c = op[1] - elif type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - param_count, cfunc = op[1] - address = cfunc_addresses[cfunc] - self.ops[i].params.func = address - self.ops[i].type = ['', ONE_ARG_FUNC, TWO_ARG_FUNC][param_count] - elif type == PY_FUNC: - if self.py_funcs is None: - self.py_funcs = op[1] - else: - self.py_funcs = self.py_funcs + (op[1],) - self.ops[i].params.func = op[1] - i += 1 - return self - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef inline int process_op(fast_double_op op, double* stack, double* argv, int top) except -2: - cdef int i, n - cdef object arg - cdef tuple py_args - - if op.type == LOAD_ARG: - stack[top+1] = argv[op.params.n] - return top+1 - - elif op.type == PUSH_CONST: - stack[top+1] = op.params.c - return top+1 - - elif op.type == POP: - return top-1 - - elif op.type == POP_N: - return top-op.params.n - - elif op.type == DUP: - stack[top+1] = stack[top] - return top+1 - - elif op.type == ADD: - stack[top-1] += stack[top] - return top-1 - - elif op.type == SUB: - stack[top-1] -= stack[top] - return top-1 - - elif op.type == MUL: - stack[top-1] *= stack[top] - return top-1 - - elif op.type == DIV: - stack[top-1] /= stack[top] - return top-1 - - elif op.type == NEG: - stack[top] = -stack[top] - return top - - elif op.type == ABS: - if stack[top] < 0: - stack[top] = -stack[top] - return top - - elif op.type == INVERT: - stack[top] = 1/stack[top] - return top - - elif op.type == POW: - if stack[top-1] < 0 and stack[top] != floor(stack[top]): - raise ValueError("negative number to a fractional power not real") - stack[top-1] = pow(stack[top-1], stack[top]) - return top-1 - - elif op.type == LT: - stack[top-1] = 1.0 if stack[top-1] < stack[top] else 0.0 - return top-1 - - elif op.type == LE: - stack[top-1] = 1.0 if stack[top-1] <= stack[top] else 0.0 - return top-1 - - elif op.type == EQ: - stack[top-1] = 1.0 if stack[top-1] == stack[top] else 0.0 - return top-1 - - elif op.type == NE: - stack[top-1] = 1.0 if stack[top-1] != stack[top] else 0.0 - return top-1 - - elif op.type == GT: - stack[top-1] = 1.0 if stack[top-1] > stack[top] else 0.0 - return top-1 - - elif op.type == GE: - stack[top-1] = 1.0 if stack[top-1] >= stack[top] else 0.0 - return top-1 - - elif op.type == ONE_ARG_FUNC: - stack[top] = (op.params.f)(stack[top]) - return top - - elif op.type == TWO_ARG_FUNC: - stack[top-1] = (op.params.ff)(stack[top-1], stack[top]) - return top-1 - - elif op.type == PY_FUNC: - # We use a few direct C/API calls here because Cython itself - # doesn't generate optimal code for this. - n = PyInt_AS_LONG((op.params.func)[0]) - top = top - n + 1 - py_args = PyTuple_New(n) - for i in range(n): - arg = stack[top+i] - Py_INCREF(arg) # PyTuple_SET_ITEM() steals a reference - PyTuple_SET_ITEM(py_args, i, arg) - stack[top] = PyObject_CallObject((op.params.func)[1], py_args) - return top - - raise RuntimeError("Bad op code %s" % op.type) - - -cdef class FastDoubleFunc: - """ - This class is for fast evaluation of algebraic expressions over - the real numbers (e.g. for plotting). It represents an expression - as a stack-based series of operations. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import FastDoubleFunc - sage: f = FastDoubleFunc('const', 1.5) # the constant function - sage: f() - 1.5 - sage: g = FastDoubleFunc('arg', 0) # the first argument - sage: g(5) - 5.0 - sage: h = f+g - sage: h(17) - 18.5 - sage: h = h.sin() - sage: h(pi/2-1.5) - 1.0 - sage: h.is_pure_c() - True - sage: list(h) - ['push 1.5', 'load 0', 'add', 'call sin(1)'] - - We can wrap Python functions too:: - - sage: h = FastDoubleFunc('callable', lambda x,y: x*x*x - y, g, f) - sage: h(10) - 998.5 - sage: h.is_pure_c() - False - sage: list(h) - ['load 0', 'push 1.5', 'py_call at 0x...>(2)'] - - Here's a more complicated expression:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: a = fast_float_constant(1.5) - sage: b = fast_float_constant(3.14) - sage: c = fast_float_constant(7) - sage: x = fast_float_arg(0) - sage: y = fast_float_arg(1) - sage: f = a*x^2 + b*x + c - y/sqrt(sin(y)^2+a) - sage: f(2,3) - 16.846610528508116 - sage: f.max_height - 4 - sage: f.is_pure_c() - True - sage: list(f) - ['push 1.5', 'load 0', 'dup', 'mul', 'mul', 'push 3.14', 'load 0', 'mul', 'add', 'push 7.0', 'add', 'load 1', 'load 1', 'call sin(1)', 'dup', 'mul', 'push 1.5', 'add', 'call sqrt(1)', 'div', 'sub'] - - AUTHORS: - - - Robert Bradshaw - """ - def __init__(self, type, param, *args): - - cdef FastDoubleFunc arg - cdef int i - - if type == 'arg': - self.nargs = param+1 - self.nops = 1 - self.max_height = 1 - self.ops = sig_malloc(sizeof(fast_double_op)) - self.ops[0].type = LOAD_ARG - self.ops[0].params.n = param - - elif type == 'const': - self.nargs = 0 - self.nops = 1 - self.max_height = 1 - self.ops = sig_malloc(sizeof(fast_double_op)) - self.ops[0].type = PUSH_CONST - self.ops[0].params.c = param - - elif type == 'callable': - py_func = len(args), param - self.py_funcs = (py_func,) # just so it doesn't get garbage collected - self.nops = 1 - self.nargs = 0 - for i from 0 <= i < len(args): - a = args[i] - if not isinstance(a, FastDoubleFunc): - a = FastDoubleFunc('const', a) - args = args[:i] + (a,) + args[i+1:] - arg = a - self.nops += arg.nops - if arg.py_funcs is not None: - self.py_funcs += arg.py_funcs - self.nargs = max(self.nargs, arg.nargs) - self.max_height = max(self.max_height, arg.max_height+i) - self.ops = sig_malloc(sizeof(fast_double_op) * self.nops) - if self.ops == NULL: - raise MemoryError - i = 0 - for arg in args: - memcpy(self.ops + i, arg.ops, sizeof(fast_double_op) * arg.nops) - i += arg.nops - self.ops[self.nops-1].type = PY_FUNC - self.ops[self.nops-1].params.func = py_func - - else: - raise ValueError("Unknown operation: %s" % type) - - self.allocate_stack() - - cdef int allocate_stack(FastDoubleFunc self) except -1: - self.argv = sig_malloc(sizeof(double) * self.nargs) - if self.argv == NULL: - raise MemoryError - self.stack = sig_malloc(sizeof(double) * self.max_height) - if self.stack == NULL: - raise MemoryError - - def __dealloc__(self): - sig_free(self.ops) - sig_free(self.stack) - sig_free(self.argv) - - def __reduce__(self): - """ - TESTS:: - - sage: from sage.ext.fast_eval import fast_float_arg, fast_float_func - sage: f = fast_float_arg(0).sin() * 10 + fast_float_func(hash, fast_float_arg(1)) - sage: loads(dumps(f)) == f - True - """ - L = [op_to_tuple(self.ops[i]) for i from 0 <= i < self.nops] - return _unpickle_FastDoubleFunc, (self.nargs, self.max_height, L) - - def __richcmp__(self, other, op): - """ - Two functions are considered equal if they represent the same - exact sequence of operations. - - TESTS:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: fast_float_arg(0) == fast_float_arg(0) - True - sage: fast_float_arg(0) == fast_float_arg(1) - False - sage: fast_float_arg(0) == fast_float_arg(0).sin() - False - """ - cdef int c, i - cdef FastDoubleFunc left, right - try: - left = self - right = other - - lx = left.nargs - rx = right.nargs - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - lx = left.nops - rx = right.nops - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - lx = left.max_height - rx = right.max_height - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - for i from 0 <= i < self.nops: - lx = left.ops[i].type - rx = right.ops[i].type - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - for i from 0 <= i < self.nops: - lx = op_to_tuple(left.ops[i]) - rx = op_to_tuple(right.ops[i]) - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - return rich_to_bool(op, 0) - except TypeError: - return NotImplemented - - def __call__(FastDoubleFunc self, *args): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(2) - sage: f(0,1,2,3) - 2.0 - sage: f(10) - Traceback (most recent call last): - ... - TypeError: Wrong number of arguments (need at least 3, got 1) - sage: f('blah', 1, 2, 3) # py2 - Traceback (most recent call last): - ... - TypeError: a float is required - sage: f('blah', 1, 2, 3) # py3 - Traceback (most recent call last): - ... - TypeError: must be real number, not str - """ - if len(args) < self.nargs: - raise TypeError("Wrong number of arguments (need at least %s, got %s)" % (self.nargs, len(args))) - cdef int i = 0 - for i from 0 <= i < self.nargs: - self.argv[i] = args[i] - res = self._call_c(self.argv) - return res - - cdef double _call_c(FastDoubleFunc self, double* argv) except? -2: - # The caller must assure that argv has length at least self.nargs - # The bulk of this function is in the (inlined) function process_op. - cdef int i, top = -1 - for i from 0 <= i < self.nops: - top = process_op(self.ops[i], self.stack, argv, top) - cdef double res = self.stack[0] - return res - - def _fast_float_(self, *vars): - r""" - Returns ``self`` if there are enough arguments, otherwise raises a ``TypeError``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(1) - sage: f._fast_float_('x','y') is f - True - sage: f._fast_float_('x') is f - Traceback (most recent call last): - ... - TypeError: Needs at least 2 arguments (1 provided) - """ - if self.nargs > len(vars): - raise TypeError("Needs at least %s arguments (%s provided)" % (self.nargs, len(vars))) - return self - - def op_list(self): - """ - Returns a list of string representations of the - operations that make up this expression. - - Python and C function calls may be only available by function - pointer addresses. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: a = fast_float_constant(17) - sage: x = fast_float_arg(0) - sage: a.op_list() - ['push 17.0'] - sage: x.op_list() - ['load 0'] - sage: (a*x).op_list() - ['push 17.0', 'load 0', 'mul'] - sage: (a+a*x^2).sqrt().op_list() - ['push 17.0', 'push 17.0', 'load 0', 'dup', 'mul', 'mul', 'add', 'call sqrt(1)'] - """ - cdef int i - return [op_to_string(self.ops[i]) for i from 0 <= i < self.nops] - - def __iter__(self): - """ - Returns the list of operations of ``self``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0)*2 + 3 - sage: list(f) - ['load 0', 'push 2.0', 'mul', 'push 3.0', 'add'] - """ - return iter(self.op_list()) - - cpdef bint is_pure_c(self): - """ - Returns ``True`` if this function can be evaluated without - any python calls (at any level). - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg, fast_float_func - sage: fast_float_constant(2).is_pure_c() - True - sage: fast_float_arg(2).sqrt().sin().is_pure_c() - True - sage: fast_float_func(lambda _: 2).is_pure_c() - False - """ - cdef int i - for i from 0 <= i < self.nops: - if self.ops[i].type == PY_FUNC: - return 0 - return 1 - - def python_calls(self): - """ - Returns a list of all python calls used by function. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg - sage: x = fast_float_arg(0) - sage: f = fast_float_func(hash, sqrt(x)) - sage: f.op_list() - ['load 0', 'call sqrt(1)', 'py_call (1)'] - sage: f.python_calls() - [] - """ - L = [] - cdef int i - for i from 0 <= i < self.nops: - if self.ops[i].type == PY_FUNC: - L.append((self.ops[i].params.func)[1]) - return L - - ################################################################### - # Basic Arithmetic - ################################################################### - - def __add__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) + fast_float_arg(1) - sage: f(3,4) - 7.0 - """ - return binop(left, right, ADD) - - def __sub__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) - fast_float_arg(2) - sage: f(3,4,5) - -2.0 - """ - return binop(left, right, SUB) - - def __mul__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) * 2 - sage: f(17) - 34.0 - """ - return binop(left, right, MUL) - - def __truediv__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).__truediv__(7) - sage: f(14) - 2.0 - """ - return binop(left, right, DIV) - - def __pow__(FastDoubleFunc left, right, dummy): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import FastDoubleFunc - sage: f = FastDoubleFunc('arg', 0)^2 - sage: f(2) - 4.0 - sage: f = FastDoubleFunc('arg', 0)^4 - sage: f(2) - 16.0 - sage: f = FastDoubleFunc('arg', 0)^-3 - sage: f(2) - 0.125 - sage: f = FastDoubleFunc('arg', 0)^FastDoubleFunc('arg', 1) - sage: f(5,3) - 125.0 - - TESTS:: - - sage: var('a,b') - (a, b) - sage: ff = (a^b)._fast_float_(a,b) - sage: ff(2, 9) - 512.0 - sage: ff(-2, 9) - -512.0 - sage: ff(-2, 9.1) - Traceback (most recent call last): - ... - ValueError: negative number to a fractional power not real - """ - if isinstance(right, FastDoubleFunc) and right.nargs == 0: - right = float(right) - if not isinstance(right, FastDoubleFunc): - if right == int(float(right)): - if right == 1: - return left - elif right == 2: - return left.unop(DUP).unop(MUL) - elif right == 3: - return left.unop(DUP).unop(DUP).unop(MUL).unop(MUL) - elif right == 4: - return left.unop(DUP).unop(MUL).unop(DUP).unop(MUL) - elif right < 0: - return (~left)**(-right) - right = FastDoubleFunc('const', right) - cdef FastDoubleFunc feval = binop(left, right, POW) - return feval - - def __neg__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = -fast_float_arg(0) - sage: f(3.5) - -3.5 - """ - return self.unop(NEG) - - def __abs__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = abs(fast_float_arg(0)) - sage: f(-3) - 3.0 - """ - return self.unop(ABS) - - def __float__(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: ff = fast_float_constant(17) - sage: float(ff) - 17.0 - sage: ff = fast_float_constant(17) - fast_float_constant(2)^2 - sage: float(ff) - 13.0 - sage: ff = fast_float_constant(17) - fast_float_constant(2)^2 + fast_float_arg(1) - sage: float(ff) - Traceback (most recent call last): - ... - TypeError: Not a constant. - """ - if self.nargs == 0: - return self._call_c(NULL) - else: - raise TypeError("Not a constant.") - - def abs(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).abs() - sage: f(3) - 3.0 - """ - return self.unop(ABS) - - def __invert__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = ~fast_float_arg(0) - sage: f(4) - 0.25 - """ - return self.unop(INVERT) - - def sqrt(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sqrt() - sage: f(4) - 2.0 - """ - return self.cfunc(&sqrt) - - ################################################################### - # Exponential and log - ################################################################### - - def log(self, base=None): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).log() - sage: f(2) - 0.693147180559945... - sage: f = fast_float_arg(0).log(2) - sage: f(2) - 1.0 - sage: f = fast_float_arg(0).log(3) - sage: f(9) - 2.0... - """ - if base is None: - return self.cfunc(&log) - elif base == 2: - return self.cfunc(&log2) - elif base == 10: - return self.cfunc(&log10) - else: - try: - base = fast_float_constant(log(float(base))) - except TypeError as e: - base = fast_float(base.log()) - return binop(self.cfunc(&log), base, DIV) - - def exp(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).exp() - sage: f(1) - 2.718281828459045... - sage: f(100) - 2.6881171418161356e+43 - """ - return self.cfunc(&exp) - - ################################################################### - # Rounding - ################################################################### - - def ceil(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).ceil() - sage: f(1.5) - 2.0 - sage: f(-1.5) - -1.0 - """ - return self.cfunc(&ceil) - - def floor(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).floor() - sage: f(11.5) - 11.0 - sage: f(-11.5) - -12.0 - """ - return self.cfunc(&floor) - - ################################################################### - # Trigonometric - ################################################################### - - def sin(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sin() - sage: f(pi/2) - 1.0 - """ - return self.cfunc(&sin) - - def cos(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cos() - sage: f(0) - 1.0 - """ - return self.cfunc(&cos) - - def tan(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).tan() - sage: f(pi/3) - 1.73205080756887... - """ - return self.cfunc(&tan) - - def csc(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).csc() - sage: f(pi/2) - 1.0 - """ - return ~self.sin() - - def sec(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sec() - sage: f(pi) - -1.0 - """ - return ~self.cos() - - def cot(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cot() - sage: f(pi/4) - 1.0... - """ - return ~self.tan() - - def arcsin(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arcsin() - sage: f(0.5) - 0.523598775598298... - """ - return self.cfunc(&asin) - - def arccos(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arccos() - sage: f(sqrt(3)/2) - 0.5235987755982989... - """ - return self.cfunc(&acos) - - def arctan(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arctan() - sage: f(1) - 0.785398163397448... - """ - return self.cfunc(&atan) - - ################################################################### - # Hyperbolic - ################################################################### - - def sinh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sinh() - sage: f(log(2)) - 0.75 - """ - return self.cfunc(&sinh) - - def cosh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cosh() - sage: f(log(2)) - 1.25 - """ - return self.cfunc(&cosh) - - def tanh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).tanh() - sage: f(0) - 0.0 - """ - return self.cfunc(&tanh) - - def arcsinh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arcsinh() - sage: f(sinh(5)) - 5.0 - """ - return self.cfunc(&asinh) - - def arccosh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arccosh() - sage: f(cosh(5)) - 5.0 - """ - return self.cfunc(&acosh) - - def arctanh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arctanh() - sage: abs(f(tanh(0.5)) - 0.5) < 0.0000001 - True - """ - return self.cfunc(&atanh) - - cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func): - cdef FastDoubleFunc feval = self.unop(ONE_ARG_FUNC) - feval.ops[feval.nops - 1].params.func = func - feval.allocate_stack() - return feval - - ################################################################### - # Utility functions - ################################################################### - - cdef FastDoubleFunc unop(FastDoubleFunc self, char type): - cdef FastDoubleFunc feval = FastDoubleFunc.__new__(FastDoubleFunc) - feval.nargs = self.nargs - feval.nops = self.nops + 1 - feval.max_height = self.max_height - if type == DUP: - feval.max_height += 1 - feval.ops = sig_malloc(sizeof(fast_double_op) * feval.nops) - memcpy(feval.ops, self.ops, sizeof(fast_double_op) * self.nops) - feval.ops[feval.nops - 1].type = type - feval.py_funcs = self.py_funcs - feval.allocate_stack() - return feval - -cdef FastDoubleFunc binop(_left, _right, char type): - r""" - Returns a function that calculates left and right on the stack, leaving - their results on the top, and then calls operation ``type``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(1) - sage: g = fast_float_arg(2) * 11 - sage: f.op_list() - ['load 1'] - sage: g.op_list() - ['load 2', 'push 11.0', 'mul'] - sage: (f+g).op_list() - ['load 1', 'load 2', 'push 11.0', 'mul', 'add'] - - Correctly calculates the maximum stack heights and number of arguments:: - - sage: f.max_height - 1 - sage: g.max_height - 2 - sage: (f+g).max_height - 3 - sage: (g+f).max_height - 2 - - sage: f.nargs - 2 - sage: g.nargs - 3 - sage: (f+g).nargs - 3 - """ - cdef FastDoubleFunc left, right - try: - left = _left - except TypeError: - left = fast_float(_left) - try: - right = _right - except TypeError: - right = fast_float(_right) - - # In Cython assigning None does NOT raise a TypeError above. - if left is None or right is None: - raise TypeError - - cdef FastDoubleFunc feval = FastDoubleFunc.__new__(FastDoubleFunc) - feval.nargs = max(left.nargs, right.nargs) - feval.nops = left.nops + right.nops + 1 - feval.max_height = max(left.max_height, right.max_height+1) - feval.ops = sig_malloc(sizeof(fast_double_op) * feval.nops) - memcpy(feval.ops, left.ops, sizeof(fast_double_op) * left.nops) - memcpy(feval.ops + left.nops, right.ops, sizeof(fast_double_op) * right.nops) - feval.ops[feval.nops - 1].type = type - if left.py_funcs is None: - feval.py_funcs = right.py_funcs - elif right.py_funcs is None: - feval.py_funcs = left.py_funcs - else: - feval.py_funcs = left.py_funcs + right.py_funcs - feval.allocate_stack() - return feval - - -def fast_float_constant(x): - """ - Return a fast-to-evaluate constant function. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant - sage: f = fast_float_constant(-2.75) - sage: f() - -2.75 - - This is all that goes on under the hood:: - - sage: fast_float_constant(pi).op_list() - ['push 3.1415926535...'] - """ - return FastDoubleFunc('const', x) - -def fast_float_arg(n): - """ - Return a fast-to-evaluate argument selector. - - INPUT: - - - ``n`` -- the (zero-indexed) argument to select - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) - sage: f(1,2) - 1.0 - sage: f = fast_float_arg(1) - sage: f(1,2) - 2.0 - - This is all that goes on under the hood:: - - sage: fast_float_arg(10).op_list() - ['load 10'] - """ - return FastDoubleFunc('arg', n) - -def fast_float_func(f, *args): - """ - Returns a wrapper around a python function. - - INPUT: - - - ``f`` -- a callable python object - - ``args`` -- a list of FastDoubleFunc inputs - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg - sage: f = fast_float_arg(0) - sage: g = fast_float_arg(1) - sage: h = fast_float_func(lambda x,y: x-y, f, g) - sage: h(5, 10) - -5.0 - - This is all that goes on under the hood:: - - sage: h.op_list() - ['load 0', 'load 1', 'py_call at 0x...>(2)'] - """ - return FastDoubleFunc('callable', f, *args) def fast_float(f, *vars, old=None, expect_one_var=False): @@ -1370,11 +128,6 @@ def fast_float(f, *vars, old=None, expect_one_var=False): except AttributeError: pass - try: - return FastDoubleFunc('const', float(f)) - except TypeError: - pass - try: from sage.symbolic.ring import SR return fast_float(SR(f), *vars) @@ -1388,4 +141,4 @@ def fast_float(f, *vars, old=None, expect_one_var=False): def is_fast_float(x): - return isinstance(x, FastDoubleFunc) or isinstance(x, Wrapper) + return isinstance(x, Wrapper) From 31b873a91c826c111ae51cd172bb5911c2472c37 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 15:07:39 -0700 Subject: [PATCH 323/355] src/sage/calculus/integration.pyx: Remove handling of FastDoubleFunc --- src/sage/calculus/integration.pyx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 156e6c5140a..51dfc10c9d9 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -32,7 +32,6 @@ from memory_allocator cimport MemoryAllocator from sage.rings.real_double import RDF from sage.libs.gsl.all cimport * from sage.misc.sageinspect import sage_getargspec -from sage.ext.fast_eval cimport FastDoubleFunc from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf from sage.ext.fast_callable import fast_callable @@ -61,9 +60,6 @@ cdef double c_f(double t, void *params): return value -cdef double c_ff(double t, void *params): - return (params)._call_c(&t) - def numerical_integral(func, a, b=None, algorithm='qag', @@ -273,7 +269,7 @@ def numerical_integral(func, a, b=None, cdef gsl_integration_workspace* W W = NULL - if not isinstance(func, FastDoubleFunc): + if True: from sage.rings.infinity import Infinity try: if hasattr(func, 'arguments'): @@ -318,11 +314,7 @@ def numerical_integral(func, a, b=None, func = fast_callable(func, vars=[v]) - if isinstance(func, FastDoubleFunc): - F.function = c_ff - F.params = func - - elif not isinstance(func, compiled_integrand): + if not isinstance(func, compiled_integrand): wrapper = PyFunctionWrapper() if not func is None: wrapper.the_function = func From 71103cb3d41a7e3ecac102430e0bfc124532f86a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 15:12:22 -0700 Subject: [PATCH 324/355] src/sage/plot/plot3d/parametric_surface.pyx: Remove handling of FastDoubleFunc --- src/sage/plot/plot3d/parametric_surface.pyx | 40 ++++----------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 42d3cb37430..1d62774e186 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -92,7 +92,6 @@ from sage.rings.all import RDF from sage.plot.colors import check_color_data from .base import RenderParams from .transform cimport point_c, face_c -from sage.ext.fast_eval cimport FastDoubleFunc from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf include "point_c.pxi" @@ -605,8 +604,7 @@ cdef class ParametricSurface(IndexFaceSet): - tuple -- split into fx, fy, fz and call each separately - callable -- call f(u,v) - In addition, branches are taken for efficient calling of FastDoubleFunc - (including whether to iterate over python or c doubles). + In addition, branches are taken for efficient calling of fast callables """ cdef Py_ssize_t i, j cdef Py_ssize_t m = len(urange) @@ -634,23 +632,15 @@ cdef class ParametricSurface(IndexFaceSet): fx, fy, fz = self.f # First, deal with the fast functions (if any) - fast_x = isinstance(fx, (FastDoubleFunc, Wrapper_rdf)) - fast_y = isinstance(fy, (FastDoubleFunc, Wrapper_rdf)) - fast_z = isinstance(fz, (FastDoubleFunc, Wrapper_rdf)) + fast_x = isinstance(fx, Wrapper_rdf) + fast_y = isinstance(fy, Wrapper_rdf) + fast_z = isinstance(fz, Wrapper_rdf) if fast_x or fast_y or fast_z: ulist = to_double_array(urange) vlist = to_double_array(vrange) res = self.vs - if isinstance(fx, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.x = (fx)._call_c(uv) - res += 1 - elif fast_x: # must be Wrapper_rdf + if fast_x: # must be Wrapper_rdf for i in range(m): uv[0] = ulist[i] for j in range(n): @@ -660,15 +650,7 @@ cdef class ParametricSurface(IndexFaceSet): res += 1 res = self.vs - if isinstance(fy, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.y = (fy)._call_c(uv) - res += 1 - elif fast_y: # must be Wrapper_rdf + if fast_y: # must be Wrapper_rdf for i from 0 <= i < m: uv[0] = ulist[i] for j from 0 <= j < n: @@ -678,15 +660,7 @@ cdef class ParametricSurface(IndexFaceSet): res += 1 res = self.vs - if isinstance(fz, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.z = (fz)._call_c(uv) - res += 1 - elif fast_z: # must be Wrapper_rdf + if fast_z: # must be Wrapper_rdf for i in range(m): uv[0] = ulist[i] for j in range(n): From 38aab890d846e8253187142c3407fc99a9a4238c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jul 2021 15:16:56 -0700 Subject: [PATCH 325/355] src/sage/ext/fast_eval.pyx: Reduce/update documentation --- src/sage/ext/fast_eval.pyx | 44 +++----------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index c00b52dd134..7b45ea1c5a0 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -9,47 +9,9 @@ point values. Doing this via recursive calls over a python representation of the object (even if Maxima or other outside packages are not involved) is extremely inefficient. -Up until now the solution has been to use lambda expressions, but this -is neither intuitive, Sage-like, nor efficient (compared to operating -on raw C doubles). This module provides a representation of algebraic -expression in Reverse Polish Notation, and provides an efficient -interpreter on C double values as a callable python object. It does -what it can in C, and will call out to Python if necessary. - -Essential to the understanding of this class is the distinction -between symbolic expressions and callable symbolic expressions (where -the latter binds argument names to argument positions). The -``*vars`` parameter passed around encapsulates this information. - -See the function ``fast_float(f, *vars)`` to create a fast-callable -version of f. - -.. NOTE:: - - Sage temporarily has two implementations of this functionality ; - one in this file, which will probably be deprecated soon, and one in - fast_callable.pyx. The following instructions are for the old - implementation; you probably want to be looking at fast_callable.pyx - instead. - -To provide this interface for a class, implement ``fast_float_(self, *vars)``. The basic building blocks are -provided by the functions ``fast_float_constant`` (returns a -constant function), ``fast_float_arg`` (selects the ``n``-th value -when called with ``\ge_n`` arguments), and ``fast_float_func`` which -wraps a callable Python function. These may be combined with the -standard Python arithmetic operators, and support many of the basic -math functions such ``sqrt``, ``exp``, and trig functions. - -TESTS: - -This used to segfault because of an assumption that assigning None to a -variable would raise a TypeError:: - - sage: from sage.ext.fast_eval import fast_float_arg, fast_float - sage: fast_float_arg(0)+None - Traceback (most recent call last): - ... - TypeError +The solution implemented in this module, by Robert Bradshaw (2008-10), +has been superseded by :func:`~sage.ext.fast_callable.fast_callable`. +All that remains here is a compatible interface function :func:`fast_float`. AUTHORS: From 36ed79788d2b946eab24d3cf1e219d4014f500d6 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 21 Jul 2021 18:21:08 -0400 Subject: [PATCH 326/355] Trac #32234: use fast_callable() for symbolic find_root(). --- src/sage/symbolic/expression.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index b0374f26cd4..c9964c1cbc6 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12481,7 +12481,8 @@ cdef class Expression(CommutativeRingElement): else: raise RuntimeError("no zero in the interval, since constant expression is not 0.") elif self.number_of_arguments() == 1: - f = self._fast_float_(self.default_variable()) + from sage.ext.fast_callable import fast_callable + f = fast_callable(self, vars=[self.default_variable()]) return find_root(f, a=a, b=b, xtol=xtol, rtol=rtol,maxiter=maxiter, full_output=full_output) From dc130386753d735693d450d43409468c9ce16170 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 21 Jul 2021 18:24:40 -0400 Subject: [PATCH 327/355] Trac #32234: don't import fast_callable() from sage.ext.fast_eval. This function is defined in sage.ext.fast_callable, and is only imported into sage.ext.fast_eval incidentally. --- src/sage/calculus/riemann.pyx | 2 +- src/sage/numerical/optimize.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 5d5d550c7cc..ac59aa2a898 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -30,7 +30,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.misc.decorators import options from sage.plot.all import list_plot, Graphics -from sage.ext.fast_eval import fast_callable +from sage.ext.fast_callable import fast_callable from sage.rings.all import CDF diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 6686b269ed5..82c90f72a63 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -385,7 +385,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm="default", (1.0, 1.0, 1.0) """ from sage.symbolic.expression import Expression - from sage.ext.fast_eval import fast_callable + from sage.ext.fast_callable import fast_callable import numpy from scipy import optimize if isinstance(func, Expression): @@ -505,7 +505,7 @@ def minimize_constrained(func,cons,x0,gradient=None,algorithm='default', **args) (805.985..., 1005.985...) """ from sage.symbolic.expression import Expression - from sage.ext.fast_eval import fast_callable + from sage.ext.fast_callable import fast_callable import numpy from scipy import optimize function_type = type(lambda x,y: x+y) @@ -779,7 +779,7 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N raise ValueError("length of initial_guess does not coincide with the number of parameters") if isinstance(model, Expression): - from sage.ext.fast_eval import fast_callable + from sage.ext.fast_callable import fast_callable var_list = variables + parameters func = fast_callable(model, vars=var_list) else: From 7b3429f23e8e612c961d6684a407f3ea4dd0a4cf Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 21 Jul 2021 19:46:53 -0400 Subject: [PATCH 328/355] Trac #32234: replace fast_float_arg() in plot3d. The fast_float_arg() function is based on the old sage.ext.fast_eval module. We replace two uses of it within plot3d with fast_callable() from sage.ext.fast_callable. --- src/sage/plot/plot3d/plot3d.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index d5951640950..238992fe483 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -149,8 +149,6 @@ def f(x,y): return math.exp(x/5)*math.cos(y) from sage.plot.colors import rainbow from .texture import Texture -from sage.ext.fast_eval import fast_float_arg - from sage.functions.trig import cos, sin from sage.misc.sageinspect import sage_getargspec, is_function_or_cython_function @@ -1086,9 +1084,16 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): elif adaptive: P = plot3d_adaptive(f, urange, vrange, **kwds) else: - u=fast_float_arg(0) - v=fast_float_arg(1) - P=parametric_plot3d.parametric_plot3d((u,v,f), urange, vrange, **kwds) + from sage.ext.fast_callable import fast_callable, ExpressionTreeBuilder + etb = ExpressionTreeBuilder(vars=('u','v')) + u = etb.var('u') + v = etb.var('v') + arg1 = fast_callable(u, vars=[u,v]) + arg2 = fast_callable(v, vars=[u,v]) + P = parametric_plot3d.parametric_plot3d((arg1,arg2,f), + urange, + vrange, + **kwds) P.frame_aspect_ratio([1.0,1.0,0.5]) return P From 0b0822353ba13257989b361075c713225af8e547 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 22 Jul 2021 08:28:20 -0400 Subject: [PATCH 329/355] Trac #32234: fix symbolic find_local_minimum() docs. The INPUT documentation for symbolic find_local_minimum() was in the wrong order. Now it isn't. --- src/sage/symbolic/expression.pyx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index c9964c1cbc6..8f25fc94837 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12519,16 +12519,20 @@ cdef class Expression(CommutativeRingElement): INPUT: - - ``var`` - variable (default: first variable in - self) + - ``a`` - real number; left endpoint of interval on which to + minimize - - ``a,b`` - endpoints of interval on which to minimize - self. + - ``b`` - real number; right endpoint of interval on which to + minimize - - ``tol`` - the convergence tolerance + - ``var`` - variable (default: first variable in self); the + variable in self to maximize over - - ``maxfun`` - maximum function evaluations + - ``tol`` - positive real (default: 1.48e-08); the convergence + tolerance + - ``maxfun`` - natural number (default: 500); maximum function + evaluations OUTPUT: From e1777227f9b8fba8e74e5add682fbec7776368af Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 22 Jul 2021 09:09:42 -0400 Subject: [PATCH 330/355] Trac #32234: use domain=float for fast callables used by numpy. If we pass a fast_callable() to numpy without specifying its domain, we run the risk of hitting a NaN and triggering an error like, TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' Our numeric routines (in particular, find_root) are not expecting this. Instead, they want numpy to detect the NaN and give up, returning a tuple that contains some information about where we stopped. To let numpy detect the NaN, it seems to suffice to pass domain=float to the fast_callable() function. We do this for both the symbolic find_local_minimum() and find_root(). --- src/sage/symbolic/expression.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 8f25fc94837..3a918c4ce80 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12482,7 +12482,8 @@ cdef class Expression(CommutativeRingElement): raise RuntimeError("no zero in the interval, since constant expression is not 0.") elif self.number_of_arguments() == 1: from sage.ext.fast_callable import fast_callable - f = fast_callable(self, vars=[self.default_variable()]) + # The domain=float is important for numpy if we encounter NaN. + f = fast_callable(self, vars=[self.default_variable()], domain=float) return find_root(f, a=a, b=b, xtol=xtol, rtol=rtol,maxiter=maxiter, full_output=full_output) @@ -12571,7 +12572,8 @@ cdef class Expression(CommutativeRingElement): if var is None: var = self.default_variable() - f = fast_callable(self, vars=[var]) + # The domain=float is important for numpy if we encounter NaN. + f = fast_callable(self, vars=[var], domain=float) return find_local_minimum(f, a=a, b=b, tol=tol, maxfun=maxfun) ################### From 138eab9de20c0893aa661af1bcdcb6cf90d44267 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 27 Jul 2021 15:56:41 -0400 Subject: [PATCH 331/355] Trac #32234: replace two trivial fast-callables in plot3d(). We tried too hard. We are currently creating two fast-callable functions in plot3d() that pick out the first and second elements of an ordered pair, respectively. Although fast_callable() has "fast" in the name, a little experimentation shows that e.g. "lambda u,v: u" is much faster then its fast-callable counterpart. This commit switches to the faster, simpler implementation. --- src/sage/plot/plot3d/plot3d.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 238992fe483..06dd6a9df65 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1084,12 +1084,8 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): elif adaptive: P = plot3d_adaptive(f, urange, vrange, **kwds) else: - from sage.ext.fast_callable import fast_callable, ExpressionTreeBuilder - etb = ExpressionTreeBuilder(vars=('u','v')) - u = etb.var('u') - v = etb.var('v') - arg1 = fast_callable(u, vars=[u,v]) - arg2 = fast_callable(v, vars=[u,v]) + arg1 = lambda u,v: u + arg2 = lambda u,v: v P = parametric_plot3d.parametric_plot3d((arg1,arg2,f), urange, vrange, From 96ba1213fa281beba55d95f15352b09699eea45f Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 2 Oct 2021 08:53:45 -0400 Subject: [PATCH 332/355] Trac #32234: use domain=float in a few more fast_callables. In an earlier commit, some numerical routines were converted from the old fast_float() to fast_callable(). Since these interface with external libraries that expect floats, there is no harm in passing domain=float when we construct the fast callable. This should provide a minor speedup; and is probably closer to the old behavior anyway. --- src/sage/calculus/integration.pyx | 2 +- src/sage/numerical/optimize.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 51dfc10c9d9..7d624bf7528 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -311,7 +311,7 @@ def numerical_integral(func, a, b=None, else: if ell.is_numeric() and not ell.is_zero(): raise ValueError('integral does not converge at infinity') - func = fast_callable(func, vars=[v]) + func = fast_callable(func, vars=[v], domain=float) if not isinstance(func, compiled_integrand): diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 82c90f72a63..b21e0f471bd 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -512,17 +512,20 @@ def minimize_constrained(func,cons,x0,gradient=None,algorithm='default', **args) if isinstance(func, Expression): var_list = func.variables() - fast_f = fast_callable(func, vars=var_list) + fast_f = fast_callable(func, vars=var_list, domain=float) f = lambda p: fast_f(*p) gradient_list = func.gradient() - fast_gradient_functions = [ fast_callable(gi, vars=var_list) + fast_gradient_functions = [ fast_callable(gi, + vars=var_list, + domain=float) for gi in gradient_list ] gradient = lambda p: numpy.array([ a(*p) for a in fast_gradient_functions]) if isinstance(cons, Expression): - fast_cons = fast_callable(cons, vars=var_list) + fast_cons = fast_callable(cons, vars=var_list, domain=float) cons = lambda p: numpy.array([fast_cons(*p)]) elif isinstance(cons, list) and isinstance(cons[0], Expression): - fast_cons = [fast_callable(ci, vars=var_list) for ci in cons] + fast_cons = [ fast_callable(ci, vars=var_list, domain=float) + for ci in cons ] cons = lambda p: numpy.array([a(*p) for a in fast_cons]) else: f = func @@ -781,7 +784,7 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N if isinstance(model, Expression): from sage.ext.fast_callable import fast_callable var_list = variables + parameters - func = fast_callable(model, vars=var_list) + func = fast_callable(model, vars=var_list, domain=float) else: func = model From 092b66ee0aac495464fda649509e3441894c3b67 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 2 Oct 2021 15:42:57 +0200 Subject: [PATCH 333/355] trac #13521: more flexible vertex labels in graph plot --- src/sage/graphs/graph_plot.py | 70 ++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 558eb4f22c8..fdcf2f1461c 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -175,7 +175,11 @@ 'pos': 'The position dictionary of vertices.', 'vertex_labels': - 'Whether or not to draw vertex labels.', + 'Vertex labels to draw. This can be ``True``/``False`` to indicate ' + 'whether to print the vertex string representation of not, ' + 'a dictionary keyed by vertices and associating to each vertex ' + 'a label string, or a function taking as input a vertex and returning ' + 'a label string.', 'vertex_color': 'Default color for vertices not listed ' 'in vertex_colors dictionary.', @@ -429,6 +433,54 @@ def set_vertices(self, **vertex_options): GP.set_vertices(talk=True) GP.set_vertices(vertex_color='green', vertex_shape='^') sphinx_plot(GP) + + Vertex labels are flexible:: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=False) + Graphics object consisting of 4 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=False) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=True) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=True) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=dict(zip(g, ['+', '-', '/', '*']))) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=dict(zip(g, ['+', '-', '/', '*']))) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=lambda x: str(x % 2)) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=lambda x: str(x % 2)) + sphinx_plot(P) """ # Handle base vertex options voptions = {} @@ -509,12 +561,18 @@ def set_vertices(self, **vertex_options): self._plot_components['vertices'] = scatter_plot( pos, facecolor=colors, clip=False, **voptions) - if self._options['vertex_labels']: - self._plot_components['vertex_labels'] = [] + vlabels = self._options['vertex_labels'] + if vlabels: + if vlabels is True: + vfun = str + elif isinstance(vlabels, dict): + def vfun(x): + return vlabels.get(x, "") + else: + vfun = vlabels # TODO: allow text options - for v in self._nodelist: - self._plot_components['vertex_labels'].append( - text(str(v), self._pos[v], rgbcolor=(0, 0, 0), zorder=8)) + self._plot_components['vertex_labels'] = [text(vfun(v), self._pos[v], color='black', zorder=8) + for v in self._nodelist] def set_edges(self, **edge_options): """ From 1276609634a35c5d4b0131661791f4d47f1914cf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 08:48:43 -0700 Subject: [PATCH 334/355] src/sage/matrix/matrix_gfpn_dense.pyx: Use # sage.doctest: optional - meataxe --- src/sage/matrix/matrix_gfpn_dense.pyx | 163 +++++++++++++------------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index affaa351af6..c33e987ac21 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -1,5 +1,6 @@ # distutils: libraries = mtx # sage_setup: distribution = sagemath-meataxe +# sage.doctest: optional - meataxe r""" Dense Matrices over `\mathbb F_q`, with `q<255`. @@ -94,15 +95,15 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F. = GF(125) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y - sage: C.field_to_fel(y) # optional: meataxe + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -116,8 +117,8 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe - sage: FieldConverter_class(GF(13^2)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class + sage: FieldConverter_class(GF(13^2)) """ self.field = field._cache.fetch_int @@ -129,10 +130,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y @@ -145,10 +146,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(y) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -157,7 +158,7 @@ cdef class FieldConverter_class: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... AttributeError: 'str' object has no attribute 'integer_representation' @@ -187,15 +188,15 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F = GF(5) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(2) 2 sage: F(2) 2 - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C.field_to_fel(F(2)) 2 sage: int(F(2)) 2 @@ -209,8 +210,8 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe - sage: PrimeFieldConverter_class(GF(251)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class + sage: PrimeFieldConverter_class(GF(251)) """ self.field = field @@ -221,10 +222,10 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.fel_to_field(2) 2 """ return IntegerMod_int(self.field, FfToInt(x)) @@ -235,17 +236,17 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.field_to_fel(F(2)) 2 TESTS: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... TypeError: an integer is required @@ -339,7 +340,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: print(M) [1 2 3] [4 0 1] - sage: type(M) # optional: meataxe + sage: type(M) The documentation of the ``__init__`` methods shows further @@ -355,11 +356,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): TESTS:: sage: MS = MatrixSpace(GF(64), 0) - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) [] sage: M = None - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) sage: del M # indirect doctest """ if self.Data != NULL: @@ -384,27 +385,27 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense 1. Creating a zero (3x2)-matrix:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) [0 0] [0 0] [0 0] 2. Creating a matrix from a list or list of lists:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) [1 2 3] [4 0 1] - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) [1 2 3] [4 0 1] 3. Creating a diagonal matrix:: - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M [2 0 0 0 0] [0 2 0 0 0] [0 0 2 0 0] @@ -457,12 +458,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): does not exist, an error raised by the MeatAxe library is propagated:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') Traceback (most recent call last): ... OSError: foobarNONEXISTING_FILE: No such file or directory in file os.c (line 255) - sage: Matrix_gfpn_dense.from_filename('') # optional: meataxe + sage: Matrix_gfpn_dense.from_filename('') Traceback (most recent call last): ... ValueError: cannot construct meataxe matrix from empty filename @@ -496,9 +497,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): True sage: N is M False - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) # optional: meataxe - sage: copy(M) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) + sage: copy(M) Traceback (most recent call last): ... ValueError: cannot copy an uninitialized matrix @@ -559,7 +560,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: F. = GF(9) sage: M = MatrixSpace(F,3)(sorted(list(F))) - sage: type(M) # optional: meataxe + sage: type(M) sage: M # indirect doctest [ 0 1 2] @@ -606,18 +607,18 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX # optional: meataxe - sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) # optional: meataxe - sage: M # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX + sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) + sage: M [0 1 2] [1 2 3] [2 3 4] [3 4 5] [4 5 6] - sage: M.get_slice(1,3) # optional: meataxe + sage: M.get_slice(1,3) [1 2 3] [2 3 4] - sage: type(_) is MTX # optional: meataxe + sage: type(_) is MTX True """ @@ -696,23 +697,23 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: MS = MatrixSpace(GF(27,'z'),6,6) sage: M = MS.random_element() # indirect doctest - sage: M # optional: meataxe + sage: M [ 1 z + 1 z^2 + z + 1 z^2 2*z^2 + z z + 1] [2*z^2 + 2*z + 2 2*z^2 + z + 2 z^2 + 1 2*z^2 + 2*z + 2 z^2 + z 2*z^2 + z + 1] [ 2*z + 2 z^2 + z + 2 z + 2 2*z^2 + 2*z + 2 2*z^2 2*z^2] [ 2*z^2 + z + 2 z^2 z + 2 z^2 + z 2*z^2 + 2 z^2 + 2] [ 2*z^2 + z 2*z 2*z^2 + 2*z + 1 2*z^2 + 1 2*z^2 + 2*z + 1 2*z^2 + z] [ 2*z + 1 z^2 + z z^2 z^2 2*z^2 + 2*z z + 1] - sage: type(M) # optional: meataxe + sage: type(M) - sage: MS.random_element(nonzero=True) # optional: meataxe + sage: MS.random_element(nonzero=True) [ 2*z 1 z^2 + 2*z + 1 2*z^2 + z + 1 z^2 z^2 + z + 1] [ 2*z^2 + 2*z 2*z^2 + z + 2 2*z + 1 z^2 + 2*z 2*z^2 + 2*z z^2] [ z^2 + z z^2 + z + 2 2*z^2 + 2*z + 1 z^2 + 2 1 2*z^2] [ z 2*z^2 + 2*z 2*z^2 2*z + 1 z + 2 z + 2] [ z^2 + z z^2 z + 2 2*z^2 + 2*z 2*z + 1 z^2 + z] [ z^2 + z + 2 2*z^2 + z z^2 z + 1 2*z^2 + 2*z z^2 + 2*z + 1] - sage: MS.random_element(density=0.5) # optional: meataxe + sage: MS.random_element(density=0.5) [ z^2 + 2 0 z^2 + 2*z + 2 2*z^2 + z 0 z^2 + z + 2] [ 0 1 0 0 0 0] [ 2*z^2 + z + 1 2*z^2 + z + 2 0 z^2 + z + 2 0 z^2 + z + 1] @@ -723,7 +724,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): The following tests against a bug that was fixed in :trac:`23352`:: sage: MS = MatrixSpace(GF(9,'x'),1,5) - sage: MS.random_element() # optional: meataxe + sage: MS.random_element() [x + 1 x 2 x + 2 x + 2] """ @@ -897,19 +898,19 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: sage: M = random_matrix(GF(25,'x'), 5,5) - sage: M # optional: meataxe + sage: M [ 4 4*x x + 3 4*x + 2 3*x + 4] [ x + 2 3*x + 1 3 0 3] [ 3*x 2*x + 4 1 0 2*x] [4*x + 4 2*x + 3 4*x 1 3*x + 1] [3*x + 3 x + 3 x + 2 x + 1 3*x + 2] - sage: M._rowlist_(1) # optional: meataxe + sage: M._rowlist_(1) [7, 16, 3, 0, 3] - sage: [M[1,i]._int_repr() for i in range(5)] # optional: meataxe + sage: [M[1,i]._int_repr() for i in range(5)] ['7', '16', '3', '0', '3'] - sage: M._rowlist_(2,4) # optional: meataxe + sage: M._rowlist_(2,4) [15, 14, 1, 0, 10, 24, 13, 20, 1, 16, 18, 8, 7, 6, 17] - sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] # optional: meataxe + sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] [['15', '14', '1', '0', '10'], ['24', '13', '20', '1', '16'], ['18', '8', '7', '6', '17']] @@ -1340,7 +1341,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1000,500).random_element() sage: N = MatrixSpace(GF(9,'x'),500,2000).random_element() - sage: M*N == M._multiply_classical(N) # optional: meataxe + sage: M*N == M._multiply_classical(N) True """ @@ -1376,7 +1377,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1500,600).random_element() sage: N = MatrixSpace(GF(9,'x'),600,1500).random_element() - sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) # optional: meataxe + sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) True """ @@ -1483,7 +1484,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): ....: M = MS.random_element(density=0.4) ....: if M.rank() < 5: ....: break - sage: ~M # optional: meataxe + sage: ~M Traceback (most recent call last): ... ZeroDivisionError: Division by zero in file matinv.c (line 50) @@ -1540,7 +1541,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(K, 4)([2*x^2 + 2*x, 2*x^2 + x, 2*x^2 + x + 1, ....: x^2 + x + 2, x + 2, x^2, 2*x + 2, 2*x^2 + 2*x, 2*x^2 + 1, ....: 1, 2, x^2 + 2*x + 1, x^2 + x + 2, x + 1, 2*x^2 + 2*x, x^2 + x]) - sage: M.order() # optional: meataxe + sage: M.order() 104 sage: M^104 == 1 True @@ -1594,7 +1595,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): Basis matrix: [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] - sage: M.left_kernel_matrix() # optional: meataxe + sage: M.left_kernel_matrix() [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] @@ -1707,9 +1708,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): method directly:: sage: N = copy(M) - sage: N._echelon_in_place_classical(reduced=False) # optional: meataxe + sage: N._echelon_in_place_classical(reduced=False) (2, 1, 3, 4, 5, 6, 7, 8) - sage: N # optional: meataxe + sage: N [ 0 0 x 0 3*x + 2 0 0 0 2*x 0] [ 0 x + 3 0 0 0 3*x x + 4 0 0 0] [ 0 0 0 2*x 0 4*x + 1 4 0 0 0] @@ -1726,7 +1727,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): We verify that the above echelon form is consistent with Sage's generic implementation of dense matrices:: - sage: type(M) # optional: meataxe + sage: type(M) sage: MS = MatrixSpace(M.base_ring(), M.nrows(), M.ncols(), implementation='generic') sage: X = MS(M) @@ -1864,19 +1865,19 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: s = b'Uq\x82\xa7\x8bh' sage: len(s) 6 - sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense # optional: meataxe - sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) # optional: meataxe - sage: N = mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe - sage: N # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense + sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) + sage: N = mtx_unpickle(MS, 2, 5, s, True) + sage: N [ 6 7 8 9 10] [12 11 10 9 8] - sage: type(N) # optional: meataxe + sage: type(N) We demonstrate that a slightly different pickle format can be understood as well, that was at some point used by some optional package:: - sage: N == mtx_unpickle(int(13), 2, 5, s, True) # optional: meataxe + sage: N == mtx_unpickle(int(13), 2, 5, s, True) True In a previous version of this optional module, the whole memory chunk @@ -1887,7 +1888,7 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00' sage: len(t) 16 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) doctest:warning ... DeprecationWarning: Reading this pickle may be machine dependent @@ -1900,12 +1901,12 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' sage: len(t) 18 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) True The data may be empty, which results in the zero matrix:: - sage: mtx_unpickle(MS, 2, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, b'', True) [0 0 0 0 0] [0 0 0 0 0] @@ -1914,27 +1915,27 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): pickle format (we test several code paths here):: sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t, True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 17 instead sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t[:4], True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t[:4], True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 2*2 instead sage: MS = MatrixSpace(GF(13), 0, 5) - sage: mtx_unpickle(MS, 0, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 0, 5, s, True) Traceback (most recent call last): ... ValueError: This matrix pickle contains data, thus, the number of rows and columns must be positive sage: MS = MatrixSpace(GF(13), 3, 5) - sage: mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, s, True) Traceback (most recent call last): ... ValueError: Inconsistent dimensions in this matrix pickle - sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) [] """ # The expected input type is bytes. However, Python-2 legacy pickles do From 848cf86999bec0e3a7058417fe02b6b35d2ff8c9 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 2 Oct 2021 20:42:19 +0100 Subject: [PATCH 335/355] use inner_product and sqrtrem --- src/sage/modules/diamond_cutting.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index 458d98ca539..b18fc315754 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -258,7 +258,10 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): artificial_length = None if dim[0] < dim[1]: # introduce "artificial" basis points (representing infinity) - artificial_length = max(v.norm(1) for v in basis).ceil() * 2 + def approx_norm(v): + r,r1 = (v.inner_product(v)).sqrtrem() + return r + (r1 > 0) + artificial_length = max(approx_norm(v) for v in basis) * 2 additional_vectors = identity_matrix(dim[1]) * artificial_length basis = basis.stack(additional_vectors) # LLL-reduce to get quadratic matrix @@ -277,7 +280,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): # twice the length of longest vertex in Q is a safe choice if radius is None: - radius = 2 * max(v.norm(1) ** 2 for v in basis) + radius = 2 * max(v.inner_product(v) for v in basis) V = diamond_cut(Q, basis, radius, verbose=verbose) From 1bbe46bb87f2e036d813025261588d05f8138cf3 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 2 Oct 2021 23:12:23 +0200 Subject: [PATCH 336/355] trac #13521: pyflakes --- src/sage/graphs/graph_plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index fdcf2f1461c..23ffeb016f0 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -126,10 +126,10 @@ # **************************************************************************** from collections import defaultdict -from math import sqrt, cos, sin, acos, atan, pi +from math import sqrt, cos, sin, atan, pi from sage.structure.sage_object import SageObject from sage.plot.all import ( - Graphics, scatter_plot, bezier_path, line, arrow, text, arc, circle) + Graphics, scatter_plot, bezier_path, line, arrow, text, circle) layout_options = { 'layout': From 4764e6085d7598756fe20367f13ee4a99b7f4806 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 3 Oct 2021 11:53:59 +0200 Subject: [PATCH 337/355] trac #30998: review comments --- .../tree_decomposition.pyx | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 45ff3e60e32..b3f59228434 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -106,7 +106,6 @@ from itertools import combinations from itertools import chain from sage.features import PythonModule from sage.sets.disjoint_set import DisjointSet -from sage.functions.other import ceil from sage.rings.infinity import Infinity from sage.graphs.distances_all_pairs cimport c_distances_all_pairs from cysignals.memory cimport sig_malloc, sig_calloc, sig_free @@ -780,7 +779,7 @@ def treelength_lowerbound(G): r""" Return a lower bound on the treelength of `G`. - See [DG2006]_ for more details`. + See [DG2006]_ for more details. INPUT: @@ -806,6 +805,7 @@ def treelength_lowerbound(G): 0 """ if G.is_cycle(): + from sage.functions.other import ceil return int(ceil(G.order() / 3.0)) lowerbound = 0 @@ -824,7 +824,7 @@ cdef class TreelengthConnected: connected graph that virtually explores the graph of all pairs ``(vertex_cut, connected_component)``, where ``vertex_cut`` is a vertex cut of the graph of length `\leq k`, and ``connected_component`` is a connected - component of the graph induced by `G - vertex_cut`. + component of the graph induced by ``G - vertex_cut``. We deduce that the pair ``(vertex_cut, connected_component)`` is feasible with treelength `k` if ``connected_component`` is empty, or if a vertex @@ -846,10 +846,10 @@ cdef class TreelengthConnected: OUTPUT: - ``TreelengthConnected(G)`` returns the treelength of `G`. When `k` is - specified, it returns ``False`` when no tree-decomposition of length - `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the - tree-decomposition is also returned. + ``TreelengthConnected(G)`` returns the treelength of `G`. When `k` is + specified, it returns ``False`` when no tree-decomposition of length + `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the + tree-decomposition is also returned. EXAMPLES: @@ -970,7 +970,7 @@ cdef class TreelengthConnected: self.leq_k = True # We know that k is non negative return - if self.k_is_defined and k == 0: + if self.k_is_defined and not k: # We have at least 2 vertices and 1 edges, so tl >= 1 self.leq_k = False return @@ -1030,7 +1030,7 @@ cdef class TreelengthConnected: else: self.leq_k = False - def __destroy__(self): + def __dealloc__(self): r""" Destroy the object @@ -1261,6 +1261,15 @@ def treelength(G, k=None, certificate=False): r""" Compute the treelength of `G` (and provide a decomposition). + The *length* of a tree decomposition, as proposed in [DG2006]_, is the + maximum *diameter* in `G` of its bags, where the diameter of a bag `X_i` is + the largest distance in `G` between the vertices in `X_i` (i.e., `\max_{u, v + \in X_i} dist_G(u, v)`). The *treelength* `tl(G)` of a graph `G` is the + minimum length among all possible tree decompositions of `G`. + See the documentation of the + :mod:`~sage.graphs.graph_decompositions.tree_decomposition` module for more + details. + INPUT: - ``G`` -- a sage Graph @@ -1275,31 +1284,31 @@ def treelength(G, k=None, certificate=False): OUTPUT: - ``G.treelength()`` returns the treelength of `G`. When `k` is specified, - it returns ``False`` when no tree-decomposition of length `\leq k` - exists or ``True`` otherwise. When ``certificate=True``, the - tree-decomposition is also returned. + ``G.treelength()`` returns the treelength of `G`. When `k` is specified, it + returns ``False`` when no tree-decomposition of length `\leq k` exists or + ``True`` otherwise. When ``certificate=True``, the tree-decomposition is + also returned. ALGORITHM: - This method virtually explores the graph of all pairs ``(vertex_cut, - connected_component)``, where ``vertex_cut`` is a vertex cut of the - graph of length `\leq k`, and ``connected_component`` is a - connected component of the graph induced by `G - vertex_cut`. - - We deduce that the pair ``(vertex_cut, connected_component)`` is - feasible with treelength `k` if ``connected_component`` is empty, or if - a vertex ``v`` from ``vertex_cut`` can be replaced with a vertex from - ``connected_component``, such that the pair ``(vertex_cut + v, - connected_component - v)`` is feasible. - - In practice, this method decomposes the graph by its clique minimal - separators into atoms, computes the treelength of each of atom and - returns the maximum value over all the atoms. Indeed, we have that - `tl(G) = \max_{X \in A} tl(G[X])` where `A` is the set of atoms of the - decomposition by clique separators of `G`. When ``certificate == True``, - the tree-decompositions of the atoms are connected to each others by - adding edges with respect to the clique separators. + This method virtually explores the graph of all pairs ``(vertex_cut, + connected_component)``, where ``vertex_cut`` is a vertex cut of the graph of + length `\leq k`, and ``connected_component`` is a connected component of the + graph induced by `G - vertex_cut`. + + We deduce that the pair ``(vertex_cut, connected_component)`` is feasible + with treelength `k` if ``connected_component`` is empty, or if a vertex + ``v`` from ``vertex_cut`` can be replaced with a vertex from + ``connected_component``, such that the pair ``(vertex_cut + v, + connected_component - v)`` is feasible. + + In practice, this method decomposes the graph by its clique minimal + separators into atoms, computes the treelength of each of atom and returns + the maximum value over all the atoms. Indeed, we have that `tl(G) = \max_{X + \in A} tl(G[X])` where `A` is the set of atoms of the decomposition by + clique separators of `G`. When ``certificate == True``, the + tree-decompositions of the atoms are connected to each others by adding + edges with respect to the clique separators. .. SEEALSO:: @@ -1344,7 +1353,7 @@ def treelength(G, k=None, certificate=False): sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] [1, 2, 2, 2, 3, 3, 3, 4] - TESTS:: + TESTS: Check that the decomposition by clique separators is valid:: From 01d200b8f047ddc356dad7eb3172530f6fe1eee8 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 3 Oct 2021 12:53:26 +0200 Subject: [PATCH 338/355] trac #30998: ensure that the documentation is built --- src/doc/en/reference/graphs/index.rst | 1 + .../tree_decomposition.pyx | 42 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index 2347747d65b..b1ec35240de 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -91,6 +91,7 @@ Libraries of algorithms sage/graphs/traversals sage/graphs/graph_plot sage/graphs/graph_plot_js + sage/graphs/graph_decompositions/tree_decomposition sage/graphs/graph_decompositions/vertex_separation sage/graphs/graph_decompositions/rankwidth sage/graphs/graph_decompositions/bandwidth diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index b3f59228434..5301b678d16 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -9,11 +9,13 @@ X_2, \ldots, X_t\}` is a familly of subsets of `V`, usually called *bags*, and `T` is a tree of order `t` whose nodes are the subsets `X_i` satisfying the following properties: -1. The union of all sets `X_i` equals `V`. That is, each vertex of the graph `G` +- The union of all sets `X_i` equals `V`. That is, each vertex of the graph `G` is associated with at least one tree node. -2. For every edge `(v, w)` in the graph, there is a subset `X_i` that contains + +- For every edge `(v, w)` in the graph, there is a subset `X_i` that contains both `v` and `w`. That is, each edge of the graph `G` appears in a tree node. -3. The nodes associated with vertex `v \in V` form a connected subtree of + +- The nodes associated with vertex `v \in V` form a connected subtree of `T`. That is, if `X_i` and `X_j` both contain a vertex `v \in V`, then all nodes `X_k` of the tree in the (unique) path between `X_i` and `X_j` contain `v` as well, and we have `X_i \cap X_j \subseteq X_k`. @@ -74,7 +76,7 @@ The treewidth of a clique is `n-1` and its treelength is 1:: :meth:`treewidth` | Compute the treewidth of `G` (and provide a decomposition). :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. - :meth:`reduced_tree_decomposition(T)` | Return a reduced tree-decomposition of `T`. + :meth:`reduced_tree_decomposition` | Return a reduced tree-decomposition of `T`. :meth:`width_of_tree_decomposition` | Return the width of the tree decomposition `T` of `G`. @@ -248,7 +250,7 @@ def reduced_tree_decomposition(T): This method assumes that the vertices of the input tree `T` are hashable and have attribute ``issuperset``, e.g., ``frozenset`` or - :class:`~sage.sets.set.Set_object_enumerated_with_category`. + :class:`~sage.sets.set.Set_object_enumerated`. INPUT: @@ -456,22 +458,22 @@ def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): OUTPUT: - ``g.treewidth()`` returns the treewidth of ``g``. When ``k`` is - specified, it returns ``False`` when no tree-decomposition of width - `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the - tree-decomposition is also returned. + ``g.treewidth()`` returns the treewidth of ``g``. When ``k`` is specified, + it returns ``False`` when no tree-decomposition of width `\leq k` exists or + ``True`` otherwise. When ``certificate=True``, the tree-decomposition is + also returned. ALGORITHM: - This function virtually explores the graph of all pairs - ``(vertex_cut,cc)``, where ``vertex_cut`` is a vertex cut of the graph - of cardinality `\leq k+1`, and ``connected_component`` is a connected - component of the graph induced by ``G-vertex_cut``. + This function virtually explores the graph of all pairs ``(vertex_cut,cc)``, + where ``vertex_cut`` is a vertex cut of the graph of cardinality `\leq k+1`, + and ``connected_component`` is a connected component of the graph induced by + ``G-vertex_cut``. - We deduce that the pair ``(vertex_cut,cc)`` is feasible with tree-width - `k` if ``cc`` is empty, or if a vertex ``v`` from ``vertex_cut`` can be - replaced with a vertex from ``cc``, such that the pair - ``(vertex_cut+v,cc-v)`` is feasible. + We deduce that the pair ``(vertex_cut,cc)`` is feasible with tree-width `k` + if ``cc`` is empty, or if a vertex ``v`` from ``vertex_cut`` can be replaced + with a vertex from ``cc``, such that the pair ``(vertex_cut+v,cc-v)`` is + feasible. .. NOTE:: @@ -1294,7 +1296,7 @@ def treelength(G, k=None, certificate=False): This method virtually explores the graph of all pairs ``(vertex_cut, connected_component)``, where ``vertex_cut`` is a vertex cut of the graph of length `\leq k`, and ``connected_component`` is a connected component of the - graph induced by `G - vertex_cut`. + graph induced by ``G - vertex_cut``. We deduce that the pair ``(vertex_cut, connected_component)`` is feasible with treelength `k` if ``connected_component`` is empty, or if a vertex @@ -1315,8 +1317,8 @@ def treelength(G, k=None, certificate=False): - :meth:`treewidth` computes the treewidth of a graph. - :meth:`~sage.graphs.graph_decompositions.vertex_separation.path_decomposition` computes the pathwidth of a graph. - - :mod:`~sage.graphs.graph_decompositions.vertex_separation` module. - - :meth:`~sage.graphs.Graph.atoms_and_clique_separators` + - module :mod:`~sage.graphs.graph_decompositions.vertex_separation`. + - :meth:`~sage.graphs.graph_decompositions.clique_separators.atoms_and_clique_separators` EXAMPLES: From 6fc96d64d66b7e894fc0703a9324f43d54474bc4 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 3 Oct 2021 07:54:37 -0400 Subject: [PATCH 339/355] Trac #32234: fix pyflakes warning (missing scipy import). --- src/sage/numerical/optimize.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index b21e0f471bd..255e958c2d0 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -418,7 +418,8 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm="default", hess=func.hessian() hess_fast= [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess] hessian=lambda p: [[a(*p) for a in row] for row in hess_fast] - hessian_p=lambda p,v: scipy.dot(numpy.array(hessian(p)),v) + from scipy import dot + hessian_p=lambda p,v: dot(numpy.array(hessian(p)),v) min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, \ fhess=hessian, fhess_p=hessian_p, disp=verbose, **args) return vector(RDF, min) From da449a214a214b1125af78540f20cbd28be997ee Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 3 Oct 2021 14:22:14 +0200 Subject: [PATCH 340/355] trac #30998: add some type informations --- .../tree_decomposition.pxd | 1 + .../tree_decomposition.pyx | 32 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pxd b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd index b45006eb087..e8afe048691 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pxd +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd @@ -13,3 +13,4 @@ cdef class TreelengthConnected: cdef GenericGraph_pyx tree # The final tree decomposition is stored cdef unsigned int length cdef bint leq_k + cdef bint _treelength(self, g, k) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 5301b678d16..fc5f31eb57b 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -362,7 +362,7 @@ def width_of_tree_decomposition(G, T, check=True): def _from_tree_decompositions_of_atoms_to_tree_decomposition(T_atoms, cliques): r""" - Return a tree-decomposition formed by the tree_decompositions of the atoms. + Return a tree-decomposition formed by the tree-decompositions of the atoms. This is a helper method to avoid duplicated code. @@ -1048,7 +1048,7 @@ cdef class TreelengthConnected: sig_free(self.distances) - def _treelength(self, g, k): + cdef bint _treelength(self, g, k): r""" Check whether the treelength of `g` is at most `k`. @@ -1075,6 +1075,9 @@ cdef class TreelengthConnected: # tree-decomposition at the end of the _treelength method). @cached_function def rec(cut, cc): + cdef int v + cdef frozenset reduced_cut + if len(cc) == 1: [v] = cc # We identify the neighbors of v in cut @@ -1092,6 +1095,13 @@ cdef class TreelengthConnected: return True # We explore all possible extensions of the cut + cdef frozenset cutv + cdef frozenset ccv + cdef frozenset cci + cdef frozenset reduced_cuti + cdef list sons + cdef int x + for v in cc: # We know that the cut has diameter <= k. So we check is adding @@ -1107,8 +1117,8 @@ cdef class TreelengthConnected: # Removing v may have disconnected cc. We iterate on its # connected components - for cci in g.subgraph(ccv).connected_components(): - cci = frozenset(cci) + for _cci in g.subgraph(ccv).connected_components(): + cci = frozenset(_cci) # The recursive subcalls. We remove on-the-fly the vertices # from the cut which play no role in separating the @@ -1145,8 +1155,8 @@ cdef class TreelengthConnected: return False # Main call to rec function, i.e. rec({v}, V-{v}) - V = list(g) - v = frozenset([V.pop()]) + cdef list V = list(g) + cdef frozenset v = frozenset([V.pop()]) TD = rec(v, frozenset(V)) if TD is False: @@ -1407,7 +1417,7 @@ def treelength(G, k=None, certificate=False): if k is not None and k < 0: raise ValueError("k(={}) must be a nonnegative integer".format(k)) - name = "Tree decomposition" + cdef str name = "Tree decomposition" if G.name(): name += " of {}".format(G.name()) @@ -1453,9 +1463,11 @@ def treelength(G, k=None, certificate=False): # As some atoms might be isomorphic, we use a dictionary keyed by immutable # copies of canonical graphs to store intermediate results. - data = dict() - result = [] - tl = 1 # The graph is connected and of order at least 2 + cdef dict data = dict() + cdef list result = [] + cdef int tl = 1 # The graph is connected and of order at least 2 + cdef dict certif_inv + cdef dict perm for atom in atoms: From 26079ff80d81d7b42bd9a3dad9adc21882c22c79 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 3 Oct 2021 14:25:06 +0200 Subject: [PATCH 341/355] trac #30998: minor details --- src/sage/graphs/graph_decompositions/tree_decomposition.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index fc5f31eb57b..e2608da8995 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -433,7 +433,7 @@ def _from_tree_decompositions_of_atoms_to_tree_decomposition(T_atoms, cliques): def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): r""" - Computes the tree-width of `g` (and provides a decomposition) + Compute the treewidth of `g` (and provide a decomposition). INPUT: From ac5cbbf0072380022c32466aab95fdfb31c4ecee Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 4 Oct 2021 00:08:28 +0200 Subject: [PATCH 342/355] Trac #29581: remove unicode character --- .../differentiable/characteristic_cohomology_class.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 8ac01c82d8b..e5c80062844 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -1668,7 +1668,7 @@ def get_local(self, cmat): Consider the 2-sphere:: - sage: M.<ϑ,ϕ> = manifolds.Sphere(2) # use spherical coordinates + sage: M. = manifolds.Sphere(2) # use spherical coordinates sage: TM = M.tangent_bundle() sage: g = M.metric() sage: nab = g.connection() @@ -1689,7 +1689,7 @@ def get_local(self, cmat): sage: algorithm = EulerAlgorithm() sage: euler = -algorithm.get_local(gcmat)[0] / sqrt(g.det(frame=e)) sage: euler.display() - 1/2*sin(ϑ)/pi dϑ∧dϕ + 1/2*sin(th)/pi dth∧dphi """ from sage.symbolic.constants import pi From f0bc1b4a447d28cdb8066c4bef99e981593f2799 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 13:13:39 -0700 Subject: [PATCH 343/355] build/pkgs/argcomplete: New --- build/pkgs/argcomplete/SPKG.rst | 18 ++++++++++++++++++ build/pkgs/argcomplete/checksums.ini | 5 +++++ build/pkgs/argcomplete/dependencies | 4 ++++ build/pkgs/argcomplete/install-requires.txt | 1 + build/pkgs/argcomplete/package-version.txt | 1 + build/pkgs/argcomplete/spkg-install.in | 2 ++ build/pkgs/argcomplete/type | 1 + 7 files changed, 32 insertions(+) create mode 100644 build/pkgs/argcomplete/SPKG.rst create mode 100644 build/pkgs/argcomplete/checksums.ini create mode 100644 build/pkgs/argcomplete/dependencies create mode 100644 build/pkgs/argcomplete/install-requires.txt create mode 100644 build/pkgs/argcomplete/package-version.txt create mode 100644 build/pkgs/argcomplete/spkg-install.in create mode 100644 build/pkgs/argcomplete/type diff --git a/build/pkgs/argcomplete/SPKG.rst b/build/pkgs/argcomplete/SPKG.rst new file mode 100644 index 00000000000..4e823cf2f7d --- /dev/null +++ b/build/pkgs/argcomplete/SPKG.rst @@ -0,0 +1,18 @@ +argcomplete: Bash tab completion for argparse +============================================= + +Description +----------- + +Bash tab completion for argparse + +License +------- + +Apache Software License + +Upstream Contact +---------------- + +https://pypi.org/project/argcomplete/ + diff --git a/build/pkgs/argcomplete/checksums.ini b/build/pkgs/argcomplete/checksums.ini new file mode 100644 index 00000000000..6acbb72e9a2 --- /dev/null +++ b/build/pkgs/argcomplete/checksums.ini @@ -0,0 +1,5 @@ +tarball=argcomplete-VERSION.tar.gz +sha1=bd6b35aee6fc44c82d02772b054b5c5ff1bc5983 +md5=ded03f9c5d41c193dfe5869634d78211 +cksum=3352024634 +upstream_url=https://pypi.io/packages/source/a/argcomplete/argcomplete-VERSION.tar.gz diff --git a/build/pkgs/argcomplete/dependencies b/build/pkgs/argcomplete/dependencies new file mode 100644 index 00000000000..0738c2d7777 --- /dev/null +++ b/build/pkgs/argcomplete/dependencies @@ -0,0 +1,4 @@ +$(PYTHON) | $(PYTHON_TOOLCHAIN) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/argcomplete/install-requires.txt b/build/pkgs/argcomplete/install-requires.txt new file mode 100644 index 00000000000..e60624ffee6 --- /dev/null +++ b/build/pkgs/argcomplete/install-requires.txt @@ -0,0 +1 @@ +argcomplete diff --git a/build/pkgs/argcomplete/package-version.txt b/build/pkgs/argcomplete/package-version.txt new file mode 100644 index 00000000000..81f363239f5 --- /dev/null +++ b/build/pkgs/argcomplete/package-version.txt @@ -0,0 +1 @@ +1.12.3 diff --git a/build/pkgs/argcomplete/spkg-install.in b/build/pkgs/argcomplete/spkg-install.in new file mode 100644 index 00000000000..37ac1a53437 --- /dev/null +++ b/build/pkgs/argcomplete/spkg-install.in @@ -0,0 +1,2 @@ +cd src +sdh_pip_install . diff --git a/build/pkgs/argcomplete/type b/build/pkgs/argcomplete/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/argcomplete/type @@ -0,0 +1 @@ +optional From 1c95bac06729b644ff019cee01518a8e0bcd49c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 13:13:59 -0700 Subject: [PATCH 344/355] build/pkgs/ipykernel/dependencies: Add argcomplete and other missing deps --- build/pkgs/ipykernel/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/ipykernel/dependencies b/build/pkgs/ipykernel/dependencies index 45d2d0c0eb9..1b4d1569996 100644 --- a/build/pkgs/ipykernel/dependencies +++ b/build/pkgs/ipykernel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) debugpy matplotlib_inline ipython jupyter_client scandir | $(PYTHON_TOOLCHAIN) +$(PYTHON) ipython_genutils importlib_metadata argcomplete debugpy matplotlib_inline ipython jupyter_client tornado appnope scandir traitlets | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. From b09693dfae08f6844a81aac89f157456105eb630 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 22:15:17 -0700 Subject: [PATCH 345/355] build/pkgs/scandir: Remove --- build/pkgs/ipykernel/dependencies | 2 +- build/pkgs/scandir/SPKG.rst | 18 ------------------ build/pkgs/scandir/checksums.ini | 5 ----- build/pkgs/scandir/dependencies | 5 ----- build/pkgs/scandir/distros/conda.txt | 1 - build/pkgs/scandir/distros/macports.txt | 1 - build/pkgs/scandir/distros/opensuse.txt | 1 - build/pkgs/scandir/distros/repology.txt | 1 - build/pkgs/scandir/install-requires.txt | 1 - build/pkgs/scandir/package-version.txt | 1 - build/pkgs/scandir/spkg-install.in | 1 - build/pkgs/scandir/type | 1 - 12 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 build/pkgs/scandir/SPKG.rst delete mode 100644 build/pkgs/scandir/checksums.ini delete mode 100644 build/pkgs/scandir/dependencies delete mode 100644 build/pkgs/scandir/distros/conda.txt delete mode 100644 build/pkgs/scandir/distros/macports.txt delete mode 100644 build/pkgs/scandir/distros/opensuse.txt delete mode 100644 build/pkgs/scandir/distros/repology.txt delete mode 100644 build/pkgs/scandir/install-requires.txt delete mode 100644 build/pkgs/scandir/package-version.txt delete mode 100644 build/pkgs/scandir/spkg-install.in delete mode 100644 build/pkgs/scandir/type diff --git a/build/pkgs/ipykernel/dependencies b/build/pkgs/ipykernel/dependencies index 1b4d1569996..eec7126f687 100644 --- a/build/pkgs/ipykernel/dependencies +++ b/build/pkgs/ipykernel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ipython_genutils importlib_metadata argcomplete debugpy matplotlib_inline ipython jupyter_client tornado appnope scandir traitlets | $(PYTHON_TOOLCHAIN) +$(PYTHON) ipython_genutils importlib_metadata argcomplete debugpy matplotlib_inline ipython jupyter_client tornado appnope traitlets | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/scandir/SPKG.rst b/build/pkgs/scandir/SPKG.rst deleted file mode 100644 index df729b9205a..00000000000 --- a/build/pkgs/scandir/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -scandir: Fast file system iteration for Python -============================================== - -Description ------------ - -scandir, a better directory iterator and faster os.walk() - -License -------- - -New BSD License - -Upstream Contact ----------------- - -https://pypi.org/project/scandir/ - diff --git a/build/pkgs/scandir/checksums.ini b/build/pkgs/scandir/checksums.ini deleted file mode 100644 index e1e2591b621..00000000000 --- a/build/pkgs/scandir/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=scandir-VERSION.tar.gz -sha1=460c739b514872233c573dded3490718348ec820 -md5=f8378f4d9f95a6a78e97ab01aa900c1d -cksum=855102986 -upstream_url=https://pypi.io/packages/source/s/scandir/scandir-VERSION.tar.gz diff --git a/build/pkgs/scandir/dependencies b/build/pkgs/scandir/dependencies deleted file mode 100644 index 15df0c4d6d8..00000000000 --- a/build/pkgs/scandir/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/scandir/distros/conda.txt b/build/pkgs/scandir/distros/conda.txt deleted file mode 100644 index f649108ecda..00000000000 --- a/build/pkgs/scandir/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -scandir diff --git a/build/pkgs/scandir/distros/macports.txt b/build/pkgs/scandir/distros/macports.txt deleted file mode 100644 index 9cd1875e243..00000000000 --- a/build/pkgs/scandir/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-scandir diff --git a/build/pkgs/scandir/distros/opensuse.txt b/build/pkgs/scandir/distros/opensuse.txt deleted file mode 100644 index d05b4d1319d..00000000000 --- a/build/pkgs/scandir/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-scandir diff --git a/build/pkgs/scandir/distros/repology.txt b/build/pkgs/scandir/distros/repology.txt deleted file mode 100644 index e098979afc8..00000000000 --- a/build/pkgs/scandir/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -python:scandir diff --git a/build/pkgs/scandir/install-requires.txt b/build/pkgs/scandir/install-requires.txt deleted file mode 100644 index 75f24d3b10a..00000000000 --- a/build/pkgs/scandir/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -scandir >=1.9.0 diff --git a/build/pkgs/scandir/package-version.txt b/build/pkgs/scandir/package-version.txt deleted file mode 100644 index 81c871de46b..00000000000 --- a/build/pkgs/scandir/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.10.0 diff --git a/build/pkgs/scandir/spkg-install.in b/build/pkgs/scandir/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/scandir/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/scandir/type b/build/pkgs/scandir/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/scandir/type +++ /dev/null @@ -1 +0,0 @@ -standard From 78b36f70abcb4bafdaf9b857ffb325c9cc4220a3 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 5 Oct 2021 23:16:52 +0200 Subject: [PATCH 346/355] trac #32539: other solution to get the objective value --- src/sage/graphs/generic_graph.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 40ad276d9ae..fcf78e8f113 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8813,7 +8813,8 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, from sage.numerical.mip import MixedIntegerLinearProgram g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) - flow = p.new_variable(nonnegative=True) + flow = p.new_variable(integer=integer, nonnegative=True) + obj = p.new_variable(nonnegative=True) if g.is_directed(): # This function return the balance of flow at X @@ -8837,7 +8838,8 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, capacity_sum = lambda u,v: flow[u,v] + flow[v,u] # Maximizes the flow leaving x - p.set_objective(flow_sum(x)) + p.add_constraint(flow_sum(x) == obj[0]) + p.set_objective(obj[0]) # Elsewhere, the flow is equal to 0 for v in g: @@ -8854,23 +8856,16 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, if v!=x and v!=y: p.add_constraint(flow_leaving(v), max=1) - if integer: - p.set_integer(flow) - p.solve(log=verbose) # If integer is True, flow variables will be converted to integers. # Otherwise, the base ring of the MILP solver is used flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) - if g.is_directed(): - obj = sum(flow[x, v] for u, v in g.outgoing_edge_iterator([x], labels=False)) - obj -= sum(flow[u, x] for u, v in g.incoming_edge_iterator([x], labels=False)) + if integer or (not integer and use_edge_labels is False): + obj = p.get_values(obj[0], convert=ZZ, tolerance=integrality_tolerance) else: - obj = sum(flow[x, v] - flow[v, x] for v in g[x]) - - if not integer and use_edge_labels is False: - obj = Integer(obj) + obj = p.get_values(obj[0], convert=True, tolerance=integrality_tolerance) if value_only: return obj From 9e980fd499226e62c73f4d36eca372d4b7b4fee1 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 5 Oct 2021 23:20:59 +0200 Subject: [PATCH 347/355] trac #32539: further cleaning --- src/sage/graphs/generic_graph.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index fcf78e8f113..f455bfc7e32 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8753,11 +8753,14 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, from sage.rings.real_mpfr import RR if integer: from math import floor - capacity=lambda x: floor(x) if x in RR else 1 + def capacity(z): + return floor(z) if z in RR else 1 else: - capacity=lambda x: x if x in RR else 1 + def capacity(z): + return z if z in RR else 1 else: - capacity=lambda x: 1 + def capacity(z): + return 1 if algorithm is None: if vertex_bound: @@ -8843,7 +8846,7 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, # Elsewhere, the flow is equal to 0 for v in g: - if v!=x and v!=y: + if v != x and v != y: p.add_constraint(flow_sum(v), min=0, max=0) # Capacity constraints @@ -8853,7 +8856,7 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, # No vertex except the sources can send more than 1 if vertex_bound: for v in g: - if v!=x and v!=y: + if v != x and v != y: p.add_constraint(flow_leaving(v), max=1) p.solve(log=verbose) From 7bf6a01b1693fbe5045c5b52a0ce1a76ad49642b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 5 Oct 2021 23:23:43 +0200 Subject: [PATCH 348/355] trac #32539: better management of obj --- src/sage/graphs/generic_graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f455bfc7e32..2ecb9937005 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8817,7 +8817,7 @@ def capacity(z): g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) flow = p.new_variable(integer=integer, nonnegative=True) - obj = p.new_variable(nonnegative=True) + obj = p.new_variable(integer=integer, nonnegative=True) if g.is_directed(): # This function return the balance of flow at X @@ -8865,7 +8865,7 @@ def capacity(z): # Otherwise, the base ring of the MILP solver is used flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) - if integer or (not integer and use_edge_labels is False): + if not integer and use_edge_labels is False: obj = p.get_values(obj[0], convert=ZZ, tolerance=integrality_tolerance) else: obj = p.get_values(obj[0], convert=True, tolerance=integrality_tolerance) From 5cc1288bec7a4c165723f8fd20d14843547faccc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 21:16:52 -0700 Subject: [PATCH 349/355] src/sage/matrix/matrix_gfpn_dense.pyx: Add reference to meataxe spkg --- src/sage/matrix/matrix_gfpn_dense.pyx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index c33e987ac21..32b77a861fa 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -5,8 +5,7 @@ r""" Dense Matrices over `\mathbb F_q`, with `q<255`. -This module is a wrapper for version 2.4.24 of the Aachen -`C-MeatAxe `_, +This module is a wrapper for the `Aachen C-MeatAxe library <../spkg/meataxe.html>`_, improved by an implementation of the Winograd-Strassen multiplication algorithm. It provides matrices over the finite field `\mathbb F_q`, where `q\le 255`. @@ -15,6 +14,11 @@ By default, it is only used when `q` is odd and not prime, because other matrix implementations in SageMath perform better for prime fields or in characteristic two. +.. NOTE:: + + The examples shown here will only work when the `meataxe + <../spkg/meataxe.html>` package has been installed. + AUTHORS: - Simon King (2015-09): initial version From 6b729bc9426c65b2d76269b57a2839a65139b5c2 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 6 Oct 2021 11:06:05 -0400 Subject: [PATCH 350/355] renamed to_polynomial into polynomial, removed differentiation_operator --- src/sage/modular/quasimodform/element.py | 8 +++-- src/sage/modular/quasimodform/ring.py | 38 ------------------------ 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 38d0e0c6e86..cbc80e7024b 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -342,7 +342,7 @@ def is_modular_form(self): """ return self._polynomial.degree() <= 0 and self._polynomial[0].is_modular_form() - def to_polynomial(self, names='E2, E4, E6'): + def polynomial(self, names='E2, E4, E6'): r""" Return a multivariate polynomial `P(E_2, E_4, E_6)` corresponding to the given form where `E_2`, `E_4` and `E_6` are the generators of the @@ -360,9 +360,9 @@ def to_polynomial(self, names='E2, E4, E6'): EXAMPLES:: sage: QM = QuasiModularForms(1) - sage: (QM.0 + QM.1).to_polynomial() + sage: (QM.0 + QM.1).polynomial() E4 + E2 - sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).to_polynomial() + sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial() E2*E6 + 2*E4^2 + E2 + 1/2 """ P = self.parent().polynomial_ring(names) @@ -370,6 +370,8 @@ def to_polynomial(self, names='E2, E4, E6'): E2, E4, E6 = P.gens() return sum(f.to_polynomial().subs({g0:E4, g1:E6}) * E2 ** exp for exp, f in enumerate(self._polynomial.coefficients(sparse=False))) + to_polynomial = polynomial # alias + def weights_list(self): r""" Return the list of the weights of all the graded components of the given diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 8845d090765..5fbcb7e62ec 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -569,41 +569,3 @@ def from_polynomial(self, polynomial): raise ValueError("the number of variables (%s) of the given polynomial cannot exceed the number of generators (%s) of the quasimodular forms ring" % (nb_var, self.ngens())) gens_dict = {poly_parent.gen(i):self.gen(i) for i in range(0, nb_var)} return self(polynomial.subs(gens_dict)) - - def differentiation_operator(self, f): - r""" - Compute the formal derivative `q\frac{d}{dq}` of the q-expansion of a - quasimodular form `f` - - INPUT: - - - ``f`` -- a power serie in corresponding to the q-expansion of a - quasimodular form. - - OUTPUT: - - The power series `q\frac{d}{dq}(f)` - - EXAMPLES:: - - sage: M = QuasiModularForms() - sage: D = M.differentiation_operator - sage: B = M.gens() - sage: P = B[0]; Q = B[1]; R = B[2] - sage: D(P) - -24*q - 144*q^2 - 288*q^3 - 672*q^4 - 720*q^5 + O(q^6) - sage: (P.q_expansion()^2 - Q.q_expansion())/12 - -24*q - 144*q^2 - 288*q^3 - 672*q^4 - 720*q^5 + O(q^6) - sage: D(Q) - 240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6) - sage: (P.q_expansion()*Q.q_expansion() - R.q_expansion())/3 - 240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6) - sage: D(R) - -504*q - 33264*q^2 - 368928*q^3 - 2130912*q^4 - 7877520*q^5 + O(q^6) - sage: (P.q_expansion()*R.q_expansion() - Q.q_expansion()^2)/2 - -504*q - 33264*q^2 - 368928*q^3 - 2130912*q^4 - 7877520*q^5 + O(q^6) - - TODO:: This method need some work. It should return a QuasiModularFormsElement (not a power series in q) - """ - q = f.q_expansion().parent().gen() - return q*f.q_expansion().derivative() From 7a4ed0d6dddaeab25d51d74096d288297e2be6e1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 17:41:30 -0700 Subject: [PATCH 351/355] src/sage/interfaces/maxima_lib.py: Re-indent lisp code --- src/sage/interfaces/maxima_lib.py | 36 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 6b911df28d3..12005b269e8 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -129,26 +129,24 @@ (setq msg (mapcar #'(lambda (x) (if (eq x '| |) " " x)) msg)) (or (eq flag 'noprint) (setq print? t)) (error - (concatenate 'string "Maxima asks: " + (concatenate 'string + "Maxima asks: " (string-trim '(#\Newline) - (with-output-to-string (*standard-output*) - (cond ((not print?) - (setq print? t) - (format-prompt t "")) - ((null msg) - (format-prompt t "")) - ((atom msg) - (format-prompt t "~A" msg) - (mterpri)) - ((eq flag t) - (format-prompt t "~{~A~}" (cdr msg)) - (mterpri)) - (t - (format-prompt t "~M" msg) - (mterpri)) - )))) - ) -) + (with-output-to-string (*standard-output*) + (cond ((not print?) + (setq print? t) + (format-prompt t "")) + ((null msg) + (format-prompt t "")) + ((atom msg) + (format-prompt t "~A" msg) + (mterpri)) + ((eq flag t) + (format-prompt t "~{~A~}" (cdr msg)) + (mterpri)) + (t + (format-prompt t "~M" msg) + (mterpri)))))))) """) ## Redirection of ECL and Maxima stdout to /dev/null From a842fc0d159d9a183f60a6795836a7693ee11a65 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 17:50:10 -0700 Subject: [PATCH 352/355] build/pkgs/maxima: Bump patch level --- build/pkgs/maxima/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/maxima/package-version.txt b/build/pkgs/maxima/package-version.txt index 5a053acd6b8..83476624dc0 100644 --- a/build/pkgs/maxima/package-version.txt +++ b/build/pkgs/maxima/package-version.txt @@ -1 +1 @@ -5.45.0 +5.45.0.p0 From 016f0229a5b03637b33baee5909d53f2fdd1c53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 7 Oct 2021 10:10:48 +0200 Subject: [PATCH 353/355] 31378: removing trailing whitespaces in morphism.py --- src/sage/combinat/words/morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 746dbb2a97f..5e346d7806f 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1818,7 +1818,7 @@ def fixed_point(self, letter): parent = self.codomain() if self.is_growing(letter): from sage.combinat.words.word import InfiniteWord_morphic - return InfiniteWord_morphic(parent.shift(), self, letter, + return InfiniteWord_morphic(parent.shift(), self, letter, coding=None, length=Infinity) else: from sage.combinat.words.word import FiniteWord_morphic @@ -1827,7 +1827,7 @@ def fixed_point(self, letter): # since FiniteWord_morphic uses the method __getitem__ # from FiniteWord_callable, the length must be precomputed # for __getitem__ to work properly - w.length() + w.length() return w def fixed_points(self): From 275f5b9b0507e1dd9c9cfd83d18b730e22823544 Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Sat, 9 Oct 2021 11:14:15 -0600 Subject: [PATCH 354/355] trac 29400 add doctest --- src/sage/symbolic/expression.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index de4720f90a7..09039723266 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -8558,6 +8558,11 @@ cdef class Expression(CommutativeRingElement): sage: (I^m).imag_part() sin(1/2*pi*m) sage: forget() + + Check that :trac:`29400` is fixed:: + + sage: cot(1 + i).imag().n() - (1/tan(1 + i)).imag().n() # abs tol 10^-12 + 0.00000000000000 """ return new_Expression_from_GEx(self._parent, g_hold_wrapper(g_real_part, self._gobj, hold)) From c896669b1f2303da42e33bbb50d664bd16c7124c Mon Sep 17 00:00:00 2001 From: Release Manager Date: Mon, 11 Oct 2021 23:13:18 +0200 Subject: [PATCH 355/355] Updated SageMath version to 9.5.beta3 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sagelib/package-version.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 51e1992f633..035015bacf5 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.5.beta2", - "version": "9.5.beta2", + "title": "sagemath/sage: 9.5.beta3", + "version": "9.5.beta3", "upload_type": "software", - "publication_date": "2021-09-26", + "publication_date": "2021-10-11", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.5.beta2", + "identifier": "https://github.com/sagemath/sage/tree/9.5.beta3", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 85f52b22a59..88f7d68ebc9 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.5.beta2, Release Date: 2021-09-26 +SageMath version 9.5.beta3, Release Date: 2021-10-11 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 2369e44aec4..95ba9591301 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=3d447d16ccee7d1f5a9ebaea31153f98bd1cffa0 -md5=6a9015ec510b88f92645f308c2544919 -cksum=801814561 +sha1=9c45053634b6912dd4e4e68a483b5dbd483fc47d +md5=11496f4636f7c19bb4cfbaf6e57af698 +cksum=2205302326 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index ff997c28754..42d10d82fec 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -2f1dfaa56b98e1e2d9dcf9e048bc6bc302964159 +32c0d4075fb515a073925ad1feefcc4fc349b47d diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index bc12a7eeb60..173833eaf87 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.5.beta2 +9.5.beta3 diff --git a/src/VERSION.txt b/src/VERSION.txt index bc12a7eeb60..173833eaf87 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.5.beta2 +9.5.beta3 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 46acf9862a7..750e10d31e0 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.5.beta2' -SAGE_RELEASE_DATE='2021-09-26' -SAGE_VERSION_BANNER='SageMath version 9.5.beta2, Release Date: 2021-09-26' +SAGE_VERSION='9.5.beta3' +SAGE_RELEASE_DATE='2021-10-11' +SAGE_VERSION_BANNER='SageMath version 9.5.beta3, Release Date: 2021-10-11' diff --git a/src/sage/version.py b/src/sage/version.py index bf1bc3b976e..e9950f06043 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 = '9.5.beta2' -date = '2021-09-26' -banner = 'SageMath version 9.5.beta2, Release Date: 2021-09-26' +version = '9.5.beta3' +date = '2021-10-11' +banner = 'SageMath version 9.5.beta3, Release Date: 2021-10-11'