From 2aef68d521da520c7e9026ef362a6318d8f2f68d Mon Sep 17 00:00:00 2001 From: Jeremy Martin Date: Thu, 2 Jun 2016 17:11:12 +0200 Subject: [PATCH 001/218] Added cone_vertices, decone, is_balanced, is_partitionable, intersection methods to SimplicialComplex class --- src/sage/homology/simplicial_complex.py | 193 ++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 67b4b4fc674..729d66c4c3c 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -23,6 +23,9 @@ - Simon King (2014-05-02): Let simplicial complexes be objects of the category of simplicial complexes. +- Jeremy Martin (2016-06-02): added cone_vertices, decone, is_balanced, + is_partitionable, intersection methods + This module implements the basic structure of finite simplicial complexes. Given a set `V` of "vertices", a simplicial complex on `V` is a collection `K` of subsets of `V` satisfying the condition that if @@ -3845,6 +3848,196 @@ def is_immutable(self): """ return not self._is_mutable + def cone_vertices(self): + r""" + Return the list of cone vertices of ``self``. + + A vertex is a cone vertex iff it appears in every facet. + + EXAMPLES:: + + sage: SimplicialComplex([[1,2,3]]).cone_vertices() + [1, 2, 3] + sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).cone_vertices() + [1] + sage: SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]).cone_vertices() + [] + """ + F = self.facets() + C = set(self.vertices()) + for f in F: + C = C.intersection(list(f)) + if not C: + break + return sorted(list(C)) + + def decone(self): + r""" + Return the subcomplex of ``self`` induced by the non-cone vertices. + + EXAMPLES:: + + sage: SimplicialComplex([[1,2,3]]).decone() + Simplicial complex with vertex set () and facets {()} + sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).decone() + Simplicial complex with vertex set (2, 3, 4, 5, 6) and facets {(3, 4), (2, 3), (5, 6)} + sage: X = SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]) + sage: X.decone()==X + True + """ + V = set(self.vertices()).difference(self.cone_vertices()) + return self.generated_subcomplex(V) + + def is_balanced(self, check_purity=False, certificate=False): + r""" + Determines whether ``self`` is balanced. + + A simplicial complex `X` of dimension `d-1` is balanced iff its vertices + can be colored with `d` colors such that every face contains at most one + vertex of each color. An equivalent condition is that the 1-skeleton of + `X` is `d`-colorable. In some contexts, it is also required that `X` be + pure (i.e., that all maximal faces of `X` have the same dimension). + + INPUT: + + - ``check_purity`` -- (default: False) if this is True, require that + ``self`` be pure as well as balanced + + - ``certificate`` -- (default: False) if this is True and ``self`` is + balanced, then return a `d`-coloring of the 1-skeleton. + + EXAMPLES:: + + # A 1-dim simplicial complex is balanced iff it is bipartite + sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,5]]) + sage: X.is_balanced() + True + sage: X.is_balanced(certificate=True) + [[2, 4], [1, 3, 5]] + sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,4]]) + sage: X.is_balanced() + False + + # Any barycentric division is balanced + sage: X = SimplicialComplex([[1,2,3],[1,2,4],[2,3,4]]) + sage: X.is_balanced() + False + sage: X.barycentric_subdivision().is_balanced() + True + + # A non-pure balanced complex + sage: X=SimplicialComplex([[1,2,3],[3,4]]) + sage: X.is_balanced(check_purity=True) + False + sage: X.is_balanced(certificate=True) + [[2], [1, 4], [3]] + """ + d = 1+self.dimension() + if check_purity and not self.is_pure(): + return False + Skel = self.graph() + if certificate: + C = Skel.coloring() + C = C if len(C)==d else False + return C + else: + ch = Skel.chromatic_number() + return ch==d + + def is_partitionable(self, certificate=False): + r""" + Determines whether ``self`` is partitionable. + + A partitioning of a simplicial complex `X` is a decomposition of its face + poset into disjoint Boolean intervals `[R,F]`, where `F` ranges over all + facets of `X`. + + The method sets up an integer program with + - a variable `y_i` for each pair `(R,F)`, where `F` is a facet of `X` + and `R` is a subface of `F` + - a constraint `y_i+y_j \leq 1` for each pair `(R_i,F_i)`, `(R_j,F_j)` + whose Boolean intervals intersect nontrivially (equivalent to + `(R_i\subseteq F_j and R_j\subseteq F_i))` + - objective function equal to the sum of all `y_i` + + INPUT: + + - ``certificate`` -- (default: False) If True, and ``self`` is + partitionable, then return a list of pairs `(R,F)` that form + a partitioning. + + EXAMPLES:: + + # Simplices are trivially partitionable + sage: X = SimplicialComplex([ [1,2,3,4] ]) + sage: X.is_partitionable() + True + sage: X.is_partitionable(certificate=True) + [((), (1, 2, 3, 4), 4)] + + # Shellable complexes are partitionable + sage: X = SimplicialComplex([ [1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5] ]) + sage: X.is_partitionable() + True + sage: P = X.is_partitionable(certificate=True) + sage: n_intervals_containing = lambda f: len([ RF for RF in P if RF[0].is_face(f) and f.is_face(RF[1]) ]) + sage: all( n_intervals_containing(f)==1 for k in X.faces().keys() for f in X.faces()[k] ) + True + + # A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Björner + sage: X = SimplicialComplex([ [1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,5,6] ]) + sage: X.is_partitionable() + True + + # The bowtie complex is not partitionable + sage: X = SimplicialComplex([ [1,2,3],[1,4,5] ]) + sage: X.is_partitionable() + False + """ + from sage.numerical.mip import MixedIntegerLinearProgram + Facets = self.facets() + RFPairs = [(Simplex(r),f,f.dimension()-len(r)+1) for f in self.facets() for r in Set(f).subsets()] + n = len(RFPairs) + IP = MixedIntegerLinearProgram() + y = IP.new_variable(binary=True) + for i0,pair0 in enumerate(RFPairs): + for i1,pair1 in enumerate(RFPairs): + if i0 Date: Thu, 27 Apr 2017 15:43:25 +0200 Subject: [PATCH 002/218] fix headers --- src/sage/ext/mod_int.pxd | 2 +- src/sage/geometry/triangulation/data.h | 4 ++-- src/sage/geometry/triangulation/data.pxd | 2 +- src/sage/geometry/triangulation/functions.pxd | 2 +- src/sage/geometry/triangulation/triangulations.pxd | 2 +- src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd | 2 +- src/sage/libs/coxeter3/coxeter.pxd | 2 +- src/sage/libs/lcalc/lcalc_Lfunction.pxd | 2 +- src/sage/libs/ntl/GF2.pxd | 2 +- src/sage/libs/ntl/GF2E.pxd | 2 +- src/sage/libs/ntl/GF2EX.pxd | 2 +- src/sage/libs/ntl/GF2X.pxd | 2 +- src/sage/libs/ntl/ZZ.pxd | 2 +- src/sage/libs/ntl/ZZX.pxd | 2 +- src/sage/libs/ntl/ZZ_p.pxd | 2 +- src/sage/libs/ntl/ZZ_pE.pxd | 2 +- src/sage/libs/ntl/ZZ_pEX.pxd | 2 +- src/sage/libs/ntl/ZZ_pX.pxd | 2 +- src/sage/libs/ntl/lzz_p.pxd | 2 +- src/sage/libs/ntl/lzz_pX.pxd | 2 +- src/sage/libs/ntl/mat_GF2.pxd | 2 +- src/sage/libs/ntl/mat_GF2E.pxd | 2 +- src/sage/libs/ntl/mat_ZZ.pxd | 2 +- src/sage/libs/ntl/ntlwrap.cpp | 3 +++ src/sage/libs/ntl/types.pxd | 2 +- src/sage/libs/ntl/vec_GF2.pxd | 2 +- src/sage/libs/polybori/decl.pxd | 2 +- src/sage/libs/pynac/pynac.pxd | 2 +- src/sage/libs/pynac/{wrap.h => pynac_wrap.h} | 5 +++++ src/sage/misc/cython_metaclass.pxd | 2 +- .../rings/finite_rings/{stdint.h => integer_mod_limits.h} | 3 +++ src/sage/rings/finite_rings/stdint.pxd | 6 ++---- src/sage/sat/solvers/cryptominisat/solverconf.pxd | 2 +- 33 files changed, 43 insertions(+), 34 deletions(-) rename src/sage/libs/pynac/{wrap.h => pynac_wrap.h} (96%) rename src/sage/rings/finite_rings/{stdint.h => integer_mod_limits.h} (66%) diff --git a/src/sage/ext/mod_int.pxd b/src/sage/ext/mod_int.pxd index 763fa69f068..f2ef6fe5527 100644 --- a/src/sage/ext/mod_int.pxd +++ b/src/sage/ext/mod_int.pxd @@ -17,7 +17,7 @@ The `mod_int` Data Type #***************************************************************************** -cdef extern from "sage/ext/mod_int.h": +cdef extern from "mod_int.h": ctypedef long mod_int mod_int MOD_INT_MAX mod_int MOD_INT_OVERFLOW diff --git a/src/sage/geometry/triangulation/data.h b/src/sage/geometry/triangulation/data.h index 246ae48ceea..3e18c9d00a7 100644 --- a/src/sage/geometry/triangulation/data.h +++ b/src/sage/geometry/triangulation/data.h @@ -1,5 +1,5 @@ -#ifndef __DATA_H__ -#define __DATA_H__ +#ifndef __TRIANGULATION_DATA_H__ +#define __TRIANGULATION_DATA_H__ #include #include diff --git a/src/sage/geometry/triangulation/data.pxd b/src/sage/geometry/triangulation/data.pxd index eeac175a259..779c77f0a8d 100644 --- a/src/sage/geometry/triangulation/data.pxd +++ b/src/sage/geometry/triangulation/data.pxd @@ -1,3 +1,3 @@ -cdef extern from "sage/geometry/triangulation/data.h": +cdef extern from "data.h": cdef cppclass compact_simplices(object): void push_back(int encoded_simplex) diff --git a/src/sage/geometry/triangulation/functions.pxd b/src/sage/geometry/triangulation/functions.pxd index 3088e757dfd..fa981e5215b 100644 --- a/src/sage/geometry/triangulation/functions.pxd +++ b/src/sage/geometry/triangulation/functions.pxd @@ -1,3 +1,3 @@ -cdef extern from "sage/geometry/triangulation/functions.h": +cdef extern from "functions.h": int factorial(int n) int binomial(int n, int D) diff --git a/src/sage/geometry/triangulation/triangulations.pxd b/src/sage/geometry/triangulation/triangulations.pxd index 057b8226ec3..0111fb0dd5f 100644 --- a/src/sage/geometry/triangulation/triangulations.pxd +++ b/src/sage/geometry/triangulation/triangulations.pxd @@ -1,4 +1,4 @@ -cdef extern from "sage/geometry/triangulation/triangulations.h": +cdef extern from "triangulations.h": ctypedef void* triangulations_ptr cdef triangulations_ptr init_triangulations \ (int n, int d, int star, bint fine, object seed, object flips) diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd index 7f6ac82c1e6..e9c99789df1 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd @@ -10,7 +10,7 @@ from sage.groups.perm_gps.partn_ref.data_structures cimport OrbitPartition, PartitionStack from sage.libs.gap.element cimport GapElement, GapElement_Permutation -cdef extern from "sage/groups/perm_gps/partn_ref2/refinement_generic.h": +cdef extern from "refinement_generic.h": cdef long *global_refine_vals_array cdef int my_comp_func(void *a, void *b) cdef int BACKTRACK_WITHLATEX_DEBUG diff --git a/src/sage/libs/coxeter3/coxeter.pxd b/src/sage/libs/coxeter3/coxeter.pxd index a234ab78e53..cffa2505e39 100644 --- a/src/sage/libs/coxeter3/coxeter.pxd +++ b/src/sage/libs/coxeter3/coxeter.pxd @@ -6,7 +6,7 @@ #***************************************************************************** from sage.structure.sage_object cimport SageObject -include "decl.pxd" +from .decl cimport * cdef class String: cdef c_String x diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pxd b/src/sage/libs/lcalc/lcalc_Lfunction.pxd index c9f5a9241cd..56224a1bc36 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pxd +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pxd @@ -1,4 +1,4 @@ -cdef extern from "sage/libs/lcalc/lcalc_sage.h": +cdef extern from "lcalc_sage.h": ctypedef struct doublevec "std::vector": int (*size)() diff --git a/src/sage/libs/ntl/GF2.pxd b/src/sage/libs/ntl/GF2.pxd index e4e1757bb91..72402b400d1 100644 --- a/src/sage/libs/ntl/GF2.pxd +++ b/src/sage/libs/ntl/GF2.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void GF2_from_str "_from_str"(GF2_c* dest, char* s) object GF2_to_PyString "_to_PyString"(GF2_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": int GF2_IsOne "IsOne"(GF2_c x) int GF2_IsZero "IsZero"(GF2_c x) diff --git a/src/sage/libs/ntl/GF2E.pxd b/src/sage/libs/ntl/GF2E.pxd index 443439ecb20..b1253a27012 100644 --- a/src/sage/libs/ntl/GF2E.pxd +++ b/src/sage/libs/ntl/GF2E.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void GF2E_from_str "_from_str"(GF2E_c* dest, char* s) object GF2E_to_PyString "_to_PyString"(GF2E_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void GF2E_init "GF2E::init"(GF2X_c x) long GF2E_degree "GF2E::degree"() GF2XModulus_c GF2E_modulus "GF2E::modulus"() diff --git a/src/sage/libs/ntl/GF2EX.pxd b/src/sage/libs/ntl/GF2EX.pxd index f4a66485c57..fd2b32b977d 100644 --- a/src/sage/libs/ntl/GF2EX.pxd +++ b/src/sage/libs/ntl/GF2EX.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void GF2EX_from_str "_from_str"(GF2EX_c* dest, char* s) object GF2EX_to_PyString "_to_PyString"(GF2EX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void GF2EX_add "add"( GF2EX_c x, GF2EX_c a, GF2EX_c b) void GF2EX_sub "sub"( GF2EX_c x, GF2EX_c a, GF2EX_c b) void GF2EX_mul "mul"( GF2EX_c x, GF2EX_c a, GF2EX_c b) diff --git a/src/sage/libs/ntl/GF2X.pxd b/src/sage/libs/ntl/GF2X.pxd index a1930acc158..0eec3b33b24 100644 --- a/src/sage/libs/ntl/GF2X.pxd +++ b/src/sage/libs/ntl/GF2X.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void GF2X_from_str "_from_str"(GF2X_c* dest, char* s) object GF2X_to_PyString "_to_PyString"(GF2X_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long *GF2XHexOutput_c "(&GF2X::HexOutput)" # work-around for Cython bug int GF2X_IsOne "IsOne"(GF2X_c x) diff --git a/src/sage/libs/ntl/ZZ.pxd b/src/sage/libs/ntl/ZZ.pxd index 618c6f26214..b4078222236 100644 --- a/src/sage/libs/ntl/ZZ.pxd +++ b/src/sage/libs/ntl/ZZ.pxd @@ -6,7 +6,7 @@ cdef extern from "ccobject.h": void ZZ_from_str "_from_str"(ZZ_c* dest, char* s) object ZZ_to_PyString "_to_PyString"(ZZ_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void ZZ_conv_from_int "conv"(ZZ_c x, int i) void ZZ_conv_to_int "conv"(int i, ZZ_c x) void ZZ_conv_from_long "conv"(ZZ_c x, long l) diff --git a/src/sage/libs/ntl/ZZX.pxd b/src/sage/libs/ntl/ZZX.pxd index 9d83a7d2f10..76961fc6e70 100644 --- a/src/sage/libs/ntl/ZZX.pxd +++ b/src/sage/libs/ntl/ZZX.pxd @@ -8,7 +8,7 @@ cdef extern from "ccobject.h": void ZZX_from_str "_from_str"(ZZX_c* dest, char* s) object ZZX_to_PyString "_to_PyString"(ZZX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": ctypedef struct pair_ZZX_long_c "pair_ZZX_long": ZZX_c a long b diff --git a/src/sage/libs/ntl/ZZ_p.pxd b/src/sage/libs/ntl/ZZ_p.pxd index 8b66c7bd673..85e4f0eb2e8 100644 --- a/src/sage/libs/ntl/ZZ_p.pxd +++ b/src/sage/libs/ntl/ZZ_p.pxd @@ -6,7 +6,7 @@ cdef extern from "ccobject.h": void ZZ_p_from_str "_from_str"(ZZ_p_c* dest, char* s) object ZZ_p_to_PyString "_to_PyString"(ZZ_p_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": char* ZZ_p_to_str(ZZ_p_c* x) void ZZ_p_add "add"( ZZ_p_c x, ZZ_p_c a, ZZ_p_c b) void ZZ_p_sub "sub"( ZZ_p_c x, ZZ_p_c a, ZZ_p_c b) diff --git a/src/sage/libs/ntl/ZZ_pE.pxd b/src/sage/libs/ntl/ZZ_pE.pxd index 26018eb1ffa..1da7f80f4a5 100644 --- a/src/sage/libs/ntl/ZZ_pE.pxd +++ b/src/sage/libs/ntl/ZZ_pE.pxd @@ -6,7 +6,7 @@ cdef extern from "ccobject.h": void ZZ_pE_from_str "_from_str"(ZZ_pE_c* dest, char* s) object ZZ_pE_to_PyString "_to_PyString"(ZZ_pE_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void ZZ_pE_add "add"( ZZ_pE_c x, ZZ_pE_c a, ZZ_pE_c b) void ZZ_pE_add_long "add"( ZZ_pE_c x, ZZ_pE_c a, long b) void ZZ_pE_add_ZZ_p "add"( ZZ_pE_c x, ZZ_pE_c a, ZZ_p_c b) diff --git a/src/sage/libs/ntl/ZZ_pEX.pxd b/src/sage/libs/ntl/ZZ_pEX.pxd index c68ebe87ea0..aadd6dc8b93 100644 --- a/src/sage/libs/ntl/ZZ_pEX.pxd +++ b/src/sage/libs/ntl/ZZ_pEX.pxd @@ -7,7 +7,7 @@ cdef extern from "ccobject.h": void ZZ_pEX_from_str "_from_str"(ZZ_pEX_c* dest, char* s) object ZZ_pEX_to_PyString "_to_PyString"(ZZ_pEX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long ZZ_pEX_IsZero "IsZero"(ZZ_pEX_c a) long ZZ_pEX_IsOne "IsOne"(ZZ_pEX_c a) diff --git a/src/sage/libs/ntl/ZZ_pX.pxd b/src/sage/libs/ntl/ZZ_pX.pxd index 2e43f9a524f..4cd37e59a87 100644 --- a/src/sage/libs/ntl/ZZ_pX.pxd +++ b/src/sage/libs/ntl/ZZ_pX.pxd @@ -7,7 +7,7 @@ cdef extern from "ccobject.h": void ZZ_pX_from_str "_from_str"(ZZ_pX_c* dest, char* s) object ZZ_pX_to_PyString "_to_PyString"(ZZ_pX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long ZZ_pX_IsZero "IsZero"(ZZ_pX_c a) long ZZ_pX_IsOne "IsOne"(ZZ_pX_c a) diff --git a/src/sage/libs/ntl/lzz_p.pxd b/src/sage/libs/ntl/lzz_p.pxd index e8db69d3a32..aadea27231d 100644 --- a/src/sage/libs/ntl/lzz_p.pxd +++ b/src/sage/libs/ntl/lzz_p.pxd @@ -2,7 +2,7 @@ from .types cimport zz_p_c -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long zz_p_rep "rep"(zz_p_c x) long zz_p_isZero "IsZero"(zz_p_c x) void zz_p_add "add"(zz_p_c x, zz_p_c a, zz_p_c b) diff --git a/src/sage/libs/ntl/lzz_pX.pxd b/src/sage/libs/ntl/lzz_pX.pxd index afe3c7f3e18..c894823ca4d 100644 --- a/src/sage/libs/ntl/lzz_pX.pxd +++ b/src/sage/libs/ntl/lzz_pX.pxd @@ -5,7 +5,7 @@ from .types cimport ZZ_c, zz_p_c, zz_pX_c, zz_pX_Modulus_c cdef extern from "ccobject.h": void zz_pX_Modulus_from_str "_from_str"(zz_pX_Modulus_c* dest, char* s) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": char* zz_pX_repr(zz_pX_c* x) void zz_pX_SetCoeff_long "SetCoeff"(zz_pX_c x, long i, long a) zz_p_c zz_pX_GetCoeff "coeff"(zz_pX_c x, long i) diff --git a/src/sage/libs/ntl/mat_GF2.pxd b/src/sage/libs/ntl/mat_GF2.pxd index 182887963d4..920ea60a977 100644 --- a/src/sage/libs/ntl/mat_GF2.pxd +++ b/src/sage/libs/ntl/mat_GF2.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void mat_GF2_from_str "_from_str"(mat_GF2_c* dest, char* s) object mat_GF2_to_PyString "_to_PyString"(mat_GF2_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_GF2_add "add"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) void mat_GF2_sub "sub"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) void mat_GF2_mul "mul"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) diff --git a/src/sage/libs/ntl/mat_GF2E.pxd b/src/sage/libs/ntl/mat_GF2E.pxd index ade3dd11f25..a59de25e0e2 100644 --- a/src/sage/libs/ntl/mat_GF2E.pxd +++ b/src/sage/libs/ntl/mat_GF2E.pxd @@ -4,7 +4,7 @@ cdef extern from "ccobject.h": void mat_GF2E_from_str "_from_str"(mat_GF2E_c* dest, char* s) object mat_GF2E_to_PyString "_to_PyString"(mat_GF2E_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_GF2E_add "add"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) void mat_GF2E_sub "sub"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) void mat_GF2E_mul "mul"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) diff --git a/src/sage/libs/ntl/mat_ZZ.pxd b/src/sage/libs/ntl/mat_ZZ.pxd index b86929ab547..fe3b1703036 100644 --- a/src/sage/libs/ntl/mat_ZZ.pxd +++ b/src/sage/libs/ntl/mat_ZZ.pxd @@ -3,7 +3,7 @@ from .types cimport mat_ZZ_c, ZZ_c, ZZX_c cdef extern from "ccobject.h": object mat_ZZ_to_PyString "_to_PyString"(mat_ZZ_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_ZZ_mul "mul"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) void mat_ZZ_add "add"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) void mat_ZZ_sub "sub"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) diff --git a/src/sage/libs/ntl/ntlwrap.cpp b/src/sage/libs/ntl/ntlwrap.cpp index 0ad51983f59..38c9cfebf6c 100644 --- a/src/sage/libs/ntl/ntlwrap.cpp +++ b/src/sage/libs/ntl/ntlwrap.cpp @@ -1,3 +1,5 @@ +#ifndef _SAGE_NTLWRAP_CPP +#define _SAGE_NTLWRAP_CPP #include "ntlwrap.h" #ifdef __cplusplus @@ -832,3 +834,4 @@ static void ZZ_pX_InvMod_newton_ram(struct ZZ_pX &x, const struct ZZ_pX &a, cons } #endif /* #ifdef __cplusplus */ +#endif /* #ifndef _SAGE_NTLWRAP_CPP */ diff --git a/src/sage/libs/ntl/types.pxd b/src/sage/libs/ntl/types.pxd index b52bc0f0d68..1c8f74d1bc5 100644 --- a/src/sage/libs/ntl/types.pxd +++ b/src/sage/libs/ntl/types.pxd @@ -1,6 +1,6 @@ # distutils: depends = NTL/ZZ.h -cdef extern from "sage/libs/ntl/ntlwrap.h": +cdef extern from "ntlwrap.h": long NTL_OVFBND, NTL_SP_BOUND cdef cppclass ZZ_c "ZZ": diff --git a/src/sage/libs/ntl/vec_GF2.pxd b/src/sage/libs/ntl/vec_GF2.pxd index 0630893b65a..fd7ef6c636d 100644 --- a/src/sage/libs/ntl/vec_GF2.pxd +++ b/src/sage/libs/ntl/vec_GF2.pxd @@ -5,7 +5,7 @@ cdef extern from "ccobject.h": object vec_GF2_to_PyString "_to_PyString"(vec_GF2_c *x) void vec_GF2_swap "swap"(vec_GF2_c x, vec_GF2_c y) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": int vec_GF2_IsZero "IsZero"(vec_GF2_c x) void vec_GF2_append_GF2 "append"(vec_GF2_c v, GF2_c a) diff --git a/src/sage/libs/polybori/decl.pxd b/src/sage/libs/polybori/decl.pxd index e7703c14291..7b455c9dd6f 100644 --- a/src/sage/libs/polybori/decl.pxd +++ b/src/sage/libs/polybori/decl.pxd @@ -1,6 +1,6 @@ # distutils: language = c++ -cdef extern from "sage/libs/polybori/pb_wrap.h": +cdef extern from "pb_wrap.h": ctypedef struct std_string "std::string": char *(* c_str)() diff --git a/src/sage/libs/pynac/pynac.pxd b/src/sage/libs/pynac/pynac.pxd index 17c9a355a22..a9561f00509 100644 --- a/src/sage/libs/pynac/pynac.pxd +++ b/src/sage/libs/pynac/pynac.pxd @@ -34,7 +34,7 @@ from libcpp.pair cimport pair from libcpp.string cimport string as stdstring from sage.libs.gmp.types cimport mpz_t, mpq_t, mpz_ptr, mpq_ptr -cdef extern from "sage/libs/pynac/wrap.h": +cdef extern from "pynac_wrap.h": void ginac_pyinit_Integer(object) void ginac_pyinit_Float(object) void ginac_pyinit_I(object) diff --git a/src/sage/libs/pynac/wrap.h b/src/sage/libs/pynac/pynac_wrap.h similarity index 96% rename from src/sage/libs/pynac/wrap.h rename to src/sage/libs/pynac/pynac_wrap.h index da6a9142065..041b72fc653 100644 --- a/src/sage/libs/pynac/wrap.h +++ b/src/sage/libs/pynac/pynac_wrap.h @@ -7,6 +7,9 @@ http://www.gnu.org/licenses/ *******************************************************************************/ +#ifndef _SAGE_PYNAC_WRAP_H +#define _SAGE_PYNAC_WRAP_H + #include "ccobject.h" #include #include @@ -115,3 +118,5 @@ namespace GiNaC { extern const ex _ex1_2; } + +#endif /* ifndef __SAGE_PYNAC_WRAP_H */ diff --git a/src/sage/misc/cython_metaclass.pxd b/src/sage/misc/cython_metaclass.pxd index 66df2cfc6db..189eb04f1c4 100644 --- a/src/sage/misc/cython_metaclass.pxd +++ b/src/sage/misc/cython_metaclass.pxd @@ -1,2 +1,2 @@ -cdef extern from "sage/misc/cython_metaclass.h": +cdef extern from "cython_metaclass.h": PyMethodDescr_CallSelf(desc, self) diff --git a/src/sage/rings/finite_rings/stdint.h b/src/sage/rings/finite_rings/integer_mod_limits.h similarity index 66% rename from src/sage/rings/finite_rings/stdint.h rename to src/sage/rings/finite_rings/integer_mod_limits.h index d54ad4c1799..5c635b65838 100644 --- a/src/sage/rings/finite_rings/stdint.h +++ b/src/sage/rings/finite_rings/integer_mod_limits.h @@ -1,6 +1,9 @@ +#ifndef _SAGE_FINITE_RINGS_INTEGER_MOD_LIMITS_H +#define _SAGE_FINITE_RINGS_INTEGER_MOD_LIMITS_H #include #define INTEGER_MOD_INT32_LIMIT 46341 // = ceil(sqrt(2^31-1)) #define INTEGER_MOD_INT64_LIMIT 2147483647 // = 2^31-1 for now, should be 3037000500LL = ceil(sqrt(2^63-1)) +#endif diff --git a/src/sage/rings/finite_rings/stdint.pxd b/src/sage/rings/finite_rings/stdint.pxd index 52e07fc1911..b2b96a90c39 100644 --- a/src/sage/rings/finite_rings/stdint.pxd +++ b/src/sage/rings/finite_rings/stdint.pxd @@ -11,11 +11,9 @@ C Integer Types Used in Finite Rings # http://www.gnu.org/licenses/ #***************************************************************************** -cimport libc.stdint +from libc.stdint cimport int_fast32_t, int_fast64_t -cdef extern from "sage/rings/finite_rings/stdint.h": - ctypedef libc.stdint.int_fast32_t int_fast32_t - ctypedef libc.stdint.int_fast64_t int_fast64_t +cdef extern from "integer_mod_limits.h": int_fast32_t INTEGER_MOD_INT32_LIMIT int_fast64_t INTEGER_MOD_INT64_LIMIT diff --git a/src/sage/sat/solvers/cryptominisat/solverconf.pxd b/src/sage/sat/solvers/cryptominisat/solverconf.pxd index f179fc0068d..ab470c18477 100644 --- a/src/sage/sat/solvers/cryptominisat/solverconf.pxd +++ b/src/sage/sat/solvers/cryptominisat/solverconf.pxd @@ -10,7 +10,7 @@ from sage.sat.solvers.cryptominisat.decl cimport SolverConf as SolverConfC -cdef extern from "sage/sat/solvers/cryptominisat/solverconf_helper.h": +cdef extern from "solverconf_helper.h": ctypedef enum sc_type: t_int t_float From 51aeae38a87d568034d69a310b680c50146179da Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Wed, 10 May 2017 09:10:34 +0200 Subject: [PATCH 003/218] 18386: doctest dilog/polylog fixes --- src/sage/functions/log.py | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index c08a2b5a09d..a908d77e58b 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -432,9 +432,25 @@ def __init__(self): sage: polylog(2.0, 1) 1.64493406684823 sage: polylog(2, 1.0) - NaN + NaN*I + NaN sage: polylog(2.0, 1.0) - NaN + NaN*I + NaN + + sage: BF = RealBallField(100) + sage: polylog(2, BF(1/3)) + [0.3662132299770634876167462976 +/- 8.13e-29] + sage: polylog(2, BF(4/3)) + nan + sage: parent(_) + Real ball field with 100 bits precision + sage: polylog(2, CBF(1/3)) + [0.36621322997706 +/- 4.62e-15] + sage: parent(_) + Complex ball field with 53 bits precision + sage: polylog(2, CBF(1)) + nan + nan*I + sage: parent(_) + Complex ball field with 53 bits precision """ GinacFunction.__init__(self, "polylog", nargs=2) @@ -485,10 +501,16 @@ def __init__(self): dilog(x^2 + 1) sage: dilog(-1) -1/12*pi^2 + sage: dilog(-1.0) + -0.822467033424113 sage: dilog(-1.1) -0.890838090262283 - sage: float(dilog(1)) - 1.6449340668482262 + sage: dilog(1/2) + 1/12*pi^2 - 1/2*log(2)^2 + sage: dilog(.5) + 0.582240526465012 + sage: dilog(1/2).n() + 0.582240526465012 sage: var('z') z sage: dilog(z).diff(z, 2) @@ -499,7 +521,19 @@ def __init__(self): sage: latex(dilog(z)) {\rm Li}_2\left(z\right) - TESTS: + Dilog has a branch point at `1`. Sage's floating point libraries + may handle this differently from the symbolic package:: + + sage: dilog(1) + 1/6*pi^2 + sage: dilog(1.) + NaN + sage: dilog(1).n() + 1.64493406684823 + sage: float(dilog(1)) + 1.6449340668482262 + + TESTS: ``conjugate(dilog(x))==dilog(conjugate(x))`` unless on the branch cuts which run along the positive real axis beginning at 1.:: @@ -518,6 +552,21 @@ def __init__(self): dilog(-1/2*I) sage: conjugate(dilog(2)) conjugate(dilog(2)) + + Check that return type matches argument type where possible + (:trac:`18386`):: + + sage: dilog(0.5) + 0.582240526465012 + sage: dilog(-1.0) + -0.822467033424113 + sage: y = dilog(RealField(13)(0.5)) + sage: parent(y) + Real Field with 13 bits of precision + sage: dilog(RealField(13)(1.1)) + 1.96 - 0.300*I + sage: parent(_) + Complex Field with 13 bits of precision """ GinacFunction.__init__(self, 'dilog', conversions=dict(maxima='li[2]')) From 88bdf3c89c5522df62d0035cd3d8826755d451d2 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 7 Jul 2017 15:56:37 +0200 Subject: [PATCH 004/218] Fixed two bugs in the genus class In canonical_2_adic_reduction the input is now preserved from unwanted modification Added a doctest in GenusSymbol_global_ring.__eq__ The function is_2_adic_genus expect as input a canonical_symbol but does not state that in the description. Added the word "canonical". Fixed a bug in is_GlobalGenus. is_2_adic_genus now recieves a canonical symbol as input. Added an example in is_GlobalGenus of a Genus which is not coming from a global quadratic form. --- src/sage/quadratic_forms/genera/genus.py | 27 ++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 7d0961ad572..523d5b27060 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -17,7 +17,7 @@ from sage.rings.rational_field import RationalField from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField - +import copy def Genus(A): r""" @@ -101,6 +101,14 @@ def is_GlobalGenus(G): sage: G = Genus(A) sage: is_GlobalGenus(G) True + + sage: from sage.quadratic_forms.genera.genus import Genus,is_GlobalGenus + sage: G=Genus(matrix.diagonal([2,2,2,2])) + sage: G._local_symbols[0]._symbol=[[0,2,3,0,0],[1,2,5,1,0]] + sage: G._representative=None + sage: is_GlobalGenus(G) + False + """ D = G.determinant() r, s = G.signature_pair_of_matrix() @@ -112,7 +120,7 @@ def is_GlobalGenus(G): a = D // (p**v) b = Integer(prod([ s[2] for s in sym ])) if p == 2: - if not is_2_adic_genus(sym): + if not is_2_adic_genus(loc.canonical_symbol()): # print "False in is_2_adic_genus(sym)" return False if (a*b).kronecker(p) != 1: @@ -133,7 +141,7 @@ def is_GlobalGenus(G): def is_2_adic_genus(genus_symbol_quintuple_list): """ - Given a 2-adic local symbol (as the underlying list of quintuples) + Given a canonical 2-adic local symbol (as the underlying list of quintuples) check whether it is the 2-adic symbol of a 2-adic form. INPUT: @@ -423,6 +431,8 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): Add an example where sign walking occurs! """ + # Protect the input from unwanted modification + genus_symbol_quintuple_list = copy.deepcopy(genus_symbol_quintuple_list) canonical_symbol = genus_symbol_quintuple_list # Canonical determinants: for i in range(len(genus_symbol_quintuple_list)): @@ -1597,7 +1607,16 @@ def __eq__(self, other): sage: GS2 == GS2 True - + + TESTS:: + sage: D4=QuadraticForm(Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2])) + sage: G=D4.global_genus_symbol() + sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) + True + sage: G==deepcopy(G) + True + sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) + True """ if self is other: return True From 8e62210714bf1bcc426733eab9848bd3ff230c23 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 9 Jul 2017 00:23:07 +0200 Subject: [PATCH 005/218] Seems that is_2_adic_genus did not assume the input to be canonical but instead did not reduce the determinants mod 8. Changed that. --- src/sage/quadratic_forms/genera/genus.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 523d5b27060..47fd7c301fe 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -120,7 +120,7 @@ def is_GlobalGenus(G): a = D // (p**v) b = Integer(prod([ s[2] for s in sym ])) if p == 2: - if not is_2_adic_genus(loc.canonical_symbol()): + if not is_2_adic_genus(sym): # print "False in is_2_adic_genus(sym)" return False if (a*b).kronecker(p) != 1: @@ -141,7 +141,7 @@ def is_GlobalGenus(G): def is_2_adic_genus(genus_symbol_quintuple_list): """ - Given a canonical 2-adic local symbol (as the underlying list of quintuples) + Given a 2-adic local symbol (as the underlying list of quintuples) check whether it is the 2-adic symbol of a 2-adic form. INPUT: @@ -187,10 +187,10 @@ def is_2_adic_genus(genus_symbol_quintuple_list): if s[3] == 0 or s[2] != s[4]: return False if s[1] == 2 and s[3] == 1: - if s[2] in (1,-1): + if s[2]%8 in (1,7): if not s[4] in (0,2,6): return False - if s[2] in (3,-3): + if s[2]%8 in (3,5): if not s[4] in (2,4,6): return False if (s[1] - s[4])% 2 == 1: From 1c0f03737ad10bf8f97dbe02404bf1f18cf5126d Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 10 Jul 2017 16:27:07 +0200 Subject: [PATCH 006/218] Change the name of modules of differential forms of degree p from Lambda^p(M) to Omega^p(M) --- .../manifolds/differentiable/diff_form.py | 26 +++-- .../differentiable/diff_form_module.py | 106 ++++++++++-------- src/sage/manifolds/differentiable/manifold.py | 15 +-- .../manifolds/differentiable/scalarfield.py | 4 +- .../differentiable/vectorfield_module.py | 22 ++-- 5 files changed, 98 insertions(+), 75 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index db84642f52c..e70d4bca19a 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -84,10 +84,13 @@ class DiffForm(TensorField): .. MATH:: - a(x) \in \Lambda^p(T_{\Phi(x)} M) + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) , - for all `x \in U`, i.e. `a(x)` is an alternating multilinear form - of degree `p` of the tangent space to `M` at the point `\Phi(x)`. + where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at + `\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`). + In other words, `a(x)` is an alternating multilinear form of degree `p` of + the tangent vector space `T_{\Phi(x)} M`. The standard case of a differential form *on* a manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other @@ -126,7 +129,7 @@ class DiffForm(TensorField): sage: a = M.diff_form(2, name='a') ; a 2-form a on the 2-dimensional differentiable manifold M sage: a.parent() - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: a.degree() 2 @@ -146,7 +149,7 @@ class DiffForm(TensorField): sage: a = M.one_form('a') ; a 1-form a on the 2-dimensional differentiable manifold M sage: a.parent() - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: a.degree() 1 @@ -617,10 +620,13 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): .. MATH:: - a(x) \in \Lambda^p(T_{\Phi(x)} M) + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) , - for all `x \in U`, i.e. `a(x)` is an alternating multilinear form - of degree `p` of the tangent space to `M` at the point `\Phi(x)`. + where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at + `\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`). + In other words, `a(x)` is an alternating multilinear form of degree `p` of + the tangent vector space `T_{\Phi(x)} M`. The standard case of a differential form *on* a manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` @@ -651,7 +657,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: a = M.diff_form(2, 'a') ; a 2-form a on the 4-dimensional differentiable manifold M sage: a.parent() - Free module /\^2(M) of 2-forms on the 4-dimensional differentiable + Free module Omega^2(M) of 2-forms on the 4-dimensional differentiable manifold M A differential form is a tensor field of purely covariant type:: @@ -825,7 +831,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: isinstance(om, sage.manifolds.differentiable.diff_form.DiffFormParal) True sage: om.parent() - Free module /\^1(R3) of 1-forms on the 3-dimensional differentiable + Free module Omega^1(R3) of 1-forms on the 3-dimensional differentiable manifold R3 sage: om.tensor_type() (0, 1) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index bb538625ae7..bd5daf72d1f 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -1,12 +1,12 @@ r""" Differential Form Modules -The set `\Lambda^p(U, \Phi)` of `p`-forms along a differentiable manifold `U` +The set `\Omega^p(U, \Phi)` of `p`-forms along a differentiable manifold `U` with values on a differentiable manifold `M` via a differentiable map `\Phi:\ U \rightarrow M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`) is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`. It is a free module if and only if `M` is parallelizable. Accordingly, -two classes implement `\Lambda^p(U, \Phi)`: +two classes implement `\Omega^p(U, \Phi)`: - :class:`DiffFormModule` for differential forms with values on a generic (in practice, not parallelizable) differentiable manifold `M` @@ -50,7 +50,7 @@ class DiffFormModule(UniqueRepresentation, Parent): Given a differentiable manifold `U` and a differentiable map `\Phi: U \rightarrow M` to a differentiable manifold `M`, the set - `\Lambda^p(U, \Phi)` of `p`-forms along `U` with values on `M` is + `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `M` is a module over `C^k(U)`, the commutative algebra of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). @@ -61,8 +61,8 @@ class DiffFormModule(UniqueRepresentation, Parent): .. NOTE:: - This class implements `\Lambda^p(U,\Phi)` in the case where `M` is - not assumed to be parallelizable; the module `\Lambda^p(U, \Phi)` + This class implements `\Omega^p(U,\Phi)` in the case where `M` is + not assumed to be parallelizable; the module `\Omega^p(U, \Phi)` is then not necessarily free. If `M` is parallelizable, the class :class:`DiffFormFreeModule` must be used instead. @@ -89,16 +89,23 @@ class DiffFormModule(UniqueRepresentation, Parent): Module X(M) of vector fields on the 2-dimensional differentiable manifold M sage: A = M.diff_form_module(2) ; A - Module /\^2(M) of 2-forms on the 2-dimensional differentiable manifold M + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable + manifold M sage: latex(A) - \Lambda^{2}\left(M\right) + \Omega^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. + we have `\Omega^{2}(M) = \Lambda^2(\mathcal{X}(M)^*)`:: + + sage: A is XM.dual_exterior_power(2) + True Modules of differential forms are unique:: sage: A is M.diff_form_module(2) True - `\Lambda^2(M)` is a module over the algebra `C^k(M)` of (differentiable) + `\Omega^2(M)` is a module over the algebra `C^k(M)` of (differentiable) scalar fields on `M`:: sage: A.category() @@ -134,7 +141,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a = A([[0,3*x],[-3*x,0]], frame=eU, name='a') ; a 2-form a on the 2-dimensional differentiable manifold M - sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes the initialization of a + sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes initializ. of a sage: a.display(eU) a = 3*x dx/\dy sage: a.display(eV) @@ -151,16 +158,17 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a.display(eV) a = (-3/4*u - 3/4*v) du/\dv - The module `\Lambda^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathcal{X}(M)` (the module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 - Module /\^1(M) of 1-forms on the 2-dimensional differentiable manifold M + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable + manifold M sage: L1 is XM.dual() True Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Lambda^1(M)`:: + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 Module T^(0,1)(M) of type-(0,1) tensors fields on the 2-dimensional @@ -174,7 +182,7 @@ class DiffFormModule(UniqueRepresentation, Parent): True For a degree `p \geq 2`, the coercion holds only in the direction - `\Lambda^p(M)\rightarrow T^{(0,p)}(M)`:: + `\Omega^p(M)\rightarrow T^{(0,p)}(M)`:: sage: T02 = M.tensor_field_module((0,2)) ; T02 Module T^(0,2)(M) of type-(0,2) tensors fields on the 2-dimensional @@ -184,7 +192,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Lambda^1(M)` in action:: + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([y,x], frame=eU, name='b') ; b Tensor field b of type (0,1) on the 2-dimensional differentiable @@ -201,7 +209,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: lb.display(eV) b = 1/2*u du - 1/2*v dv - The coercion map `\Lambda^1(M) \rightarrow T^{(0,1)}(M)` in action:: + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb) ; tlb Tensor field b of type (0,1) on the 2-dimensional differentiable @@ -213,7 +221,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: tlb == b True - The coercion map `\Lambda^2(M) \rightarrow T^{(0,2)}(M)` in action:: + The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: ta = T02(a) ; ta Tensor field a of type (0,2) on the 2-dimensional differentiable @@ -231,7 +239,7 @@ class DiffFormModule(UniqueRepresentation, Parent): of the differential form to some subset of its domain:: sage: L2U = U.diff_form_module(2) ; L2U - Free module /\^2(U) of 2-forms on the Open subset U of the + Free module Omega^2(U) of 2-forms on the Open subset U of the 2-dimensional differentiable manifold M sage: L2U.has_coerce_map_from(A) True @@ -263,7 +271,7 @@ def __init__(self, vector_field_module, degree): sage: from sage.manifolds.differentiable.diff_form_module import \ ....: DiffFormModule sage: A = DiffFormModule(M.vector_field_module(), 2) ; A - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: TestSuite(A).run(skip='_test_elements') @@ -274,8 +282,8 @@ def __init__(self, vector_field_module, degree): """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map - name = "/\^{}(".format(degree) + domain._name - latex_name = r"\Lambda^{{{}}}\left({}".format(degree, domain._latex_name) + name = "Omega^{}(".format(degree) + domain._name + latex_name = r"\Omega^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -371,7 +379,8 @@ def _an_element_(self): if open_covers != []: oc = open_covers[0] # the first non-trivial open cover is selected for dom in oc: - vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom)) + vmodule_dom = dom.vector_field_module( + dest_map=self._dest_map.restrict(dom)) dmodule_dom = vmodule_dom.dual_exterior_power(self._degree) resu.set_restriction(dmodule_dom._an_element_()) return resu @@ -444,7 +453,7 @@ def _repr_(self): sage: M = Manifold(3, 'M') sage: A2 = M.diff_form_module(2) sage: A2 - Module /\^2(M) of 2-forms on + Module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M """ @@ -468,9 +477,9 @@ def _latex_(self): sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}') sage: A2 = M.diff_form_module(2) sage: A2._latex_() - '\\Lambda^{2}\\left(\\mathcal{M}\\right)' + '\\Omega^{2}\\left(\\mathcal{M}\\right)' sage: latex(A2) # indirect doctest - \Lambda^{2}\left(\mathcal{M}\right) + \Omega^{2}\left(\mathcal{M}\right) """ if self._latex_name is None: @@ -494,7 +503,7 @@ def base_module(self): sage: M = Manifold(3, 'M') sage: A2 = M.diff_form_module(2) ; A2 - Module /\^2(M) of 2-forms on the 3-dimensional differentiable + Module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: A2.base_module() Module X(M) of vector fields on the 3-dimensional differentiable @@ -503,8 +512,8 @@ def base_module(self): True sage: U = M.open_subset('U') sage: A2U = U.diff_form_module(2) ; A2U - Module /\^2(U) of 2-forms on the Open subset U of the 3-dimensional - differentiable manifold M + Module Omega^2(U) of 2-forms on the Open subset U of the + 3-dimensional differentiable manifold M sage: A2U.base_module() Module X(U) of vector fields on the Open subset U of the 3-dimensional differentiable manifold M @@ -542,7 +551,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): Given a differentiable manifold `U` and a differentiable map `\Phi:\; U \rightarrow M` to a parallelizable manifold `M`, the set - `\Lambda^p(U, \Phi)` of `p`-forms along `U` with values on `M` is a + `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `M` is a free module over `C^k(U)`, the commutative algebra of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). @@ -551,8 +560,8 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). - This class implements `\Lambda^p(U, \Phi)` in the case where `M` is - parallelizable; `\Lambda^p(U, \Phi)` is then a *free* module. If `M` is not + This class implements `\Omega^p(U, \Phi)` in the case where `M` is + parallelizable; `\Omega^p(U, \Phi)` is then a *free* module. If `M` is not parallelizable, the class :class:`DiffFormModule` must be used instead. This is a Sage *parent* class, whose *element* class is @@ -574,12 +583,19 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): Free module X(M) of vector fields on the 3-dimensional differentiable manifold M sage: A = M.diff_form_module(2) ; A - Free module /\^2(M) of 2-forms on the 3-dimensional differentiable + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: latex(A) - \Lambda^{2}\left(M\right) + \Omega^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. + we have `\Omega^{2}(M) = \Lambda^2(\mathcal{X}(M)^*)` (see + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`):: + + sage: A is XM.dual_exterior_power(2) + True - `A` is a module over the algebra `C^k(M)` of (differentiable) + `\Omega^{2}(M)` is a module over the algebra `C^k(M)` of (differentiable) scalar fields on `M`:: sage: A.category() @@ -628,17 +644,17 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: a.display() a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz - The module `\Lambda^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathcal{X}(M)` (the free module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 - Free module /\^1(M) of 1-forms on the 3-dimensional differentiable + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: L1 is XM.dual() True Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Lambda^1(M)`:: + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 Free module T^(0,1)(M) of type-(0,1) tensors fields on the @@ -652,7 +668,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): True For a degree `p \geq 2`, the coercion holds only in the direction - `\Lambda^p(M) \rightarrow T^{(0,p)}(M)`:: + `\Omega^p(M) \rightarrow T^{(0,p)}(M)`:: sage: T02 = M.tensor_field_module((0,2)); T02 Free module T^(0,2)(M) of type-(0,2) tensors fields on the @@ -662,7 +678,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Lambda^1(M)` in action:: + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([-x,2,3*y], name='b'); b Tensor field b of type (0,1) on the 3-dimensional differentiable @@ -674,7 +690,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: lb.display() b = -x dx + 2 dy + 3*y dz - The coercion map `\Lambda^1(M) \rightarrow T^{(0,1)}(M)` in action:: + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb); tlb Tensor field b of type (0,1) on @@ -682,7 +698,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: tlb == b True - The coercion map `\Lambda^2(M) \rightarrow T^{(0,2)}(M)` in action:: + The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: T02 = M.tensor_field_module((0,2)) ; T02 Free module T^(0,2)(M) of type-(0,2) tensors fields on the @@ -702,7 +718,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) sage: B = U.diff_form_module(2) ; B - Free module /\^2(U) of 2-forms on the Open subset U of the + Free module Omega^2(U) of 2-forms on the Open subset U of the 3-dimensional differentiable manifold M sage: B.has_coerce_map_from(A) True @@ -726,15 +742,15 @@ def __init__(self, vector_field_module, degree): sage: X. = M.chart() sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule sage: A = DiffFormFreeModule(M.vector_field_module(), 2) ; A - Free module /\^2(M) of 2-forms on + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: TestSuite(A).run() """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map - name = "/\^{}(".format(degree) + domain._name - latex_name = r"\Lambda^{{{}}}\left({}".format(degree, domain._latex_name) + name = "Omega^{}(".format(degree) + domain._name + latex_name = r"\Omega^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -848,7 +864,7 @@ def _repr_(self): sage: X. = M.chart() sage: A = M.diff_form_module(2) sage: A - Free module /\^2(M) of 2-forms on + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M """ diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 609e28006c7..ed670890b36 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -253,7 +253,8 @@ sage: df.display(stereoS.frame()) df = -2*u/(u^4 + 2*u^2*v^2 + v^4 + 1) du - 2*v/(u^4 + 2*u^2*v^2 + v^4 + 1) dv sage: df.parent() - Module /\^1(S^2) of 1-forms on the 2-dimensional differentiable manifold S^2 + Module Omega^1(S^2) of 1-forms on the 2-dimensional differentiable + manifold S^2 sage: df.parent().category() Category of modules over Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold S^2 @@ -1266,7 +1267,7 @@ def diff_form_module(self, degree, dest_map=None): :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormModule` (or if `N` is parallelizable, a :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormFreeModule`) - representing the module `\Lambda^p(M,\Phi)` of `p`-forms on `M` + representing the module `\Omega^p(M,\Phi)` of `p`-forms on `M` taking values on `\Phi(M)\subset N` EXAMPLES: @@ -1276,7 +1277,7 @@ def diff_form_module(self, degree, dest_map=None): sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: M.diff_form_module(2) - Free module /\^2(M) of 2-forms on the 3-dimensional differentiable + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: M.diff_form_module(2).category() Category of finite dimensional modules over Algebra of @@ -1709,10 +1710,10 @@ def diff_form(self, degree, name=None, latex_name=None, .. MATH:: - \forall p \in M,\ t(p) \in \Lambda^p(T^*_{\Phi(p)} N), + \forall x \in M,\ t(x) \in \Lambda^p(T^*_{\Phi(x)} N), - where `\Lambda^p(T^*_{\Phi(p)} N)` is the `p`-th exterior power - of the dual of the tangent space `T_{\Phi(p)} N`. + where `\Lambda^p(T^*_{\Phi(x)} N)` is the `p`-th exterior power + of the dual of the tangent space `T_{\Phi(x)} N`. The standard case of a differential form *on* `M` corresponds to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` @@ -1831,7 +1832,7 @@ def one_form(self, name=None, latex_name=None, dest_map=None): 1-form omega on the Open subset A of the 3-dimensional differentiable manifold M sage: om.parent() - Free module /\^1(A) of 1-forms on the Open subset A of the + Free module Omega^1(A) of 1-forms on the Open subset A of the 3-dimensional differentiable manifold M .. SEEALSO:: diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index d7f47c031e1..9e10f6a88da 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -725,8 +725,8 @@ def differential(self): sage: latex(df) \mathrm{d}f sage: df.parent() - Free module /\^1(M) of 1-forms on the 3-dimensional differentiable - manifold M + Free module Omega^1(M) of 1-forms on the 3-dimensional + differentiable manifold M The result is cached, i.e. is not recomputed unless ``f`` is changed:: diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 20dc049ff67..7c12fe66b39 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -531,7 +531,7 @@ def dual_exterior_power(self, p): module. If the vector field module is `\mathcal{X}(U,\Phi)`, the - `p`-th exterior power of its dual is the set `\Lambda^p(U, \Phi)` + `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `\Phi(U)`. It is a module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U`. @@ -544,7 +544,7 @@ def dual_exterior_power(self, p): - for `p \geq 1`, instance of :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormModule` - representing the module `\Lambda^p(U,\Phi)`; for `p=0`, the + representing the module `\Omega^p(U,\Phi)`; for `p=0`, the base ring, i.e. `C^k(U)`, is returned instead EXAMPLES:: @@ -552,10 +552,10 @@ def dual_exterior_power(self, p): sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM.dual_exterior_power(2) - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True @@ -587,7 +587,7 @@ def dual(self): sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM.dual() - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M """ @@ -1484,7 +1484,7 @@ def dual_exterior_power(self, p): Return the `p`-th exterior power of the dual of ``self``. If the vector field module is `\mathcal{X}(U,\Phi)`, the - `p`-th exterior power of its dual is the set `\Lambda^p(U, \Phi)` + `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `\Phi(U)`. It is a module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U`. @@ -1497,7 +1497,7 @@ def dual_exterior_power(self, p): - for `p \geq 1`, a :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormFreeModule` - representing the module `\Lambda^p(U,\Phi)`; for `p=0`, the + representing the module `\Omega^p(U,\Phi)`; for `p=0`, the base ring, i.e. `C^k(U)`, is returned instead EXAMPLES:: @@ -1506,11 +1506,11 @@ def dual_exterior_power(self, p): sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.dual_exterior_power(2) - Free module /\^2(M) of 2-forms on the 2-dimensional differentiable - manifold M + Free module Omega^2(M) of 2-forms on the 2-dimensional + differentiable manifold M sage: XM.dual_exterior_power(1) - Free module /\^1(M) of 1-forms on the 2-dimensional differentiable - manifold M + Free module Omega^1(M) of 1-forms on the 2-dimensional + differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True sage: XM.dual_exterior_power(0) From a73170c214b4eb979da8c2ac7acbf06c553069e7 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 10 Jul 2017 18:26:55 +0200 Subject: [PATCH 007/218] Start the implementation of multivector fields on manifolds (work in progress) --- .../manifolds/differentiable/diff_form.py | 18 +- .../differentiable/diff_form_module.py | 2 +- .../differentiable/multivector_module.py | 785 ++++++++++++++++++ .../differentiable/multivectorfield.py | 746 +++++++++++++++++ 4 files changed, 1541 insertions(+), 10 deletions(-) create mode 100644 src/sage/manifolds/differentiable/multivector_module.py create mode 100644 src/sage/manifolds/differentiable/multivectorfield.py diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index e70d4bca19a..81a8a66341d 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -3,7 +3,7 @@ Let `U` and `M` be two differentiable manifolds. Given a positive integer `p` and a differentiable map `\Phi: U \rightarrow M`, -a *differential form of degree* `p`, or *p-form*, +a *differential form of degree* `p`, or `p`-*form*, *along* `U` *with values on* `M` is a field along `U` of alternating multilinear forms of degree `p` in the tangent spaces to `M`. The standard case of a differential form *on* a differentiable manifold @@ -72,15 +72,14 @@ class DiffForm(TensorField): Given a differentiable manifold `U`, a differentiable map `\Phi: U \rightarrow M` to a differentiable manifold `M` and a positive - integer `p`, a *differential form of degree* `p` (or *p-form*) + integer `p`, a *differential form of degree* `p` (or `p`-*form*) *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map .. MATH:: a:\ U \longrightarrow T^{(0,p)}M - (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such - that + (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that .. MATH:: @@ -608,15 +607,14 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): Given a differentiable manifold `U`, a differentiable map `\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive - integer `p`, a *differential form of degree* `p` (or *p-form*) + integer `p`, a *differential form of degree* `p` (or `p`-*form*) *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map .. MATH:: a:\ U \longrightarrow T^{(0,p)}M - (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such - that + (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that .. MATH:: @@ -1198,10 +1196,12 @@ def wedge(self, other): from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index bd5daf72d1f..5bdc7eb3ce9 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -714,7 +714,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): no symmetry; antisymmetry: (0, 1) There is also coercion to subdomains, which is nothing but the - restrictionof the differential form to some subset of its domain:: + restriction of the differential form to some subset of its domain:: sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) sage: B = U.diff_form_module(2) ; B diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py new file mode 100644 index 00000000000..b0cad66be59 --- /dev/null +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -0,0 +1,785 @@ +r""" +Multivector fields Modules + +The set `A^p(U, \Phi)` of `p`-vector fields along a differentiable manifold `U` +with values on a differentiable manifold `M` via a differentiable map +`\Phi:\ U \rightarrow M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`) +is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`. +It is a free module if and only if `M` is parallelizable. Accordingly, +two classes implement `A^p(U, \Phi)`: + +- :class:`MultivectorModule` for `p`-vector fields with values on a generic + (in practice, not parallelizable) differentiable manifold `M` +- :class:`MultivectorFreeModule` for `p`-vector fields with values on a + parallelizable manifold `M` + +AUTHORS: + +- Eric Gourgoulhon (2017): initial version + +REFERENCES: + +- C.-M. Marle (1997) + +""" +#****************************************************************************** +# Copyright (C) 2017 Eric Gourgoulhon +# +# 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/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.categories.modules import Modules +from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule +from sage.manifolds.differentiable.multivectorfield import (MultivectorField, + MultivectorFieldParal) +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal + +class MultivectorModule(UniqueRepresentation, Parent): + r""" + Module of multivector fields of a given degree `p` (`p`-vector fields) + along a differentiable manifold `U` with values on a differentiable + manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi: U \rightarrow M` to a differentiable manifold `M`, the set + `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields of type + `(p,0)`) along `U` with values on `M` is a module over `C^k(U)`, the + commutative algebra of differentiable scalar fields on `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of `p`-vector fields *on* a differentiable manifold `M` + corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases + are `\Phi` being an immersion and `\Phi` being a curve in `M` + (`U` is then an open interval of `\RR`). + + .. NOTE:: + + This class implements `A^p(U,\Phi)` in the case where `M` is + not assumed to be parallelizable; the module `A^p(U, \Phi)` + is then not necessarily free. If `M` is parallelizable, the class + :class:`MultivectorFreeModule` must be used instead. + + INPUT: + + - ``vector_field_module`` -- module `\mathcal{X}(U, \Phi)` of vector + fields along `U` with values on `M` via the map `\Phi: U \rightarrow M` + - ``degree`` -- positive integer; the degree `p` of the multivector fields + + EXAMPLES: + + Module of 2-vector fields on a non-parallelizable 2-dimensional manifold:: + + sage: M = Manifold(2, 'M') + 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: transf = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', restrictions1= x>0, restrictions2= u+v>0) + sage: inv = transf.inverse() + sage: W = U.intersection(V) + sage: eU = c_xy.frame() ; eV = c_uv.frame() + sage: XM = M.vector_field_module() ; XM + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A = M.multivector_module(2) ; A + Module A^2(M) of 2-vector fields on the 2-dimensional differentiable + manifold M + sage: latex(A) + A^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of of ``XM``, i.e. + we have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))`:: + + sage: A is XM.exterior_power(2) + True + + Modules of multivector fields are unique:: + + sage: A is M.multivector_module(2) + True + + `A^2(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of modules over Algebra of differentiable scalar fields on + the 2-dimensional differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() is CM + True + sage: A.base_module() + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A.base_module() is XM + True + + Elements can be constructed from ``A()``. In particular, ``0`` yields + the zero element of ``A``:: + + sage: z = A(0) ; z + 2-vector field zero on the 2-dimensional differentiable manifold M + sage: z.display(eU) + zero = 0 + sage: z.display(eV) + zero = 0 + sage: z is A.zero() + True + + while non-zero elements are constructed by providing their components in a + given vector frame:: + + sage: a = A([[0,3*x],[-3*x,0]], frame=eU, name='a') ; a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes initializ. of a + sage: a.display(eU) + a = 3*x dx/\dy + sage: a.display(eV) + a = (-3/4*u - 3/4*v) du/\dv + + An alternative is to construct the 2-vector field from an empty list of + components and to set the nonzero nonredundant components afterwards:: + + sage: a = A([], name='a') + sage: a[eU,0,1] = 3*x + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: a.display(eU) + a = 3*x dx/\dy + sage: a.display(eV) + a = (-3/4*u - 3/4*v) du/\dv + + The module `A^1(M)` is nothing but the dual of `\mathcal{X}(M)` + (the module of vector fields on `M`):: + + sage: A1 = M.multivector_module(1) ; A1 + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A1 is XM + True + + For a degree `p \geq 2`, there is a coercion map + `A^p(M)\rightarrow T^{(p,0)}(M)`:: + + sage: T20 = M.tensor_field_module((2,0)) ; T20 + Module T^(2,0)(M) of type-(2,0) tensors fields on the 2-dimensional + differentiable manifold M + sage: T20.has_coerce_map_from(A) + True + + but of course not in the reverse direction:: + + sage: A.has_coerce_map_from(T02) + False + + The coercion map `A^2(M) \rightarrow T^{(2,0)}(M)` in action:: + + sage: ta = T20(a) ; ta + Tensor field a of type (2,0) on the 2-dimensional differentiable + manifold M + sage: ta.display(eU) + a = 3*x dx*dy - 3*x dy*dx + sage: a.display(eU) + a = 3*x dx/\dy + sage: ta.display(eV) + a = (-3/4*u - 3/4*v) du*dv + (3/4*u + 3/4*v) dv*du + sage: a.display(eV) + a = (-3/4*u - 3/4*v) du/\dv + + There is also coercion to subdomains, which is nothing but the restriction + of the multivector field to some subset of its domain:: + + sage: A2U = U.multivector_module(2) ; A2U + Free module A^2(U) of 2-vector fields on the Open subset U of the + 2-dimensional differentiable manifold M + sage: A2U.has_coerce_map_from(A) + True + sage: a_U = A2U(a) ; a_U + 2-vector field a on the Open subset U of the 2-dimensional + differentiable manifold M + sage: a_U.display(eU) + a = 3*x dx/\dy + + """ + Element = MultivectorField + + def __init__(self, vector_field_module, degree): + r""" + Construction a module of multivector fields. + + TESTS: + + Module of 2-vector fields on a non-parallelizable 2-dimensional + manifold:: + + sage: M = Manifold(2, 'M') + 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: transf = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) + sage: inv = transf.inverse() + sage: from sage.manifolds.differentiable.multivector_module import \ + ....: MultivectorModule + sage: A = MultivectorModule(M.vector_field_module(), 2) ; A + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: TestSuite(A).run(skip='_test_elements') + + In the above test suite, ``_test_elements`` is skipped because of the + ``_test_pickling`` error of the elements (to be fixed in + :class:`sage.manifolds.differentialbe.tensorfield.TensorField`) + + """ + domain = vector_field_module._domain + dest_map = vector_field_module._dest_map + name = "A^{}(".format(degree) + domain._name + latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) + if dest_map is domain.identity_map(): + name += ")" + latex_name += r"\right)" + else: + name += "," + dest_map._name + ")" + latex_name += "," + dest_map._latex_name + r"\right)" + self._vmodule = vector_field_module + self._degree = degree + self._name = name + self._latex_name = latex_name + # the member self._ring is created for efficiency (to avoid calls to + # self.base_ring()): + self._ring = domain.scalar_field_algebra() + Parent.__init__(self, base=self._ring, category=Modules(self._ring)) + self._domain = domain + self._dest_map = dest_map + self._ambient_domain = vector_field_module._ambient_domain + # NB: self._zero_element is not constructed here, since no element + # can be constructed here, to avoid some infinite recursion. + + #### Parent methods + + def _element_constructor_(self, comp=[], frame=None, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U'); V = M.open_subset('V') + sage: c_xy. = U.chart(); c_uv. = V.chart() + sage: M.declare_union(U,V) + sage: A = M.multivector_module(2) + sage: a = A([[0, x*y], [-x*y, 0]], name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.display(c_xy.frame()) + a = x*y dx/\dy + sage: A(0) is A.zero() + True + + """ + if comp == 0: + return self.zero() + if isinstance(comp, (MultivectorField, MultivectorFieldParal)): + # coercion by domain restriction + if (self._degree == comp._tensor_type[1] + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset(comp._ambient_domain)): + return comp.restrict(self._domain) + else: + raise TypeError("cannot convert the {} ".format(comp) + + "to an element of {}".format(self)) + # standard construction + resu = self.element_class(self._vmodule, self._degree, name=name, + latex_name=latex_name) + if comp: + resu.set_comp(frame)[:] = comp + return resu + + def _an_element_(self): + r""" + Construct some (unnamed) multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U'); V = M.open_subset('V') + sage: c_xy. = U.chart(); c_uv. = V.chart() + sage: M.declare_union(U,V) + sage: A = M.multivector_module(2) + sage: A._an_element_() + 2-vector field on the 2-dimensional differentiable manifold M + + """ + resu = self.element_class(self._vmodule, self._degree) + # Non-trivial open covers of the domain: + open_covers = self._domain.open_covers()[1:] # the open cover 0 + # is trivial + if open_covers != []: + oc = open_covers[0] # the first non-trivial open cover is selected + for dom in oc: + vmodule_dom = dom.vector_field_module( + dest_map=self._dest_map.restrict(dom)) + dmodule_dom = vmodule_dom.exterior_power(self._degree) + resu.set_restriction(dmodule_dom._an_element_()) + return resu + + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: A1 = M.multivector_module(1) + sage: A1._coerce_map_from_(M.tensor_field_module((0,1))) + True + sage: A2 = M.multivector_module(2) + sage: A2._coerce_map_from_(M.tensor_field_module((0,2))) + False + sage: U = M.open_subset('U') + sage: A2U = U.multivector_module(2) + sage: A2U._coerce_map_from_(A2) + True + sage: A2._coerce_map_from_(A2U) + False + + """ + if isinstance(other, (MultivectorModule, MultivectorFreeModule)): + # coercion by domain restriction + return (self._degree == other._degree + and self._domain.is_subset(other._domain) + and self._ambient_domain.is_subset(other._ambient_domain)) + return False + + @cached_method + def zero(self): + """ + Return the zero of ``self``. + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) + sage: A2.zero() + 2-vector field zero on the 3-dimensional differentiable manifold M + + """ + zero = self.element_class(self._vmodule, self._degree, name='zero', + latex_name='0') + zero = self._element_constructor_(name='zero', latex_name='0') + for frame in self._domain._frames: + if self._dest_map.restrict(frame._domain) == frame._dest_map: + zero.add_comp(frame) + # (since new components are initialized to zero) + return zero + + #### End of Parent methods + + def _repr_(self): + r""" + Return a string representation of the object. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) + sage: A2 + Module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + + """ + description = "Module " + if self._name is not None: + description += self._name + " " + description += "of {}-vector fields ".format(self._degree) + if self._dest_map is self._domain.identity_map(): + description += "on the {}".format(self._domain) + else: + description += "along the {} mapped into the {}".format( + self._domain, self._ambient_domain) + return description + + def _latex_(self): + r""" + Return a LaTeX representation of the object. + + TESTS:: + + sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}') + sage: A2 = M.multivector_module(2) + sage: A2._latex_() + '\A^{2}\\left(\\mathcal{M}\\right)' + sage: latex(A2) # indirect doctest + A^{2}\left(\mathcal{M}\right) + + """ + if self._latex_name is None: + return r'\mbox{' + str(self) + r'}' + else: + return self._latex_name + + def base_module(self): + r""" + Return the vector field module on which the multivector field module + is constructed. + + OUTPUT: + + - a + :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` + representing the module on which the multivector field module is + defined + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) ; A2 + Module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: A2.base_module() + Module X(M) of vector fields on the 3-dimensional differentiable + manifold M + sage: A2.base_module() is M.vector_field_module() + True + sage: U = M.open_subset('U') + sage: A2U = U.multivector_module(2) ; A2U + Module A^2(U) of 2-vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + sage: A2U.base_module() + Module X(U) of vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + + """ + return self._vmodule + + def degree(self): + r""" + Return the degree of the multivector fields in the module. + + OUTPUT: + + - integer `p` such that the module is a set of `p`-vector fields + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: M.multivector_module(1).degree() + 1 + sage: M.multivector_module(2).degree() + 2 + sage: M.multivector_module(3).degree() + 3 + + """ + return self._degree + +#****************************************************************************** + +class MultivectorFreeModule(ExtPowerFreeModule): + r""" + Free module of multivector fields of a given degree `p` (`p`-vector fields) + along a differentiable manifold `U` with values on a parallelizable + manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M`, the set + `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields of type + `(p,0)`) along `U` with values on `M` is a module over `C^k(U)`, the + commutative algebra of differentiable scalar fields on `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of `p`-vector fields *on* a differentiable manifold `M` + corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an + open interval of `\RR`). + + .. NOTE:: + + This class implements `A^p(U, \Phi)` in the case where `M` is + parallelizable; `A^p(U, \Phi)` is then a *free* module. If `M` is not + parallelizable, the class :class:`MultivectorModule` must be used + instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + fields along `U` associated with the map `\Phi: U \rightarrow V` + - ``degree`` -- positive integer; the degree `p` of the multivector fields + + EXAMPLES: + + Free module of 2-vector fields on a parallelizable 3-dimensional manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: XM = M.vector_field_module() ; XM + Free module X(M) of vector fields on the 3-dimensional differentiable + manifold M + sage: A = M.multivector_module(2) ; A + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: latex(A) + A^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of ``XM``, i.e. we have + `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`):: + + sage: A is XM.exterior_power(2) + True + + `A^{2}(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of finite dimensional modules over Algebra of differentiable + scalar fields on the 3-dimensional differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() + Algebra of differentiable scalar fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() + Free module X(M) of vector fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() is XM + True + sage: A.rank() + 3 + + Elements can be constructed from `A`. In particular, ``0`` yields + the zero element of `A`:: + + sage: A(0) + 2-vector field zero on the 3-dimensional differentiable manifold M + sage: A(0) is A.zero() + True + + while non-zero elements are constructed by providing their components + in a given vector frame:: + + sage: comp = [[0,3*x,-z],[-3*x,0,4],[z,-4,0]] + sage: a = A(comp, frame=X.frame(), name='a') ; a + 2-vector field a on the 3-dimensional differentiable manifold M + sage: a.display() + a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + + An alternative is to construct the 2-vector field from an empty list of + components and to set the nonzero nonredundant components afterwards:: + + sage: a = A([], name='a') + sage: a[0,1] = 3*x # component in the manifold's default frame + sage: a[0,2] = -z + sage: a[1,2] = 4 + sage: a.display() + a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + + The module `A^1(M)` is nothing but `\mathcal{X}(M)` (the free module of + vector fields on `M`):: + + sage: A1 = M.multivector_module(1) ; A1 + Free module X(M) of vector fields on the 3-dimensional differentiable + manifold M + sage: A1 is XM + True + + For a degree `p \geq 2`, there is a coercion map + `A^p(M) \rightarrow T^{(p,0)}(M)`:: + + sage: T20 = M.tensor_field_module((2,0)); T20 + Free module T^(2,0)(M) of type-(2,0) tensors fields on the + 3-dimensional differentiable manifold M + sage: T20.has_coerce_map_from(A) + True + + but of course not in the reverse direction:: + + sage: A.has_coerce_map_from(T20) + False + + The coercion map `A^2(M) \rightarrow T^{(2,0)}(M)` in action:: + + sage: T20 = M.tensor_field_module((2,0)) ; T20 + Free module T^(2,0)(M) of type-(2,0) tensors fields on the + 3-dimensional differentiable manifold M + sage: ta = T20(a) ; ta + Tensor field a of type (2,0) on the 3-dimensional differentiable + manifold M + sage: ta.display() + a = 3*x dx*dy - z dx*dz - 3*x dy*dx + 4 dy*dz + z dz*dx - 4 dz*dy + sage: a.display() + a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + sage: ta.symmetries() # the antisymmetry is preserved + no symmetry; antisymmetry: (0, 1) + + There is also coercion to subdomains, which is nothing but the + restriction of the multivector field to some subset of its domain:: + + sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) + sage: B = U.multivector_module(2) ; B + Free module A^2(U) of 2-vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + sage: B.has_coerce_map_from(A) + True + sage: a_U = B(a) ; a_U + 2-vector field a on the Open subset U of the 3-dimensional + differentiable manifold M + sage: a_U.display() + a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + + """ + + Element = MultivectorFieldParal + + def __init__(self, vector_field_module, degree): + r""" + Construct a free module of multivector fields. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: from sage.manifolds.differentiable.multivector_module import MultivectorFreeModule + sage: A = MultivectorFreeModule(M.vector_field_module(), 2) ; A + Free module A^2(M) of 2-vector fields on + the 3-dimensional differentiable manifold M + sage: TestSuite(A).run() + + """ + domain = vector_field_module._domain + dest_map = vector_field_module._dest_map + name = "A^{}(".format(degree) + domain._name + latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) + if dest_map is domain.identity_map(): + name += ")" + latex_name += r"\right)" + else: + name += "," + dest_map._name + ")" + latex_name += "," + dest_map._latex_name + r"\right)" + ExtPowerFreeModule.__init__(self, vector_field_module, degree, + name=name, latex_name=latex_name) + self._domain = domain + self._dest_map = dest_map + self._ambient_domain = vector_field_module._ambient_domain + + #### Parent methods + + def _element_constructor_(self, comp=[], frame=None, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: A = M.multivector_module(2) + sage: a = A([[0, x], [-x, 0]], name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.display() + a = x dx/\dy + sage: A(0) is A.zero() + True + + """ + if comp == 0: + return self.zero() + if isinstance(comp, (MultivectorField, MultivectorFieldParal)): + # coercion by domain restriction + if (self._degree == comp._tensor_type[1] + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset(comp._ambient_domain)): + return comp.restrict(self._domain) + else: + raise TypeError("cannot convert the {} ".format(comp) + + "to a multivector field in {}".format(self)) + if isinstance(comp, TensorFieldParal): + # coercion of a tensor of type (0,1) to a linear form + tensor = comp # for readability + if (tensor.tensor_type() == (0,1) and self._degree == 1 + and tensor._fmodule is self._fmodule): + resu = self.element_class(self._fmodule, 1, name=tensor._name, + latex_name=tensor._latex_name) + for frame, comp in tensor._components.items(): + resu._components[frame] = comp.copy() + return resu + else: + raise TypeError("cannot convert the {} ".format(tensor) + + "to an element of {}".format(self)) + resu = self.element_class(self._fmodule, self._degree, name=name, + latex_name=latex_name) + if comp != []: + resu.set_comp(frame)[:] = comp + return resu + + # Rem: _an_element_ is declared in the superclass ExtPowerFreeModule + + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A2 = M.multivector_module(2) + sage: U = M.open_subset('U', coord_def = {X: z<0}) + sage: A2U = U.multivector_module(2) + sage: A2U._coerce_map_from_(A2) + True + sage: A2._coerce_map_from_(A2U) + False + sage: A1 = M.multivector_module(1) + sage: A2U._coerce_map_from_(A1) + False + sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) + True + sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) + False + + """ + if isinstance(other, (MultivectorModule, MultivectorFreeModule)): + # coercion by domain restriction + return (self._degree == other._degree + and self._domain.is_subset(other._domain) + and self._ambient_domain.is_subset(other._ambient_domain)) + return False + + #### End of Parent methods + + def _repr_(self): + r""" + Return a string representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A = M.multivector_module(2) + sage: A + Free module A^2(M) of 2-vector fields on + the 3-dimensional differentiable manifold M + + """ + description = "Free module " + if self._name is not None: + description += self._name + " " + description += "of {}-vector fields ".format(self._degree) + if self._dest_map is self._domain.identity_map(): + description += "on the {}".format(self._domain) + else: + description += "along the {} mapped into the {}".format( + self._domain, self._ambient_domain) + return description + diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py new file mode 100644 index 00000000000..23242d4ced6 --- /dev/null +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -0,0 +1,746 @@ +r""" +Multivector Fields + +Let `U` and `M` be two differentiable manifolds. +Given a positive integer `p` and a differentiable map `\Phi: U \rightarrow M`, +a *multivector field of degree* `p`, or `p`-*vector field*, +*along* `U` *with values on* `M` is a field along `U` of alternating +contravariant tensors of rank `p` in the tangent spaces to `M`. +The standard case of a multivector field *on* a differentiable manifold +corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are +`\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open +interval of `\RR`). + +Two classes implement multivector fields, depending whether the manifold +`M` is parallelizable: + +* :class:`MultivectorFieldParal` when `M` is parallelizable +* :class:`MultivectorField` when `M` is not assumed parallelizable. + +AUTHORS: + +- Eric Gourgoulhon (2017): initial version + +REFERENCES: + +- C.-M. Marle (1997) + +""" + +#****************************************************************************** +# Copyright (C) 2017 Eric Gourgoulhon +# +# 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/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal + +class MultivectorField(TensorField): + r""" + Multivector field with values on a generic (i.e. a priori not + parallelizable) differentiable manifold. + + Given a differentiable manifold `U`, a differentiable map + `\Phi: U \rightarrow M` to a differentiable manifold `M` and a positive + integer `p`, a *multivector field of degree* `p` (or `p`-*vector field*) + *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map + + .. MATH:: + + a:\ U \longrightarrow T^{(p,0)}M + + (`T^{(p,0)}M` being the tensor bundle of type `(p,0)` over `M`) such that + + .. MATH:: + + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)} M) , + + where `T_{\Phi(x)} M` is the vector space tangent to `M` at `\Phi(x)` and + `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`). + In other words, `a(x)` is an alternating contravariant tensor of degree `p` + of the tangent vector space `T_{\Phi(x)} M`. + + The standard case of a multivector field *on* a manifold `M` corresponds to + `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an + immersion and `\Phi` being a curve in `M` (`U` is then an open interval of + `\RR`). + + .. NOTE:: + + If `M` is parallelizable, the class :class:`MultivectorFieldParal` + must be used instead. + + INPUT: + + - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector fields + along `U` with values on `M` via the map `\Phi` + - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + multivector field; if none is provided, the LaTeX symbol is set to + ``name`` + + EXAMPLES: + + Multivector field of degree 2 on a non-parallelizable 2-dimensional + manifold:: + + sage: M = Manifold(2, 'M') + 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+y, x-y), intersection_name='W', + ....: restrictions1= x>0, restrictions2= u+v>0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) + sage: eU = c_xy.frame() ; eV = c_uv.frame() + sage: a = M.multivector_field(2, name='a') ; a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.parent() + Module A^2(M) of 2-vector fields on the 2-dimensional differentiable + manifold M + sage: a.degree() + 2 + + Setting the components of ``a``:: + + sage: a[eU,0,1] = x*y^2 + 2*x + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: a.display(eU) + a = (x*y^2 + 2*x) dx/\dy + sage: a.display(eV) + a = (-1/16*u^3 + 1/16*u*v^2 - 1/16*v^3 + + 1/16*(u^2 - 8)*v - 1/2*u) du/\dv + + The exterior product of two vector fields is a 2-vector field:: + + sage: s = a.wedge(b) ; s + 2-vector field a/\b on the 2-dimensional differentiable manifold M + sage: s.display(eU) + a/\b = (-2*x^2*y - x) dx/\dy + sage: s.display(eV) + a/\b = (1/8*u^3 - 1/8*u*v^2 - 1/8*v^3 + 1/8*(u^2 + 2)*v + 1/4*u) du/\dv + + Multiplying a 2-vector field by a scalar field results in another + 2-vector field:: + + sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') + sage: s = f*s ; s + 2-vector field on the 2-dimensional differentiable manifold M + sage: s.display(eU) + (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy + sage: s.display(eV) + 1/2*u^2*v du - 1/2*u^3 dv + + """ + def __init__(self, vector_field_module, degree, name=None, latex_name=None): + r""" + Construct a multivector field. + + TESTS: + + Construction via ``parent.element_class``, and not via a direct call + to ``MultivectorField`, to fit with the category framework:: + + sage: M = Manifold(2, 'M') + 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+y, x-y), + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: A = M.multivector_module(2) + sage: XM = M.vector_field_module() + sage: a = A.element_class(XM, 2, name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a[e_xy,0,1] = x+y + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: TestSuite(a).run(skip='_test_pickling') + + Construction with ``DifferentiableManifold.multivector_field``:: + + sage: a1 = M.multivector_field(2, name='a'); a1 + 2-vector field a on the 2-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + .. TODO:: + + Fix ``_test_pickling`` (in the superclass :class:`TensorField`). + + """ + TensorField.__init__(self, vector_field_module, (degree, 0), name=name, + latex_name=latex_name, antisym=range(degree), + parent=vector_field_module.exterior_power(degree)) + self._init_derived() # initialization of derived quantities + + def _repr_(self): + r""" + String representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2, name='a') + sage: a._repr_() + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: repr(a) # indirect doctest + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: a # indirect doctest + 2-vector field a on the 3-dimensional differentiable manifold M + sage: b = M.multivector_field(2) + sage: b._repr_() + '2-vector field on the 3-dimensional differentiable manifold M' + + """ + description = "{}-vector field ".format(self._tensor_rank) + if self._name is not None: + description += self._name + " " + return self._final_repr(description) + + def _new_instance(self): + r""" + Create an instance of the same class, of the same degree and on the + same domain. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2, name='a') + sage: a1 = a._new_instance(); a1 + 2-vector field on the 3-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + return type(self)(self._vmodule, self._tensor_rank) + + def wedge(self, other): + r""" + Exterior product with another multivector field. + + INPUT: + + - ``other`` -- another multivector field (on the same manifold) + + OUTPUT: + + - a :class:`MultivectorField` of the exterior product ``self/\other`` + + EXAMPLES: + + Exterior product of two vector fields on the 2-sphere:: + + + sage: M = Manifold(2, 'S^2', start_index=1) # the 2-dimensional sphere S^2 + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # S^2 is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() # stereographic coord. (North and South) + 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: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.multivector_field(1, name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.multivector_field(1, name='b') + sage: b[e_xy,:] = x^2 + y^2, y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: c = a.wedge(b); c + 2-vector field a/\b on the 2-dimensional differentiable manifold S^2 + sage: c.display(e_xy) + a/\b = (-x^3 - (x - 1)*y^2) dx/\dy + sage: c.display(e_uv) + a/\b = -(v^2 - u)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du/\dv + + """ + from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(other._domain): + if not self._ambient_domain.is_subset(other._ambient_domain): + raise ValueError("incompatible ambient domains for exterior product") + elif other._domain.is_subset(self._domain): + if not other._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for exterior product") + dom_resu = self._domain.intersection(other._domain) + ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.wedge(self_r, other_r) + # otherwise, the result is created here: + if self._name is not None and other._name is not None: + sname = self._name + oname = other._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = sname + '/\\' + oname + if self._latex_name is not None and other._latex_name is not None: + slname = self._latex_name + olname = other._latex_name + if not is_atomic(slname): + slname = '(' + slname + ')' + if not is_atomic(olname): + olname = '(' + olname + ')' + resu_latex_name = slname + r'\wedge ' + olname + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = self._tensor_rank + other._tensor_rank + resu = vmodule.alternating_contravariant_tensor(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in other_r._restrictions: + resu._restrictions[dom] = self_r._restrictions[dom].wedge( + other_r._restrictions[dom]) + return resu + + def degree(self): + r""" + Return the degree of ``self``. + + OUTPUT: + + - integer `p` such that the multivector field is a `p`-vector field + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2); a + 2-vector field on the 3-dimensional differentiable manifold M + sage: a.degree() + 2 + sage: b = M.multivector_field(1); b + 1-vector field on the 3-dimensional differentiable manifold M + sage: b.degree() + 1 + + """ + return self._tensor_rank + + +#****************************************************************************** + +class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): + r""" + Multivector field with values on a parallelizable manifold. + + Given a differentiable manifold `U`, a differentiable map + `\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive + integer `p`, a *multivector field of degree* `p` (or `p`-*vector field*) + *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map + + .. MATH:: + + a:\ U \longrightarrow T^{(p,0)}M + + (`T^{(p,0)}M` being the tensor bundle of type `(p,0)` over `M`) such that + + .. MATH:: + + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)} M) , + + where `T_{\Phi(x)} M` is the vector space tangent to `M` at `\Phi(x)` and + `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`). + In other words, `a(x)` is an alternating contravariant tensor of degree `p` + of the tangent vector space `T_{\Phi(x)} M`. + + The standard case of a multivector field *on* a manifold `M` corresponds to + `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an + immersion and `\Phi` being a curve in `M` (`U` is then an open interval of + `\RR`). + + .. NOTE:: + + If `M` is not parallelizable, the class :class:`MultivectorField` must + be used instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + fields along `U` with values on `M` via the map `\Phi` + - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + multivector field; if none is provided, the LaTeX symbol is set to + ``name`` + + EXAMPLES: + + A 2-vector field on a 4-dimensional manifold:: + + sage: M = Manifold(4, 'M') + sage: c_txyz. = M.chart() + sage: a = M.multivector_field(2, 'a') ; a + 2-vector field a on the 4-dimensional differentiable manifold M + sage: a.parent() + Free module A^2(M) of 2-vector fields on the 4-dimensional differentiable + manifold M + + A multivector field is a tensor field of purely contravariant type:: + + sage: a.tensor_type() + (2, 0) + + It is antisymmetric, its components being + :class:`~sage.tensor.modules.comp.CompFullyAntiSym`:: + + sage: a.symmetries() + no symmetry; antisymmetry: (0, 1) + sage: a[0,1] = 2 + sage: a[1,0] + -2 + sage: a.comp() + Fully antisymmetric 2-indices components w.r.t. Coordinate frame (M, (d/dt,d/dx,d/dy,d/dz)) + sage: type(a.comp()) + + + Setting a component with repeated indices to a non-zero value results in + an error:: + + sage: a[1,1] = 3 + Traceback (most recent call last): + ... + ValueError: by antisymmetry, the component cannot have a nonzero value + for the indices (1, 1) + sage: a[1,1] = 0 # OK, albeit useless + sage: a[1,2] = 3 # OK + + The expansion of a multivector field with respect to a given frame is + displayed via the method + :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.display`:: + + sage: a.display() # expansion with respect to the default coframe (dt, dx, dy, dz) + a = 2 dt/\dx + 3 dx/\dy + sage: latex(a.display()) # output for the notebook + a = 2 \mathrm{d} t\wedge \mathrm{d} x + + 3 \mathrm{d} x\wedge \mathrm{d} y + + Multivector fields can be added or subtracted:: + + sage: b = M.multivector_field(2) + sage: b[0,1], b[0,2], b[0,3] = (1,2,3) + sage: s = a + b ; s + 2-vector field on the 4-dimensional differentiable manifold M + sage: a[:], b[:], s[:] + ( + [ 0 2 0 0] [ 0 1 2 3] [ 0 3 2 3] + [-2 0 3 0] [-1 0 0 0] [-3 0 3 0] + [ 0 -3 0 0] [-2 0 0 0] [-2 -3 0 0] + [ 0 0 0 0], [-3 0 0 0], [-3 0 0 0] + ) + sage: s = a - b ; s + 2-vector field on the 4-dimensional differentiable manifold M + sage: s[:] + [ 0 1 -2 -3] + [-1 0 3 0] + [ 2 -3 0 0] + [ 3 0 0 0] + + An example of 3-vector field in `\RR^3` oordinates:: + + sage: M = Manifold(3, 'R3', '\RR^3', start_index=1) + sage: c_cart. = M.chart() + sage: eps = M.multivector_field(3, 'epsilon', r'\epsilon') + sage: eps[1,2,3] = 1 # the only independent component + sage: eps[:] # all the components are set from the previous line: + [[[0, 0, 0], [0, 0, 1], [0, -1, 0]], [[0, 0, -1], [0, 0, 0], [1, 0, 0]], + [[0, 1, 0], [-1, 0, 0], [0, 0, 0]]] + sage: eps.display() + epsilon = dx/\dy/\dz + + Spherical components from the tensorial change-of-frame formula:: + + sage: c_spher. = M.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi') + sage: spher_to_cart = c_spher.transition_map(c_cart, + ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) + sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2), + ....: atan2(sqrt(x^2+y^2),z), atan2(y, x)) + sage: eps.comp(c_spher.frame()) # computation of the components in the spherical frame + Fully antisymmetric 3-indices components w.r.t. Coordinate frame + (R3, (d/dr,d/dth,d/dph)) + sage: eps.comp(c_spher.frame())[1,2,3, c_spher] + r^2*sin(th) + sage: eps.display(c_spher.frame()) + epsilon = sqrt(x^2 + y^2 + z^2)*sqrt(x^2 + y^2) dr/\dth/\dph + sage: eps.display(c_spher.frame(), c_spher) + epsilon = r^2*sin(th) dr/\dth/\dph + + The exterior product of two multivector fields is performed via the method + :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.wedge`:: + + sage: a = M.one_form('A') + sage: a[:] = (x*y*z, -z*x, y*z) + sage: b = M.one_form('B') + sage: b[:] = (cos(z), sin(x), cos(y)) + sage: ab = a.wedge(b) ; ab + 2-vector field A/\B on the 3-dimensional differentiable manifold R3 + sage: ab[:] + [ 0 x*y*z*sin(x) + x*z*cos(z) x*y*z*cos(y) - y*z*cos(z)] + [-x*y*z*sin(x) - x*z*cos(z) 0 -(x*cos(y) + y*sin(x))*z] + [-x*y*z*cos(y) + y*z*cos(z) (x*cos(y) + y*sin(x))*z 0] + sage: ab.display() + A/\B = (x*y*z*sin(x) + x*z*cos(z)) dx/\dy + (x*y*z*cos(y) - y*z*cos(z)) dx/\dz + - (x*cos(y) + y*sin(x))*z dy/\dz + + The tensor product of a vector field and a 2-vector field is not a 3-vector + field but a tensor field of type `(3,0)` with less symmetries:: + + sage: c = a*ab ; c + Tensor field A*(A/\B) of type (3,0) on the 3-dimensional differentiable + manifold R3 + sage: c.symmetries() # the antisymmetry is only w.r.t. the last two arguments: + no symmetry; antisymmetry: (1, 2) + sage: d = ab*a ; d + Tensor field (A/\B)*A of type (3,0) on the 3-dimensional differentiable + manifold R3 + sage: d.symmetries() # the antisymmetry is only w.r.t. the first two arguments: + no symmetry; antisymmetry: (0, 1) + + The Lie derivative of a 2-vector field is a 2-vector field:: + + sage: v = M.vector_field('v') + sage: v[:] = (y*z, -x*z, x*y) + sage: ab.lie_der(v) # long time + 2-vector field on the 3-dimensional differentiable manifold R3 + + The exterior product of two vector fields is a 2-vector field:: + + sage: d = a.wedge(b) ; d + 2-vector field A/\B on the 3-dimensional differentiable manifold R3 + sage: d[:] + [ 0 -7 -14] + [ 7 0 -7] + [ 14 7 0] + sage: d.symmetries() + no symmetry; antisymmetry: (0, 1) + + We can check the standard formula relating the exterior product to the + tensor product:: + + sage: a.wedge(b) == a*b - b*a + True + + """ + def __init__(self, vector_field_module, degree, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS: + + Construction via ``parent.element_class``, and not via a direct call + to ``MultivectorFieldParal``, to fit with the category framework:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: A = M.multivector_module(2) + sage: XM = M.vector_field_module() + sage: a = A.element_class(XM, 2, name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a[0,1] = x*y + sage: TestSuite(a).run() + + Construction via ``DifferentiableManifold.multivector_field``:: + + sage: a1 = M.multivector_field(2, name='a'); a1 + 2-vector field a on the 2-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + AlternatingContrTensor.__init__(self, vector_field_module, degree, + name=name, latex_name=latex_name) + # TensorFieldParal attributes: + self._vmodule = vector_field_module + self._domain = vector_field_module._domain + self._ambient_domain = vector_field_module._ambient_domain + # initialization of derived quantities: + self._init_derived() + + def _repr_(self): + r""" + String representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._repr_() + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: repr(a) # indirect doctest + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: a # indirect doctest + 2-vector field a on the 3-dimensional differentiable manifold M + sage: b = M.multivector_field(2) + sage: b._repr_() + '2-vector field on the 3-dimensional differentiable manifold M' + + """ + description = "{}-vector field ".format(self._tensor_rank) + if self._name is not None: + description += self._name + " " + return self._final_repr(description) + + def _new_instance(self): + r""" + Create an instance of the same class, of the same degree and on the + same domain. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a1 = a._new_instance(); a1 + 2-vector field on the 3-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + return type(self)(self._fmodule, self._tensor_rank) + + # This method is needed to redirect to the correct class (TensorFieldParal) + def _init_derived(self): + r""" + Initialize the derived quantities of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._init_derived() + + """ + TensorFieldParal._init_derived(self) + + def _del_derived(self, del_restrictions=True): + r""" + Delete the derived quantities. + + INPUT: + + - ``del_restrictions`` -- (default: ``True``) determines whether the + restrictions of ``self`` to subdomains are deleted + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._del_derived() + + """ + TensorFieldParal._del_derived(self, del_restrictions=del_restrictions) + + def __call__(self, *args): + r""" + Redefinition of + :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__call__` + to allow for domain treatment. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: a = M.multivector_field(2, name='a') + sage: a[0,1] = x*y + sage: a.display() + a = x*y dx/\dy + sage: u = M.vector_field(name='u') + sage: u[:] = [1+x, 2-y] + sage: v = M.vector_field(name='v') + sage: v[:] = [-y, x] + sage: s = a.__call__(u,v); s + Scalar field a(u,v) on the 2-dimensional differentiable manifold M + sage: s.display() + a(u,v): M --> R + (x, y) |--> -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y + sage: s == a[[0,1]]*(u[[0]]*v[[1]] -u[[1]]*v[[0]]) + True + sage: s == a(u,v) # indirect doctest + True + + """ + return TensorFieldParal.__call__(self, *args) + + def wedge(self, other): + r""" + Exterior product of ``self`` with another multivector field. + + INPUT: + + - ``other`` -- another multivector field + + OUTPUT: + + - instance of :class:`MultivectorFieldParal` representing the exterior + product ``self/\other`` + + EXAMPLES: + + Exterior product of a vector field and a 2-vector field on a + 3-dimensional manifold:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: X. = M.chart() + sage: a = M.one_form(name='a') + sage: a[:] = [2, 1+x, y*z] + sage: b = M.multivector_field(2, name='b') + sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, z^2 + sage: a.display() + a = 2 dx + (x + 1) dy + y*z dz + sage: b.display() + b = y^2 dx/\dy + (x + z) dx/\dz + z^2 dy/\dz + sage: s = a.wedge(b); s + 3-vector field a/\b on the 3-dimensional differentiable manifold M + sage: s.display() + a/\b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) dx/\dy/\dz + + Check:: + + sage: s[1,2,3] == a[1]*b[2,3] + a[2]*b[3,1] + a[3]*b[1,2] + True + + """ + from sage.tensor.modules.alternating_contr_tensor import \ + AlternatingContrTensor + if self._domain.is_subset(other._domain): + if not self._ambient_domain.is_subset(other._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + elif other._domain.is_subset(self._domain): + if not other._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + return AlternatingContrTensor.wedge(self_r, other_r) From fd4d5f4082e86d696fca0bf88e4e0231c775685d Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 11 Jul 2017 00:26:11 +0200 Subject: [PATCH 008/218] More code regarding multivector fields on manifolds (work in progress) --- src/sage/manifolds/differentiable/manifold.py | 231 +++++++++-- .../differentiable/multivector_module.py | 306 ++++++++------- .../differentiable/tensorfield_module.py | 134 +++++-- .../differentiable/vectorfield_module.py | 370 ++++++++++++++---- 4 files changed, 750 insertions(+), 291 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index ed670890b36..61c97e45077 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -1277,12 +1277,12 @@ def diff_form_module(self, degree, dest_map=None): sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: M.diff_form_module(2) - Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable - manifold M + Free module Omega^2(M) of 2-forms on the 3-dimensional + differentiable manifold M sage: M.diff_form_module(2).category() Category of finite dimensional modules over Algebra of - differentiable scalar fields on the 3-dimensional differentiable - manifold M + differentiable scalar fields on the 3-dimensional + differentiable manifold M sage: M.diff_form_module(2).base_ring() Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold M @@ -1297,6 +1297,66 @@ def diff_form_module(self, degree, dest_map=None): """ return self.vector_field_module(dest_map=dest_map).dual_exterior_power(degree) + def multivector_module(self, degree, dest_map=None): + r""" + Return the set of multivector fields of a given degree defined + on ``self``, possibly with values in another manifold, as a + module over the algebra of scalar fields defined on ``self``. + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + for complete documentation. + + INPUT: + + - ``degree`` -- positive integer; the degree `p` of the + multivector fields + - ``dest_map`` -- (default: ``None``) destination map, i.e. a + differentiable map `\Phi:\ M \rightarrow N`, where `M` is the + current manifold and `N` a differentiable manifold; + if ``None``, it is assumed that `N = M` and that `\Phi` is the + identity map (case of multivector fields *on* `M`), otherwise + ``dest_map`` must be a + :class:`~sage.manifolds.differentiable.diff_map.DiffMap` + + OUTPUT: + + - a + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + (or if `N` is parallelizable, a + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule`) + representing the module `\Omega^p(M,\Phi)` of `p`-forms on `M` + taking values on `\Phi(M)\subset N` + + EXAMPLES: + + Module of 2-vector fields on a 3-dimensional parallelizable + manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: M.multivector_module(2) + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).category() + Category of finite dimensional modules over Algebra of + differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).base_ring() + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).rank() + 3 + + The outcome is cached:: + + sage: M.multivector_module(2) is M.multivector_module(2) + True + + """ + return self.vector_field_module(dest_map=dest_map).exterior_power(degree) + def automorphism_field_group(self, dest_map=None): r""" Return the group of tangent-space automorphism fields defined on @@ -1689,6 +1749,91 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` return self.tensor_field(0, 2, name=name, latex_name=latex_name, sym=(0,1)) + def multivector_field(self, degree, name=None, latex_name=None, + dest_map=None): + r""" + Define a multivector field on ``self``. + + Via the argument ``dest_map``, it is possible to let the + multivector field take its values on another manifold. More + precisely, if `M` is the current manifold, `N` a differentiable + manifold, `\Phi:\ M \rightarrow N` a differentiable map and `p` + a non-negative integer, a *multivector field of degree* `p` (or + `p`-*vector field*) *along* `M` *with values on* `N` is a + differentiable map + + .. MATH:: + + t:\ M \longrightarrow T^{(p,0)} N + + (`T^{(p,0)} N` being the tensor bundle of type `(p,0)` over `N`) + such that + + .. MATH:: + + \forall x \in M,\quad t(x) \in \Lambda^p(T_{\Phi(x)} N), + + where `\Lambda^p(T_{\Phi(x)} N)` is the `p`-th exterior power + of the tangent vector space `T_{\Phi(x)} N`. + + The standard case of a `p`-vector field *on* `M` corresponds + to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `N` (`M` + is then an open interval of `\RR`). + + For `p = 1`, one can use the method + :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.vector_field` + instead. + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for complete documentation. + + INPUT: + + - ``degree`` -- the degree `p` of the multivector field (i.e. + its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector + field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the multivector field; if none is provided, the LaTeX symbol + is set to ``name`` + - ``dest_map`` -- (default: ``None``) the destination map + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a + multivector field *on* `M`), otherwise ``dest_map`` must be a + :class:`~sage.manifolds.differentiable.diff_map.DiffMap` + + OUTPUT: + + - the `p`-vector field as a + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + (or if `N` is parallelizable, a + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`) + + EXAMPLES: + + A 2-vector field on a open subset of a 4-dimensional + differentiable manifold:: + + sage: M = Manifold(4, 'M') + sage: A = M.open_subset('A', latex_name=r'\mathcal{A}'); A + Open subset A of the 4-dimensional differentiable manifold M + sage: c_xyzt. = A.chart() + sage: h = A.multivector_field(2, 'H'); h + 2-vector field h on the Open subset A of the 4-dimensional + differentiable manifold M + + See the documentation of class + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for more examples. + + """ + vmodule = self.vector_field_module(dest_map) + return vmodule.alternating_contravariant_tensor(degree, + name=name, latex_name=latex_name) + def diff_form(self, degree, name=None, latex_name=None, dest_map=None): r""" @@ -1699,7 +1844,8 @@ def diff_form(self, degree, name=None, latex_name=None, precisely, if `M` is the current manifold, `N` a differentiable manifold, `\Phi:\ M \rightarrow N` a differentiable map and `p` a non-negative integer, a *differential form of degree* `p` (or - `p`-form) *along* `M` *with values on* `N` is a differentiable map + `p`-*form*) *along* `M` *with values on* `N` is a differentiable + map .. MATH:: @@ -1710,15 +1856,15 @@ def diff_form(self, degree, name=None, latex_name=None, .. MATH:: - \forall x \in M,\ t(x) \in \Lambda^p(T^*_{\Phi(x)} N), + \forall x \in M,\quad t(x) \in \Lambda^p(T^*_{\Phi(x)} N), where `\Lambda^p(T^*_{\Phi(x)} N)` is the `p`-th exterior power of the dual of the tangent space `T_{\Phi(x)} N`. The standard case of a differential form *on* `M` corresponds - to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` - being an immersion and `\Phi` being a curve in `N` (`M` is then - an open interval of `\RR`). + to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `N` (`M` + is then an open interval of `\RR`). For `p = 1`, one can use the method :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.one_form` @@ -1726,21 +1872,22 @@ def diff_form(self, degree, name=None, latex_name=None, .. SEEALSO:: - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for - complete documentation. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + for complete documentation. INPUT: - - ``degree`` -- the degree `p` of the differential form (i.e. its - tensor rank) - - ``name`` -- (default: ``None``) name given to the differential form - - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the - differential form; if none is provided, the LaTeX symbol is set to - ``name`` + - ``degree`` -- the degree `p` of the differential form (i.e. + its tensor rank) + - ``name`` -- (default: ``None``) name given to the differential + form + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the differential form; if none is provided, the LaTeX symbol + is set to ``name`` - ``dest_map`` -- (default: ``None``) the destination map - `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that `N = M` - and that `\Phi` is the identity map (case of a differential - form *on* `M`), otherwise ``dest_map`` must be a + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a + differential form *on* `M`), otherwise ``dest_map`` must be a :class:`~sage.manifolds.differentiable.diff_map.DiffMap` OUTPUT: @@ -1752,19 +1899,20 @@ def diff_form(self, degree, name=None, latex_name=None, EXAMPLES: - A 2-form on a open subset of a 4-dimensional differentiable manifold:: + A 2-form on a open subset of a 4-dimensional differentiable + manifold:: sage: M = Manifold(4, 'M') sage: A = M.open_subset('A', latex_name=r'\mathcal{A}'); A Open subset A of the 4-dimensional differentiable manifold M sage: c_xyzt. = A.chart() sage: f = A.diff_form(2, 'F'); f - 2-form F on the Open subset A of the 4-dimensional differentiable - manifold M + 2-form F on the Open subset A of the 4-dimensional + differentiable manifold M See the documentation of class - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for more - examples. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for + more examples. """ vmodule = self.vector_field_module(dest_map) @@ -1779,7 +1927,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): 1-form take its values on another manifold. More precisely, if `M` is the current manifold, `N` a differentiable manifold and `\Phi:\ M \rightarrow N` a differentiable map, - a *1-form along* `M` *with values on* `N` is a differentiable map + a *1-form along* `M` *with values on* `N` is a differentiable + map .. MATH:: @@ -1789,9 +1938,10 @@ def one_form(self, name=None, latex_name=None, dest_map=None): .. MATH:: - \forall p \in M,\ t(p) \in T^*_{\Phi(p)}N, + \forall p \in M,\quad t(p) \in T^*_{\Phi(p)}N, - where `T^*_{\Phi(p)}` is the dual of the tangent space `T_{\Phi(p)} N`. + where `T^*_{\Phi(p)}` is the dual of the tangent space + `T_{\Phi(p)} N`. The standard case of a 1-form *on* `M` corresponds to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` @@ -1800,18 +1950,19 @@ def one_form(self, name=None, latex_name=None, dest_map=None): .. SEEALSO:: - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for - complete documentation. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + for complete documentation. INPUT: - ``name`` -- (default: ``None``) name given to the 1-form - - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the - 1-form; if none is provided, the LaTeX symbol is set to ``name`` + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the 1-form; if none is provided, the LaTeX symbol is set to + ``name`` - ``dest_map`` -- (default: ``None``) the destination map - `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that `N = M` - and that `\Phi` is the identity map (case of a 1-form *on* `M`), - otherwise ``dest_map`` must be a + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a 1-form + *on* `M`), otherwise ``dest_map`` must be a :class:`~sage.manifolds.differentiable.diff_map.DiffMap` OUTPUT: @@ -1832,8 +1983,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): 1-form omega on the Open subset A of the 3-dimensional differentiable manifold M sage: om.parent() - Free module Omega^1(A) of 1-forms on the Open subset A of the - 3-dimensional differentiable manifold M + Free module Omega^1(A) of 1-forms on the Open subset A of + the 3-dimensional differentiable manifold M .. SEEALSO:: @@ -1844,7 +1995,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): vmodule = self.vector_field_module(dest_map) return vmodule.linear_form(name=name, latex_name=latex_name) - def automorphism_field(self, name=None, latex_name=None, dest_map=None): + def automorphism_field(self, name=None, latex_name=None, + dest_map=None): r""" Define a field of automorphisms (invertible endomorphisms in each tangent space) on ``self``. @@ -1921,7 +2073,8 @@ def automorphism_field(self, name=None, latex_name=None, dest_map=None): vmodule = self.vector_field_module(dest_map) return vmodule.automorphism(name=name, latex_name=latex_name) - def tangent_identity_field(self, name='Id', latex_name=None, dest_map=None): + def tangent_identity_field(self, name='Id', latex_name=None, + dest_map=None): r""" Return the field of identity maps in the tangent spaces on ``self``. diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index b0cad66be59..2ec71b2f7eb 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -1,15 +1,16 @@ r""" Multivector fields Modules -The set `A^p(U, \Phi)` of `p`-vector fields along a differentiable manifold `U` -with values on a differentiable manifold `M` via a differentiable map -`\Phi:\ U \rightarrow M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`) -is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`. -It is a free module if and only if `M` is parallelizable. Accordingly, -two classes implement `A^p(U, \Phi)`: - -- :class:`MultivectorModule` for `p`-vector fields with values on a generic - (in practice, not parallelizable) differentiable manifold `M` +The set `A^p(U, \Phi)` of `p`-vector fields along a differentiable +manifold `U` with values on a differentiable manifold `M` via a +differentiable map `\Phi:\ U \rightarrow M` (possibly `U = M` and +`\Phi = \mathrm{Id}_M`) is a module over the algebra `C^k(U)` of +differentiable scalar fields on `U`. It is a free module if and only if +`M` is parallelizable. Accordingly, two classes implement +`A^p(U,\Phi)`: + +- :class:`MultivectorModule` for `p`-vector fields with values on a + generic (in practice, not parallelizable) differentiable manifold `M` - :class:`MultivectorFreeModule` for `p`-vector fields with values on a parallelizable manifold `M` @@ -36,51 +37,54 @@ from sage.structure.parent import Parent from sage.categories.modules import Modules from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule -from sage.manifolds.differentiable.multivectorfield import (MultivectorField, - MultivectorFieldParal) -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, MultivectorFieldParal) class MultivectorModule(UniqueRepresentation, Parent): r""" - Module of multivector fields of a given degree `p` (`p`-vector fields) - along a differentiable manifold `U` with values on a differentiable - manifold `M`. + Module of multivector fields of a given degree `p` (`p`-vector + fields) along a differentiable manifold `U` with values on a + differentiable manifold `M`. Given a differentiable manifold `U` and a differentiable map `\Phi: U \rightarrow M` to a differentiable manifold `M`, the set - `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields of type - `(p,0)`) along `U` with values on `M` is a module over `C^k(U)`, the - commutative algebra of differentiable scalar fields on `U` (see + `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields + of type `(p,0)`) along `U` with values on `M` is a module over + `C^k(U)`, the commutative algebra of differentiable scalar fields on + `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). - The standard case of `p`-vector fields *on* a differentiable manifold `M` - corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases - are `\Phi` being an immersion and `\Phi` being a curve in `M` - (`U` is then an open interval of `\RR`). + The standard case of `p`-vector fields *on* a differentiable + manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. + Other common cases are `\Phi` being an immersion and `\Phi` being a + curve in `M` (`U` is then an open interval of `\RR`). .. NOTE:: This class implements `A^p(U,\Phi)` in the case where `M` is not assumed to be parallelizable; the module `A^p(U, \Phi)` - is then not necessarily free. If `M` is parallelizable, the class - :class:`MultivectorFreeModule` must be used instead. + is then not necessarily free. If `M` is parallelizable, the + class :class:`MultivectorFreeModule` must be used instead. INPUT: - ``vector_field_module`` -- module `\mathcal{X}(U, \Phi)` of vector - fields along `U` with values on `M` via the map `\Phi: U \rightarrow M` - - ``degree`` -- positive integer; the degree `p` of the multivector fields + fields along `U` with values on `M` via the map + `\Phi: U \rightarrow M` + - ``degree`` -- positive integer; the degree `p` of the multivector + fields EXAMPLES: - Module of 2-vector fields on a non-parallelizable 2-dimensional manifold:: + Module of 2-vector fields on a non-parallelizable 2-dimensional + manifold:: sage: M = Manifold(2, 'M') 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: transf = c_xy.transition_map(c_uv, (x+y, x-y), - ....: intersection_name='W', restrictions1= x>0, restrictions2= u+v>0) + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() @@ -88,8 +92,8 @@ class MultivectorModule(UniqueRepresentation, Parent): Module X(M) of vector fields on the 2-dimensional differentiable manifold M sage: A = M.multivector_module(2) ; A - Module A^2(M) of 2-vector fields on the 2-dimensional differentiable - manifold M + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M sage: latex(A) A^{2}\left(M\right) @@ -108,8 +112,8 @@ class MultivectorModule(UniqueRepresentation, Parent): scalar fields on `M`:: sage: A.category() - Category of modules over Algebra of differentiable scalar fields on - the 2-dimensional differentiable manifold M + Category of modules over Algebra of differentiable scalar fields + on the 2-dimensional differentiable manifold M sage: CM = M.scalar_field_algebra() ; CM Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold M @@ -123,11 +127,12 @@ class MultivectorModule(UniqueRepresentation, Parent): sage: A.base_module() is XM True - Elements can be constructed from ``A()``. In particular, ``0`` yields - the zero element of ``A``:: + Elements can be constructed from ``A()``. In particular, ``0`` + yields the zero element of ``A``:: sage: z = A(0) ; z - 2-vector field zero on the 2-dimensional differentiable manifold M + 2-vector field zero on the 2-dimensional differentiable + manifold M sage: z.display(eU) zero = 0 sage: z.display(eV) @@ -135,27 +140,28 @@ class MultivectorModule(UniqueRepresentation, Parent): sage: z is A.zero() True - while non-zero elements are constructed by providing their components in a - given vector frame:: + while non-zero elements are constructed by providing their + components in a given vector frame:: sage: a = A([[0,3*x],[-3*x,0]], frame=eU, name='a') ; a 2-vector field a on the 2-dimensional differentiable manifold M sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes initializ. of a sage: a.display(eU) - a = 3*x dx/\dy + a = 3*x d/dx/\d/dy sage: a.display(eV) - a = (-3/4*u - 3/4*v) du/\dv + a = (-3*u - 3*v) d/du/\d/dv - An alternative is to construct the 2-vector field from an empty list of - components and to set the nonzero nonredundant components afterwards:: + An alternative is to construct the 2-vector field from an empty list + of components and to set the nonzero nonredundant components + afterwards:: sage: a = A([], name='a') sage: a[eU,0,1] = 3*x sage: a.add_comp_by_continuation(eV, W, c_uv) sage: a.display(eU) - a = 3*x dx/\dy + a = 3*x d/dx/\d/dy sage: a.display(eV) - a = (-3/4*u - 3/4*v) du/\dv + a = (-3*u - 3*v) d/du/\d/dv The module `A^1(M)` is nothing but the dual of `\mathcal{X}(M)` (the module of vector fields on `M`):: @@ -170,14 +176,14 @@ class MultivectorModule(UniqueRepresentation, Parent): `A^p(M)\rightarrow T^{(p,0)}(M)`:: sage: T20 = M.tensor_field_module((2,0)) ; T20 - Module T^(2,0)(M) of type-(2,0) tensors fields on the 2-dimensional - differentiable manifold M + Module T^(2,0)(M) of type-(2,0) tensors fields on the + 2-dimensional differentiable manifold M sage: T20.has_coerce_map_from(A) True but of course not in the reverse direction:: - sage: A.has_coerce_map_from(T02) + sage: A.has_coerce_map_from(T20) False The coercion map `A^2(M) \rightarrow T^{(2,0)}(M)` in action:: @@ -186,20 +192,20 @@ class MultivectorModule(UniqueRepresentation, Parent): Tensor field a of type (2,0) on the 2-dimensional differentiable manifold M sage: ta.display(eU) - a = 3*x dx*dy - 3*x dy*dx + a = 3*x d/dx*d/dy - 3*x d/dy*d/dx sage: a.display(eU) - a = 3*x dx/\dy + a = 3*x d/dx/\d/dy sage: ta.display(eV) - a = (-3/4*u - 3/4*v) du*dv + (3/4*u + 3/4*v) dv*du + a = (-3*u - 3*v) d/du*d/dv + (3*u + 3*v) d/dv*d/du sage: a.display(eV) - a = (-3/4*u - 3/4*v) du/\dv + a = (-3*u - 3*v) d/du/\d/dv - There is also coercion to subdomains, which is nothing but the restriction - of the multivector field to some subset of its domain:: + There is also coercion to subdomains, which is nothing but the + restriction of the multivector field to some subset of its domain:: sage: A2U = U.multivector_module(2) ; A2U - Free module A^2(U) of 2-vector fields on the Open subset U of the - 2-dimensional differentiable manifold M + Free module A^2(U) of 2-vector fields on the Open subset U of + the 2-dimensional differentiable manifold M sage: A2U.has_coerce_map_from(A) True sage: a_U = A2U(a) ; a_U @@ -225,25 +231,26 @@ def __init__(self, vector_field_module, degree): sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy. = U.chart() ; c_uv. = V.chart() sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), - ....: intersection_name='W', restrictions1= x>0, - ....: restrictions2= u+v>0) + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) sage: inv = transf.inverse() sage: from sage.manifolds.differentiable.multivector_module import \ - ....: MultivectorModule + ....: MultivectorModule sage: A = MultivectorModule(M.vector_field_module(), 2) ; A Module A^2(M) of 2-vector fields on the 2-dimensional differentiable manifold M sage: TestSuite(A).run(skip='_test_elements') - In the above test suite, ``_test_elements`` is skipped because of the - ``_test_pickling`` error of the elements (to be fixed in + In the above test suite, ``_test_elements`` is skipped because + of the ``_test_pickling`` error of the elements (to be fixed in :class:`sage.manifolds.differentialbe.tensorfield.TensorField`) """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map name = "A^{}(".format(degree) + domain._name - latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) + latex_name = r"A^{{{}}}\left({}".format(degree, + domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -254,15 +261,17 @@ def __init__(self, vector_field_module, degree): self._degree = degree self._name = name self._latex_name = latex_name - # the member self._ring is created for efficiency (to avoid calls to - # self.base_ring()): + # the member self._ring is created for efficiency (to avoid + # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() - Parent.__init__(self, base=self._ring, category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, + category=Modules(self._ring)) self._domain = domain self._dest_map = dest_map self._ambient_domain = vector_field_module._ambient_domain - # NB: self._zero_element is not constructed here, since no element - # can be constructed here, to avoid some infinite recursion. + # NB: self._zero_element is not constructed here, since no + # element can be constructed here, to avoid some infinite + # recursion. #### Parent methods @@ -279,7 +288,8 @@ def _element_constructor_(self, comp=[], frame=None, name=None, sage: M.declare_union(U,V) sage: A = M.multivector_module(2) sage: a = A([[0, x*y], [-x*y, 0]], name='a'); a - 2-vector field a on the 2-dimensional differentiable manifold M + 2-vector field a on the 2-dimensional differentiable + manifold M sage: a.display(c_xy.frame()) a = x*y dx/\dy sage: A(0) is A.zero() @@ -290,16 +300,17 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[1] + if (self._degree == comp._tensor_type[0] and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._ambient_domain.is_subset( + comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._vmodule, self._degree, + name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -316,7 +327,8 @@ def _an_element_(self): sage: M.declare_union(U,V) sage: A = M.multivector_module(2) sage: A._an_element_() - 2-vector field on the 2-dimensional differentiable manifold M + 2-vector field on the 2-dimensional differentiable + manifold M """ resu = self.element_class(self._vmodule, self._degree) @@ -324,10 +336,11 @@ def _an_element_(self): open_covers = self._domain.open_covers()[1:] # the open cover 0 # is trivial if open_covers != []: - oc = open_covers[0] # the first non-trivial open cover is selected + oc = open_covers[0] # the first non-trivial open cover is + # selected for dom in oc: vmodule_dom = dom.vector_field_module( - dest_map=self._dest_map.restrict(dom)) + dest_map=self._dest_map.restrict(dom)) dmodule_dom = vmodule_dom.exterior_power(self._degree) resu.set_restriction(dmodule_dom._an_element_()) return resu @@ -339,11 +352,8 @@ def _coerce_map_from_(self, other): TESTS:: sage: M = Manifold(3, 'M') - sage: A1 = M.multivector_module(1) - sage: A1._coerce_map_from_(M.tensor_field_module((0,1))) - True sage: A2 = M.multivector_module(2) - sage: A2._coerce_map_from_(M.tensor_field_module((0,2))) + sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) False sage: U = M.open_subset('U') sage: A2U = U.multivector_module(2) @@ -357,7 +367,8 @@ def _coerce_map_from_(self, other): # coercion by domain restriction return (self._degree == other._degree and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + and self._ambient_domain.is_subset( + other._ambient_domain)) return False @cached_method @@ -370,11 +381,12 @@ def zero(self): sage: M = Manifold(3, 'M') sage: A2 = M.multivector_module(2) sage: A2.zero() - 2-vector field zero on the 3-dimensional differentiable manifold M + 2-vector field zero on the 3-dimensional differentiable + manifold M """ - zero = self.element_class(self._vmodule, self._degree, name='zero', - latex_name='0') + zero = self.element_class(self._vmodule, self._degree, + name='zero', latex_name='0') zero = self._element_constructor_(name='zero', latex_name='0') for frame in self._domain._frames: if self._dest_map.restrict(frame._domain) == frame._dest_map: @@ -405,7 +417,7 @@ def _repr_(self): description += "on the {}".format(self._domain) else: description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + elf._domain, self._ambient_domain) return description def _latex_(self): @@ -429,15 +441,15 @@ def _latex_(self): def base_module(self): r""" - Return the vector field module on which the multivector field module - is constructed. + Return the vector field module on which the multivector field + module is constructed. OUTPUT: - a :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` - representing the module on which the multivector field module is - defined + representing the module on which the multivector field module + is defined EXAMPLES:: @@ -446,8 +458,8 @@ def base_module(self): Module A^2(M) of 2-vector fields on the 3-dimensional differentiable manifold M sage: A2.base_module() - Module X(M) of vector fields on the 3-dimensional differentiable - manifold M + Module X(M) of vector fields on the 3-dimensional + differentiable manifold M sage: A2.base_module() is M.vector_field_module() True sage: U = M.open_subset('U') @@ -482,55 +494,59 @@ def degree(self): """ return self._degree -#****************************************************************************** +#*********************************************************************** class MultivectorFreeModule(ExtPowerFreeModule): r""" - Free module of multivector fields of a given degree `p` (`p`-vector fields) - along a differentiable manifold `U` with values on a parallelizable - manifold `M`. + Free module of multivector fields of a given degree `p` (`p`-vector + fields) along a differentiable manifold `U` with values on a + parallelizable manifold `M`. Given a differentiable manifold `U` and a differentiable map `\Phi:\; U \rightarrow M` to a parallelizable manifold `M`, the set - `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields of type - `(p,0)`) along `U` with values on `M` is a module over `C^k(U)`, the - commutative algebra of differentiable scalar fields on `U` (see + `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields + of type `(p,0)`) along `U` with values on `M` is a module over + `C^k(U)`, the commutative algebra of differentiable scalar fields + on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). - The standard case of `p`-vector fields *on* a differentiable manifold `M` - corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are - `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an - open interval of `\RR`). + The standard case of `p`-vector fields *on* a differentiable + manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. + Other common cases are `\Phi` being an immersion and `\Phi` being a + curve in `M` (`U` is then an open interval of `\RR`). .. NOTE:: This class implements `A^p(U, \Phi)` in the case where `M` is - parallelizable; `A^p(U, \Phi)` is then a *free* module. If `M` is not - parallelizable, the class :class:`MultivectorModule` must be used - instead. + parallelizable; `A^p(U, \Phi)` is then a *free* module. If `M` + is not parallelizable, the class :class:`MultivectorModule` must + be used instead. INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector - fields along `U` associated with the map `\Phi: U \rightarrow V` - - ``degree`` -- positive integer; the degree `p` of the multivector fields + - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of + vector fields along `U` associated with the map + `\Phi: U \rightarrow V` + - ``degree`` -- positive integer; the degree `p` of the multivector + fields EXAMPLES: - Free module of 2-vector fields on a parallelizable 3-dimensional manifold:: + Free module of 2-vector fields on a parallelizable 3-dimensional + manifold:: sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: XM = M.vector_field_module() ; XM - Free module X(M) of vector fields on the 3-dimensional differentiable - manifold M + Free module X(M) of vector fields on the 3-dimensional + differentiable manifold M sage: A = M.multivector_module(2) ; A Free module A^2(M) of 2-vector fields on the 3-dimensional differentiable manifold M sage: latex(A) A^{2}\left(M\right) - ``A`` is nothing but the second exterior power of ``XM``, i.e. we have - `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see + ``A`` is nothing but the second exterior power of ``XM``, i.e. we + have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`):: sage: A is XM.exterior_power(2) @@ -540,8 +556,9 @@ class MultivectorFreeModule(ExtPowerFreeModule): scalar fields on `M`:: sage: A.category() - Category of finite dimensional modules over Algebra of differentiable - scalar fields on the 3-dimensional differentiable manifold M + Category of finite dimensional modules over Algebra of + differentiable scalar fields on the 3-dimensional + differentiable manifold M sage: CM = M.scalar_field_algebra() ; CM Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold M @@ -562,12 +579,13 @@ class MultivectorFreeModule(ExtPowerFreeModule): the zero element of `A`:: sage: A(0) - 2-vector field zero on the 3-dimensional differentiable manifold M + 2-vector field zero on the 3-dimensional differentiable + manifold M sage: A(0) is A.zero() True - while non-zero elements are constructed by providing their components - in a given vector frame:: + while non-zero elements are constructed by providing their + components in a given vector frame:: sage: comp = [[0,3*x,-z],[-3*x,0,4],[z,-4,0]] sage: a = A(comp, frame=X.frame(), name='a') ; a @@ -575,8 +593,9 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: a.display() a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz - An alternative is to construct the 2-vector field from an empty list of - components and to set the nonzero nonredundant components afterwards:: + An alternative is to construct the 2-vector field from an empty list + of components and to set the nonzero nonredundant components + afterwards:: sage: a = A([], name='a') sage: a[0,1] = 3*x # component in the manifold's default frame @@ -585,12 +604,12 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: a.display() a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz - The module `A^1(M)` is nothing but `\mathcal{X}(M)` (the free module of - vector fields on `M`):: + The module `A^1(M)` is nothing but `\mathcal{X}(M)` (the free module + of vector fields on `M`):: sage: A1 = M.multivector_module(1) ; A1 - Free module X(M) of vector fields on the 3-dimensional differentiable - manifold M + Free module X(M) of vector fields on the 3-dimensional + differentiable manifold M sage: A1 is XM True @@ -650,17 +669,20 @@ def __init__(self, vector_field_module, degree): sage: M = Manifold(3, 'M') sage: X. = M.chart() - sage: from sage.manifolds.differentiable.multivector_module import MultivectorFreeModule - sage: A = MultivectorFreeModule(M.vector_field_module(), 2) ; A - Free module A^2(M) of 2-vector fields on - the 3-dimensional differentiable manifold M + sage: from sage.manifolds.differentiable.multivector_module \ + ....: import MultivectorFreeModule + sage: A = MultivectorFreeModule(M.vector_field_module(), 2) + sage: A + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M sage: TestSuite(A).run() """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map name = "A^{}(".format(degree) + domain._name - latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) + latex_name = r"A^{{{}}}\left({}".format(degree, + domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -686,7 +708,8 @@ def _element_constructor_(self, comp=[], frame=None, name=None, sage: X. = M.chart() # makes M parallelizable sage: A = M.multivector_module(2) sage: a = A([[0, x], [-x, 0]], name='a'); a - 2-vector field a on the 2-dimensional differentiable manifold M + 2-vector field a on the 2-dimensional differentiable + manifold M sage: a.display() a = x dx/\dy sage: A(0) is A.zero() @@ -697,29 +720,18 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[1] + if (self._degree == comp._tensor_type[0] and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._ambient_domain.is_subset( + comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {} ".format(comp) + "to a multivector field in {}".format(self)) - if isinstance(comp, TensorFieldParal): - # coercion of a tensor of type (0,1) to a linear form - tensor = comp # for readability - if (tensor.tensor_type() == (0,1) and self._degree == 1 - and tensor._fmodule is self._fmodule): - resu = self.element_class(self._fmodule, 1, name=tensor._name, - latex_name=tensor._latex_name) - for frame, comp in tensor._components.items(): - resu._components[frame] = comp.copy() - return resu - else: - raise TypeError("cannot convert the {} ".format(tensor) + - "to an element of {}".format(self)) + # standard construction resu = self.element_class(self._fmodule, self._degree, name=name, latex_name=latex_name) - if comp != []: + if comp: resu.set_comp(frame)[:] = comp return resu @@ -753,7 +765,8 @@ def _coerce_map_from_(self, other): # coercion by domain restriction return (self._degree == other._degree and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + and self._ambient_domain.is_subset( + other._ambient_domain)) return False #### End of Parent methods @@ -780,6 +793,5 @@ def _repr_(self): description += "on the {}".format(self._domain) else: description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + self._domain, self._ambient_domain) return description - diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 2d49db9d1dd..02e78b11b10 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -44,7 +44,10 @@ from sage.tensor.modules.tensor_free_module import TensorFreeModule from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal -from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal +from sage.manifolds.differentiable.diff_form import (DiffForm, + DiffFormParal) +from sage.manifolds.differentiable.multivectorfield import (MultivectorField, + MultivectorFieldParal) from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, AutomorphismFieldParal) @@ -309,44 +312,70 @@ def _element_constructor_(self, comp=[], frame=None, name=None, # coercion of a p-form to a type-(0,p) tensor: form = comp # for readability p = form.degree() - if self._tensor_type != (0,p) or self._vmodule != form.base_module(): + if (self._tensor_type != (0,p) or + self._vmodule != form.base_module()): raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._vmodule, (0,p), name=form._name, + resu = self.element_class(self._vmodule, (0,p), + name=form._name, latex_name=form._latex_name, antisym=asym) for dom, rst in form._restrictions.items(): - resu._restrictions[dom] = dom.tensor_field_module((0,p))(rst) + resu._restrictions[dom] = \ + dom.tensor_field_module((0,p))(rst) + return resu + if isinstance(comp, MultivectorField): + # coercion of a p-vector field to a type-(p,0) tensor: + pvect = comp # for readability + p = pvect.degree() + if (self._tensor_type != (p,0) or + self._vmodule != pvect.base_module()): + raise TypeError("cannot convert the {}".format(pvect) + + " to an element of {}".format(self)) + if p == 1: + asym = None + else: + asym = range(p) + resu = self.element_class(self._vmodule, (p,0), + name=pvect._name, + latex_name=pvect._latex_name, + antisym=asym) + for dom, rst in pvect._restrictions.items(): + resu._restrictions[dom] = \ + dom.tensor_field_module((p,0))(rst) return resu if isinstance(comp, AutomorphismField): # coercion of an automorphism to a type-(1,1) tensor: autom = comp # for readability - if self._tensor_type != (1,1) or self._vmodule != autom.base_module(): + if (self._tensor_type != (1,1) or + self._vmodule != autom.base_module()): raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) - resu = self.element_class(self._vmodule, (1,1), name=autom._name, + resu = self.element_class(self._vmodule, (1,1), + name=autom._name, latex_name=autom._latex_name) for dom, rest in autom._restrictions.items(): - resu._restrictions[dom] = dom.tensor_field_module((1,1))(rest) + resu._restrictions[dom] = \ + dom.tensor_field_module((1,1))(rest) return resu if isinstance(comp, TensorField): # coercion by domain restriction if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset(comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._tensor_type, name=name, - latex_name=latex_name, sym=sym, - antisym=antisym) + resu = self.element_class(self._vmodule, self._tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) if comp != []: resu.set_comp(frame)[:] = comp return resu @@ -394,13 +423,20 @@ def _coerce_map_from_(self, other): False sage: T02._coerce_map_from_(M.diff_form_module(2)) True + sage: T20 = M.tensor_field_module((2,0)) + sage: T20._coerce_map_from_(M.multivector_module(2)) + True sage: T11 = M.tensor_field_module((1,1)) sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import DiffFormModule - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldGroup + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormModule + from sage.manifolds.differentiable.multivector_module import \ + MultivectorModule + from sage.manifolds.differentiable.automorphismfield_group \ + import AutomorphismFieldGroup if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -410,6 +446,10 @@ def _coerce_map_from_(self, other): # coercion of p-forms to type-(0,p) tensor fields return (self._vmodule is other.base_module() and self._tensor_type == (0, other.degree())) + if isinstance(other, MultivectorModule): + # coercion of p-vector fields to type-(p,0) tensor fields + return (self._vmodule is other.base_module() + and self._tensor_type == (other.degree(),0)) if isinstance(other, AutomorphismFieldGroup): # coercion of automorphism fields to type-(1,1) tensor fields return (self._vmodule is other.base_module() @@ -540,7 +580,7 @@ def zero(self): # (since new components are initialized to zero) return resu -#****************************************************************************** +#*********************************************************************** class TensorFieldFreeModule(TensorFreeModule): r""" @@ -710,7 +750,8 @@ def __init__(self, vector_field_module, tensor_type): kcon = tensor_type[0] lcov = tensor_type[1] name = "T^({},{})({}".format(kcon, lcov, domain._name) - latex_name = r"\mathcal{{T}}^{{({}, {})}}\left(".format(kcon, lcov, domain._latex_name) + latex_name = r"\mathcal{{T}}^{{({}, {})}}\left(".format(kcon, + lcov, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -737,8 +778,8 @@ def _element_constructor_(self, comp=[], frame=None, name=None, sage: T12 = M.tensor_field_module((1,2)) sage: t = T12([[[x,-y], [2,y]], [[1+x,y^2], [x^2,3]], ....: [[x*y, 1-x], [y^2, x]]], name='t'); t - Tensor field t of type (1,2) on the 2-dimensional differentiable - manifold M + Tensor field t of type (1,2) on the 2-dimensional + differentiable manifold M sage: t.display() t = x d/dx*dx*dx - y d/dx*dx*dy + 2 d/dx*dy*dx + y d/dx*dy*dy + (x + 1) d/dy*dx*dx + y^2 d/dy*dx*dy + x^2 d/dy*dy*dx @@ -753,26 +794,49 @@ def _element_constructor_(self, comp=[], frame=None, name=None, # coercion of a p-form to a type-(0,p) tensor field: form = comp # for readability p = form.degree() - if self._tensor_type != (0,p) or self._fmodule != form.base_module(): + if (self._tensor_type != (0,p) or + self._fmodule != form.base_module()): raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (0,p), name=form._name, + resu = self.element_class(self._fmodule, (0,p), + name=form._name, latex_name=form._latex_name, antisym=asym) for frame, cp in form._components.items(): resu._components[frame] = cp.copy() return resu + if isinstance(comp, MultivectorFieldParal): + # coercion of a p-vector field to a type-(p,0) tensor field: + pvect = comp # for readability + p = pvect.degree() + if (self._tensor_type != (p,0) or + self._fmodule != pvect.base_module()): + raise TypeError("cannot convert the {}".format(pvect) + + " to an element of {}".format(self)) + if p == 1: + asym = None + else: + asym = range(p) + resu = self.element_class(self._fmodule, (p,0), + name=pvect._name, + latex_name=pvect._latex_name, + antisym=asym) + for frame, cp in pvect._components.items(): + resu._components[frame] = cp.copy() + return resu if isinstance(comp, AutomorphismFieldParal): # coercion of an automorphism to a type-(1,1) tensor: autom = comp # for readability - if self._tensor_type != (1,1) or self._fmodule != autom.base_module(): + if (self._tensor_type != (1,1) or + self._fmodule != autom.base_module()): raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) - resu = self.element_class(self._fmodule, (1,1), name=autom._name, + resu = self.element_class(self._fmodule, (1,1), + name=autom._name, latex_name=autom._latex_name) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() @@ -780,16 +844,17 @@ def _element_constructor_(self, comp=[], frame=None, name=None, if isinstance(comp, TensorField): # coercion by domain restriction if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset( + comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) # Standard construction - resu = self.element_class(self._fmodule, self._tensor_type, name=name, - latex_name=latex_name, sym=sym, - antisym=antisym) + resu = self.element_class(self._fmodule, self._tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) if comp != []: resu.set_comp(frame)[:] = comp return resu @@ -813,13 +878,20 @@ def _coerce_map_from_(self, other): False sage: T02._coerce_map_from_(M.diff_form_module(2)) True + sage: T20 = M.tensor_field_module((2,0)) + sage: T20._coerce_map_from_(M.multivector_module(2)) + True sage: T11 = M.tensor_field_module((1,1)) sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormFreeModule + from sage.manifolds.differentiable.multivector_module import \ + MultivectorFreeModule + from sage.manifolds.differentiable.automorphismfield_group \ + import AutomorphismFieldParalGroup if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -829,6 +901,10 @@ def _coerce_map_from_(self, other): # coercion of p-forms to type-(0,p) tensor fields return (self._fmodule is other.base_module() and self._tensor_type == (0, other.degree())) + if isinstance(other, MultivectorFreeModule): + # coercion of p-vector fields to type-(p,0) tensor fields + return (self._fmodule is other.base_module() + and self._tensor_type == (other.degree(),0)) if isinstance(other, AutomorphismFieldParalGroup): # coercion of automorphism fields to type-(1,1) tensor fields return (self._fmodule is other.base_module() diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 7c12fe66b39..9adc6a62e69 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -41,6 +41,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.modules import Modules +from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule from sage.manifolds.differentiable.vectorfield import (VectorField, VectorFieldParal) @@ -221,14 +222,18 @@ def __init__(self, domain, dest_map=None): self._ambient_domain = self._dest_map._codomain self._name = name self._latex_name = latex_name - # the member self._ring is created for efficiency (to avoid calls to - # self.base_ring()): + # the member self._ring is created for efficiency (to avoid + # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() - Parent.__init__(self, base=self._ring, category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, + category=Modules(self._ring)) # Dictionary of the tensor modules built on self - # (dict. keys = (k,l) --the tensor type) - self._tensor_modules = {(1,0): self} # self is considered as the set of - # tensors of type (1,0) + # (keys = (k,l) --the tensor type) + self._tensor_modules = {(1,0): self} # self is considered as the + # set of tensors of type (1,0) + # Dictionary of exterior powers of self + # (keys = p --the power degree) : + self._exterior_powers = {} # Dictionary of exterior powers of the dual of self # (keys = p --the power degree) : self._dual_exterior_powers = {} @@ -525,6 +530,63 @@ def tensor_module(self, k, l): self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) return self._tensor_modules[(k,l)] + def exterior_power(self, p): + r""" + Return the `p`-th exterior power of ``self``. + + If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + its `p`-th exterior power is the set `A^p(U, \Phi)` of + `p`-vector fields along `U` with values on `\Phi(U)`. It is a + module over `C^k(U)`, the ring (algebra) of differentiable + scalar fields on `U`. + + INPUT: + + - ``p`` -- non-negative integer + + OUTPUT: + + - for `p=0`, the base ring, i.e. `C^k(U)` + - for `p=1`, the vector field module ``self``, since + `A^1(U, \Phi) = \mathcal{X}(U,\Phi)` + - for `p \geq 2`, instance of + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + representing the module `A^p(U,\Phi)` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: XM = M.vector_field_module() + sage: XM.exterior_power(2) + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) + Module X(M) of vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) is XM + True + sage: XM.exterior_power(0) + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(0) is M.scalar_field_algebra() + True + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + for more examples and documentation. + + """ + from sage.manifolds.differentiable.multivector_module import \ + MultivectorModule + if p == 0: + return self._ring + if p == 1: + return self + if p not in self._exterior_powers: + self._exterior_powers[p] = MultivectorModule(self, p) + return self._exterior_powers[p] + def dual_exterior_power(self, p): r""" Return the `p`-th exterior power of the dual of the vector field @@ -542,10 +604,10 @@ def dual_exterior_power(self, p): OUTPUT: + - for `p=0`, the base ring, i.e. `C^k(U)` - for `p \geq 1`, instance of :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormModule` - representing the module `\Omega^p(U,\Phi)`; for `p=0`, the - base ring, i.e. `C^k(U)`, is returned instead + representing the module `\Omega^p(U,\Phi)` EXAMPLES:: @@ -683,17 +745,23 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from sage.manifolds.differentiable.automorphismfield import \ - AutomorphismField - from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + AutomorphismField + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetric if tensor_type==(1,0): - return self.element_class(self, name=name, latex_name=latex_name) + return self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type == (1,1) and specific_type is not None: if issubclass(specific_type, AutomorphismField): - return self.automorphism(name=name, latex_name=latex_name) - elif (tensor_type[0] == 0 and tensor_type[1] > 1 - and antisym is not None and antisym != []): + return self.automorphism(name=name, + latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] if isinstance(antisym, list): antisym0 = antisym[0] else: @@ -701,35 +769,98 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, if len(antisym0) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] + if isinstance(antisym, list): + antisym0 = antisym[0] else: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + antisym0 = antisym + if len(antisym0) == tensor_type[0]: + return self.alternating_contravariant_tensor( + tensor_type[0], name=name, + latex_name=latex_name) elif tensor_type==(0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated # Generic case return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, sym=sym, - antisym=antisym) + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + + def alternating_contravariant_tensor(self, degree, name=None, + latex_name=None): + r""" + Construct an alternating contravariant tensor on the vector + field module ``self``. + + An alternating contravariant tensor on ``self`` is actually a + multivector field along the differentiable manifold `U` over + which ``self`` is defined. + + INPUT: + + - ``degree`` -- degree of the alternating contravariant tensor + (i.e. its tensor rank) + - ``name`` -- (default: ``None``) string; name given to the + alternating contravariant tensor + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to + denote the alternating contravariant tensor; if none is + provided, the LaTeX symbol is set to ``name`` + + OUTPUT: + + - instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: XM = M.vector_field_module() + sage: XM.alternating_contravariant_tensor(2, name='a') + 2-vector field a on the 2-dimensional differentiable + manifold M + + An alternating contravariant tensor of degree 1 is simply + a vector field:: + + sage: XM.alternating_contravariant_tensor(1, name='a') + Vector field a on the 2-dimensional differentiable + manifold M + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for more examples and documentation. + + """ + if degree == 1: + return self.element_class(self, name=name, + latex_name=latex_name) + return self.exterior_power(degree).element_class(self, degree, + name=name, latex_name=latex_name) def alternating_form(self, degree, name=None, latex_name=None): r""" - Construct an alternating form on the vector field module. + Construct an alternating form on the vector field module + ``self``. - An alternating form on the vector field module is actually a - differential form along the differentiable manifold `U` over which - the vector field module is defined. + An alternating form on ``self`` is actually a differential form + along the differentiable manifold `U` over which ``self`` is + defined. INPUT: - ``degree`` -- the degree of the alternating form (i.e. its tensor rank) - - ``name`` -- (string; optional) name given to the alternating form + - ``name`` -- (string; optional) name given to the alternating + form - ``latex_name`` -- (string; optional) LaTeX symbol to denote - the alternating form; if none is provided, the - LaTeX symbol is set to ``name`` + the alternating form; if none is provided, the LaTeX symbol is + set to ``name`` OUTPUT: @@ -751,16 +882,16 @@ def alternating_form(self, degree, name=None, latex_name=None): for more examples and documentation. """ - return self.dual_exterior_power(degree).element_class(self, degree, - name=name, latex_name=latex_name) + return self.dual_exterior_power(degree).element_class(self, + degree, name=name, latex_name=latex_name) def linear_form(self, name=None, latex_name=None): r""" Construct a linear form on the vector field module. A linear form on the vector field module is actually a field - of linear forms (i.e. a 1-form) along the differentiable manifold `U` - over which the vector field module is defined. + of linear forms (i.e. a 1-form) along the differentiable + manifold `U` over which the vector field module is defined. INPUT: @@ -789,16 +920,16 @@ def linear_form(self, name=None, latex_name=None): for more examples and documentation. """ - return self.dual_exterior_power(1).element_class(self, 1, name=name, - latex_name=latex_name) + return self.dual_exterior_power(1).element_class(self, 1, + name=name, latex_name=latex_name) def automorphism(self, name=None, latex_name=None): r""" Construct an automorphism of the vector field module. An automorphism of the vector field module is actually a field - of tangent-space automorphisms along the differentiable manifold `U` - over which the vector field module is defined. + of tangent-space automorphisms along the differentiable manifold + `U` over which the vector field module is defined. INPUT: @@ -829,8 +960,8 @@ def automorphism(self, name=None, latex_name=None): for more examples and documentation. """ - return self.general_linear_group().element_class(self, name=name, - latex_name=latex_name) + return self.general_linear_group().element_class(self, + name=name, latex_name=latex_name) @cached_method def identity_map(self, name='Id', latex_name=None): @@ -838,8 +969,8 @@ def identity_map(self, name='Id', latex_name=None): Construct the identity map on the vector field module. The identity map on the vector field module is actually a field - of tangent-space identity maps along the differentiable manifold `U` - over which the vector field module is defined. + of tangent-space identity maps along the differentiable manifold + `U` over which the vector field module is defined. INPUT: @@ -881,7 +1012,8 @@ def zero(self): sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.zero() - Vector field zero on the 2-dimensional differentiable manifold M + Vector field zero on the 2-dimensional differentiable + manifold M """ elt = self.element_class(self, name='zero', latex_name='0') for frame in self._domain._frames: @@ -1479,15 +1611,73 @@ def tensor_module(self, k, l): self._tensor_modules[(k,l)] = TensorFieldFreeModule(self, (k,l)) return self._tensor_modules[(k,l)] + def exterior_power(self, p): + r""" + Return the `p`-th exterior power of ``self``. + + If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + its `p`-th exterior power is the set `A^p(U, \Phi)` of + `p`-vector fields along `U` with values on `\Phi(U)`. It is a + free module over `C^k(U)`, the ring (algebra) of differentiable + scalar fields on `U`. + + INPUT: + + - ``p`` -- non-negative integer + + OUTPUT: + + - for `p=0`, the base ring, i.e. `C^k(U)` + - for `p=1`, the vector field free module ``self``, since + `A^1(U, \Phi) = \mathcal{X}(U,\Phi)` + - for `p \geq 2`, instance of + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule` + representing the module `A^p(U,\Phi)` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: XM = M.vector_field_module() + sage: XM.exterior_power(2) + Free module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) + Free module X(M) of vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) is XM + True + sage: XM.exterior_power(0) + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(0) is M.scalar_field_algebra() + True + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule` + for more examples and documentation. + + """ + from sage.manifolds.differentiable.multivector_module import \ + MultivectorFreeModule + if p == 0: + return self._ring + if p == 1: + return self + if p not in self._exterior_powers: + self._exterior_powers[p] = MultivectorFreeModule(self, p) + return self._exterior_powers[p] + def dual_exterior_power(self, p): r""" Return the `p`-th exterior power of the dual of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the - `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` - of `p`-forms along `U` with values on `\Phi(U)`. It is a module - over `C^k(U)`, the ring (algebra) of differentiable scalar - fields on `U`. + If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + the `p`-th exterior power of its dual is the set + `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on + `\Phi(U)`. It is a free module over `C^k(U)`, the ring (algebra) + of differentiable scalar fields on `U`. INPUT: @@ -1495,10 +1685,10 @@ def dual_exterior_power(self, p): OUTPUT: + - for `p=0`, the base ring, i.e. `C^k(U)` - for `p \geq 1`, a :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormFreeModule` - representing the module `\Omega^p(U,\Phi)`; for `p=0`, the - base ring, i.e. `C^k(U)`, is returned instead + representing the module `\Omega^p(U,\Phi)` EXAMPLES:: @@ -1525,7 +1715,8 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormFreeModule if p == 0: return self._ring if p not in self._dual_exterior_powers: @@ -1665,31 +1856,40 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.tensor((1,2), name='t') - Tensor field t of type (1,2) on the 2-dimensional differentiable - manifold M + Tensor field t of type (1,2) on the 2-dimensional + differentiable manifold M sage: XM.tensor((1,0), name='a') - Vector field a on the 2-dimensional differentiable manifold M + Vector field a on the 2-dimensional differentiable + manifold M sage: XM.tensor((0,2), name='a', antisym=(0,1)) 2-form a on the 2-dimensional differentiable manifold M + sage: XM.tensor((2,0), name='a', antisym=(0,1)) + 2-vector field a on the 2-dimensional differentiable + manifold M See :class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) - from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, AutomorphismFieldParal) + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetric if tensor_type == (1,0): - return self.element_class(self, name=name, latex_name=latex_name) + return self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type == (1,1) and specific_type is not None: if issubclass(specific_type, (AutomorphismField, AutomorphismFieldParal)): return self.automorphism(name=name, latex_name=latex_name) - elif (tensor_type[0] == 0 and tensor_type[1] > 1 - and antisym is not None and antisym != []): + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] if isinstance(antisym, list): antisym0 = antisym[0] else: @@ -1697,20 +1897,30 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, if len(antisym0) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] + if isinstance(antisym, list): + antisym0 = antisym[0] else: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + antisym0 = antisym + if len(antisym0) == tensor_type[0]: + return self.alternating_contravariant_tensor( + tensor_type[0], name=name, + latex_name=latex_name) elif tensor_type==(0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated # Generic case return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, sym=sym, - antisym=antisym) + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) - def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): + def tensor_from_comp(self, tensor_type, comp, name=None, + latex_name=None): r""" Construct a tensor on ``self`` from a set of components. @@ -1763,36 +1973,42 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): t = (x + 1) dx*dx - y dx*dy + x*y dy*dx + (-y^2 + 2) dy*dy """ - from sage.tensor.modules.comp import CompWithSym, CompFullySym, CompFullyAntiSym + from sage.tensor.modules.comp import (CompWithSym, CompFullySym, + CompFullyAntiSym) # 0/ Compatibility checks: if comp._ring is not self._ring: - raise ValueError("the components are not defined on the same " + - "ring as the module") + raise ValueError("the components are not defined on the " + + "same ring as the module") if comp._frame not in self._known_bases: - raise ValueError("the components are not defined on a basis of " + - "the module") + raise ValueError("the components are not defined on a " + + "basis of the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise ValueError("number of component indices not compatible " + - "with the tensor type") + raise ValueError("number of component indices not " + + "compatible with the tensor type") # # 1/ Construction of the tensor: if tensor_type == (1,0): - resu = self.element_class(self, name=name, latex_name=latex_name) + resu = self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): resu = self.linear_form(name=name, latex_name=latex_name) elif (tensor_type[0] == 0 and tensor_type[1] > 1 and isinstance(comp, CompFullyAntiSym)): resu = self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif (tensor_type[0] > 1 and tensor_type[1] == 0 + and isinstance(comp, CompFullyAntiSym)): + resu = self.alternating_contravariant_tensor(tensor_type[0], + name=name, latex_name=latex_name) else: resu = self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name) + tensor_type, name=name, latex_name=latex_name) # Tensor symmetries deduced from those of comp: if isinstance(comp, CompWithSym): resu._sym = comp._sym resu._antisym = comp._antisym - + # # 2/ Tensor components set to comp: resu._components[comp._frame] = comp # @@ -1810,9 +2026,10 @@ def sym_bilinear_form(self, name=None, latex_name=None): INPUT: - ``name`` -- string (default: ``None``); name given to the - automorphism - - ``latex_name`` -- string (default: ``None``); LaTeX symbol to denote - the automorphism; if ``None``, the LaTeX symbol is set to ``name`` + symmetric bilinear bilinear form + - ``latex_name`` -- string (default: ``None``); LaTeX symbol to + denote the symmetric bilinear form; if ``None``, the LaTeX + symbol is set to ``name`` OUTPUT: @@ -1835,7 +2052,8 @@ def sym_bilinear_form(self, name=None, latex_name=None): for more examples and documentation. """ - return self.tensor((0,2), name=name, latex_name=latex_name, sym=(0,1)) + return self.tensor((0,2), name=name, latex_name=latex_name, + sym=(0,1)) #### End of methods to be redefined by derived classes of FiniteRankFreeModule #### From 6f8bec4637919793dafcebf6967442dac99daaeb Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 11 Jul 2017 18:39:42 +0200 Subject: [PATCH 009/218] Implement alternating multivector fields on manifolds (interior products in progress) --- .../en/reference/manifolds/diff_manifold.rst | 2 + .../en/reference/manifolds/multivector.rst | 9 + .../manifolds/differentiable/diff_form.py | 92 +++- .../differentiable/diff_form_module.py | 27 +- src/sage/manifolds/differentiable/manifold.py | 2 +- src/sage/manifolds/differentiable/metric.py | 7 +- .../differentiable/multivector_module.py | 58 ++- .../differentiable/multivectorfield.py | 452 ++++++++++++++---- .../manifolds/differentiable/vectorfield.py | 28 +- .../differentiable/vectorfield_module.py | 2 + 10 files changed, 504 insertions(+), 175 deletions(-) create mode 100644 src/doc/en/reference/manifolds/multivector.rst diff --git a/src/doc/en/reference/manifolds/diff_manifold.rst b/src/doc/en/reference/manifolds/diff_manifold.rst index f064e855782..f358d30d6b8 100644 --- a/src/doc/en/reference/manifolds/diff_manifold.rst +++ b/src/doc/en/reference/manifolds/diff_manifold.rst @@ -22,4 +22,6 @@ Differentiable Manifolds diff_form + multivector + sage/manifolds/differentiable/affine_connection diff --git a/src/doc/en/reference/manifolds/multivector.rst b/src/doc/en/reference/manifolds/multivector.rst new file mode 100644 index 00000000000..fe2c90815cb --- /dev/null +++ b/src/doc/en/reference/manifolds/multivector.rst @@ -0,0 +1,9 @@ +Alternating Multivector Fields +============================== + +.. toctree:: + :maxdepth: 2 + + sage/manifolds/differentiable/multivector_module + + sage/manifolds/differentiable/multivectorfield diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index 81a8a66341d..671e087d03b 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -400,7 +400,8 @@ def wedge(self, other): OUTPUT: - - a :class:`DiffForm` of the exterior product ``self/\other`` + - instance of :class:`DiffForm` representing the exterior product + ``self/\other`` EXAMPLES: @@ -431,7 +432,6 @@ def wedge(self, other): a/\b = -(v^2 - u)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du/\dv """ - from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm from sage.tensor.modules.format_utilities import is_atomic if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): @@ -766,18 +766,24 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): A/\B = (x*y*z*sin(x) + x*z*cos(z)) dx/\dy + (x*y*z*cos(y) - y*z*cos(z)) dx/\dz - (x*cos(y) + y*sin(x))*z dy/\dz + Let us check the formula relating the exterior product to the tensor + product for 1-forms:: + + sage: a.wedge(b) == a*b - b*a + True + The tensor product of a 1-form and a 2-form is not a 3-form but a tensor field of type `(0,3)` with less symmetries:: sage: c = a*ab ; c Tensor field A*(A/\B) of type (0,3) on the 3-dimensional differentiable manifold R3 - sage: c.symmetries() # the antisymmetry is only w.r.t. the last two arguments: + sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments: no symmetry; antisymmetry: (1, 2) sage: d = ab*a ; d Tensor field (A/\B)*A of type (0,3) on the 3-dimensional differentiable manifold R3 - sage: d.symmetries() # the antisymmetry is only w.r.t. the first two arguments: + sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments: no symmetry; antisymmetry: (0, 1) The exterior derivative of a differential form is obtained by means @@ -872,23 +878,6 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: c.symmetries() # c has no symmetries: no symmetry; no antisymmetry - The exterior product of two 1-forms is a 2-form:: - - sage: d = a.wedge(b) ; d - 2-form A/\B on the 3-dimensional differentiable manifold R3 - sage: d[:] - [ 0 -7 -14] - [ 7 0 -7] - [ 14 7 0] - sage: d.symmetries() - no symmetry; antisymmetry: (0, 1) - - We can check the standard formula relating the exterior product to the - tensor product:: - - sage: a.wedge(b) == a*b - b*a - True - """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -1031,7 +1020,7 @@ def __call__(self, *args): sage: s.display() a(u,v): M --> R (x, y) |--> -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y - sage: s == a[[0,1]]*(u[[0]]*v[[1]] -u[[1]]*v[[0]]) + sage: s == a[[0,1]]*(u[[0]]*v[[1]] - u[[1]]*v[[0]]) True sage: s == a(u,v) # indirect doctest True @@ -1193,7 +1182,6 @@ def wedge(self, other): True """ - from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior " + @@ -1273,3 +1261,61 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + + def interior_product(self, qvect): + r""" + Interior product with a multivector field. + + If ``self`` is a differential form `A` of degree `p` and `B` is a + multivector field of degree `q\geq p` on the same manifold, the + interior product of `A` by `B` is the multivector field `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p} + B^{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract` + + INPUT: + + - ``qvect`` -- multivector field `B` (instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultiVectorFieldParal`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.multivectorfield.MultiVectorFieldParal` + (case `p = A.chart() sage: h = A.multivector_field(2, 'H'); h - 2-vector field h on the Open subset A of the 4-dimensional + 2-vector field H on the Open subset A of the 4-dimensional differentiable manifold M See the documentation of class diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 7d98cf60163..aee2e03dcc5 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -1597,7 +1597,6 @@ def volume_form(self, contra=0): sage: latex(eps) \epsilon_{g} - The tensor field of components `\epsilon^i_{\ \, jk}` (``contra=1``):: sage: eps1 = g.volume_form(1) ; eps1 @@ -1625,8 +1624,10 @@ def volume_form(self, contra=0): The tensor field of components `\epsilon^{ijk}` (``contra=3``):: sage: eps3 = g.volume_form(3) ; eps3 - Tensor field of type (3,0) on the Open subset U of the - 3-dimensional differentiable manifold M + 3-vector field on the Open subset U of the 3-dimensional + differentiable manifold M + sage: eps3.tensor_type() + (3, 0) sage: eps3.symmetries() no symmetry; antisymmetry: (0, 1, 2) sage: eps3[:] diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index 2ec71b2f7eb..07daf8e4495 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -38,7 +38,7 @@ from sage.categories.modules import Modules from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule from sage.manifolds.differentiable.multivectorfield import ( - MultivectorField, MultivectorFieldParal) + MultivectorField, MultivectorFieldParal) class MultivectorModule(UniqueRepresentation, Parent): r""" @@ -172,8 +172,7 @@ class :class:`MultivectorFreeModule` must be used instead. sage: A1 is XM True - For a degree `p \geq 2`, there is a coercion map - `A^p(M)\rightarrow T^{(p,0)}(M)`:: + There is a coercion map `A^p(M)\rightarrow T^{(p,0)}(M)`:: sage: T20 = M.tensor_field_module((2,0)) ; T20 Module T^(2,0)(M) of type-(2,0) tensors fields on the @@ -181,7 +180,8 @@ class :class:`MultivectorFreeModule` must be used instead. sage: T20.has_coerce_map_from(A) True - but of course not in the reverse direction:: + but of course not in the reverse direction, since not all contravariant + tensor field is alternating:: sage: A.has_coerce_map_from(T20) False @@ -212,7 +212,7 @@ class :class:`MultivectorFreeModule` must be used instead. 2-vector field a on the Open subset U of the 2-dimensional differentiable manifold M sage: a_U.display(eU) - a = 3*x dx/\dy + a = 3*x d/dx/\d/dy """ Element = MultivectorField @@ -291,7 +291,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, 2-vector field a on the 2-dimensional differentiable manifold M sage: a.display(c_xy.frame()) - a = x*y dx/\dy + a = x*y d/dx/\d/dy sage: A(0) is A.zero() True @@ -429,7 +429,7 @@ def _latex_(self): sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}') sage: A2 = M.multivector_module(2) sage: A2._latex_() - '\A^{2}\\left(\\mathcal{M}\\right)' + 'A^{2}\\left(\\mathcal{M}\\right)' sage: latex(A2) # indirect doctest A^{2}\left(\mathcal{M}\right) @@ -442,14 +442,13 @@ def _latex_(self): def base_module(self): r""" Return the vector field module on which the multivector field - module is constructed. + module ``self`` is constructed. OUTPUT: - a :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` - representing the module on which the multivector field module - is defined + representing the module on which ``self`` is defined EXAMPLES:: @@ -475,17 +474,15 @@ def base_module(self): def degree(self): r""" - Return the degree of the multivector fields in the module. + Return the degree of the multivector fields in ``self``. OUTPUT: - - integer `p` such that the module is a set of `p`-vector fields + - integer `p` such that ``self`` is a set of `p`-vector fields EXAMPLES:: sage: M = Manifold(3, 'M') - sage: M.multivector_module(1).degree() - 1 sage: M.multivector_module(2).degree() 2 sage: M.multivector_module(3).degree() @@ -503,11 +500,11 @@ class MultivectorFreeModule(ExtPowerFreeModule): parallelizable manifold `M`. Given a differentiable manifold `U` and a differentiable map - `\Phi:\; U \rightarrow M` to a parallelizable manifold `M`, the set - `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields - of type `(p,0)`) along `U` with values on `M` is a module over - `C^k(U)`, the commutative algebra of differentiable scalar fields - on `U` (see + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M` of dimension + `n`, the set `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor + fields of type `(p,0)`) along `U` with values on `M` is a free module + of rank `\binom{n}{p}` over `C^k(U)`, the commutative algebra of + differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). The standard case of `p`-vector fields *on* a differentiable manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. @@ -546,7 +543,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): A^{2}\left(M\right) ``A`` is nothing but the second exterior power of ``XM``, i.e. we - have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see + have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`):: sage: A is XM.exterior_power(2) @@ -591,7 +588,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: a = A(comp, frame=X.frame(), name='a') ; a 2-vector field a on the 3-dimensional differentiable manifold M sage: a.display() - a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz An alternative is to construct the 2-vector field from an empty list of components and to set the nonzero nonredundant components @@ -602,7 +599,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: a[0,2] = -z sage: a[1,2] = 4 sage: a.display() - a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz The module `A^1(M)` is nothing but `\mathcal{X}(M)` (the free module of vector fields on `M`):: @@ -613,8 +610,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: A1 is XM True - For a degree `p \geq 2`, there is a coercion map - `A^p(M) \rightarrow T^{(p,0)}(M)`:: + There is a coercion map `A^p(M) \rightarrow T^{(p,0)}(M)`:: sage: T20 = M.tensor_field_module((2,0)); T20 Free module T^(2,0)(M) of type-(2,0) tensors fields on the @@ -622,7 +618,8 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: T20.has_coerce_map_from(A) True - but of course not in the reverse direction:: + but of course not in the reverse direction, since not all contravariant + tensor field is alternating:: sage: A.has_coerce_map_from(T20) False @@ -636,9 +633,10 @@ class MultivectorFreeModule(ExtPowerFreeModule): Tensor field a of type (2,0) on the 3-dimensional differentiable manifold M sage: ta.display() - a = 3*x dx*dy - z dx*dz - 3*x dy*dx + 4 dy*dz + z dz*dx - 4 dz*dy + a = 3*x d/dx*d/dy - z d/dx*d/dz - 3*x d/dy*d/dx + 4 d/dy*d/dz + + z d/dz*d/dx - 4 d/dz*d/dy sage: a.display() - a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz sage: ta.symmetries() # the antisymmetry is preserved no symmetry; antisymmetry: (0, 1) @@ -655,7 +653,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): 2-vector field a on the Open subset U of the 3-dimensional differentiable manifold M sage: a_U.display() - a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz """ @@ -711,7 +709,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, 2-vector field a on the 2-dimensional differentiable manifold M sage: a.display() - a = x dx/\dy + a = x d/dx/\d/dy sage: A(0) is A.zero() True @@ -756,8 +754,6 @@ def _coerce_map_from_(self, other): sage: A2U._coerce_map_from_(A1) False sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) - True - sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) False """ diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 23242d4ced6..873cac2f9e9 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -96,8 +96,9 @@ class MultivectorField(TensorField): 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+y, x-y), intersection_name='W', - ....: restrictions1= x>0, restrictions2= u+v>0) + sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', + ....: restrictions1= x>0, restrictions2= u+v>0) sage: uv_to_xy = xy_to_uv.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_uv.frame() @@ -114,19 +115,24 @@ class MultivectorField(TensorField): sage: a[eU,0,1] = x*y^2 + 2*x sage: a.add_comp_by_continuation(eV, W, c_uv) sage: a.display(eU) - a = (x*y^2 + 2*x) dx/\dy + a = (x*y^2 + 2*x) d/dx/\d/dy sage: a.display(eV) - a = (-1/16*u^3 + 1/16*u*v^2 - 1/16*v^3 - + 1/16*(u^2 - 8)*v - 1/2*u) du/\dv + a = (-1/4*u^3 + 1/4*u*v^2 - 1/4*v^3 + 1/4*(u^2 - 8)*v - 2*u) d/du/\d/dv The exterior product of two vector fields is a 2-vector field:: + sage: a = M.vector_field(name='a') + sage: a[eU,:] = [-y, x] + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: b = M.vector_field(name='b') + sage: b[eU,:] = [1+x*y, x^2] + sage: b.add_comp_by_continuation(eV, W, c_uv) sage: s = a.wedge(b) ; s 2-vector field a/\b on the 2-dimensional differentiable manifold M sage: s.display(eU) - a/\b = (-2*x^2*y - x) dx/\dy + a/\b = (-2*x^2*y - x) d/dx/\d/dy sage: s.display(eV) - a/\b = (1/8*u^3 - 1/8*u*v^2 - 1/8*v^3 + 1/8*(u^2 + 2)*v + 1/4*u) du/\dv + a/\b = (1/2*u^3 - 1/2*u*v^2 - 1/2*v^3 + 1/2*(u^2 + 2)*v + u) d/du/\d/dv Multiplying a 2-vector field by a scalar field results in another 2-vector field:: @@ -135,9 +141,10 @@ class MultivectorField(TensorField): sage: s = f*s ; s 2-vector field on the 2-dimensional differentiable manifold M sage: s.display(eU) - (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy + (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy sage: s.display(eV) - 1/2*u^2*v du - 1/2*u^3 dv + (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) + d/du/\d/dv """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -239,45 +246,48 @@ def wedge(self, other): OUTPUT: - - a :class:`MultivectorField` of the exterior product ``self/\other`` + - instance of :class:`MultivectorField` representing the exterior + product ``self/\other`` EXAMPLES: Exterior product of two vector fields on the 2-sphere:: - - sage: M = Manifold(2, 'S^2', start_index=1) # the 2-dimensional sphere S^2 + sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2 sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # S^2 is the union of U and V - sage: c_xy. = U.chart() ; c_uv. = V.chart() # stereographic coord. (North and South) + sage: c_xy. = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South 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: W = U.intersection(V) # The complement of the two poles sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() - sage: a = M.multivector_field(1, name='a') + sage: a = M.vector_field(name='a') sage: a[e_xy,:] = y, x sage: a.add_comp_by_continuation(e_uv, W, c_uv) - sage: b = M.multivector_field(1, name='b') + sage: b = M.vector_field(name='b') sage: b[e_xy,:] = x^2 + y^2, y sage: b.add_comp_by_continuation(e_uv, W, c_uv) sage: c = a.wedge(b); c - 2-vector field a/\b on the 2-dimensional differentiable manifold S^2 + 2-vector field a/\b on the 2-dimensional differentiable + manifold S^2 sage: c.display(e_xy) - a/\b = (-x^3 - (x - 1)*y^2) dx/\dy + a/\b = (-x^3 - (x - 1)*y^2) d/dx/\d/dy sage: c.display(e_uv) - a/\b = -(v^2 - u)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du/\dv + a/\b = (-v^2 + u) d/du/\d/dv """ - from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.tensor.modules.format_utilities import is_atomic if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") dom_resu = self._domain.intersection(other._domain) ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain) self_r = self.restrict(dom_resu) @@ -315,13 +325,175 @@ def wedge(self, other): other_r._restrictions[dom]) return resu + def interior_product(self, form): + r""" + Interior product with a differential form. + + If ``self`` is a multivector field `A` of degree `p` and `B` is a + differential form of degree `q\geq p` on the same manifold as `A`, the + interior product of `A` by `B` is the differential form `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)_{i_1\ldots i_{q-p}} = A^{k_1\ldots k_p} + B_{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract` + + INPUT: + + - ``form`` -- differential form `B` (instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffForm`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + (case `p = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + 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: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.vector_field(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.diff_form(2, name='b') + sage: b[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: b.display(e_xy) + b = 4/(x^2 + y^2 + 1)^2 dx/\dy + sage: b.display(e_uv) + b = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du/\dv + sage: s = a.interior_product(b); s + 1-form i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + i_a b = -4*x/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx + + 4*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy + sage: s.display(e_uv) + i_a b = 4*(u^3 - 3*u*v^2)/(u^6 + v^6 + (3*u^2 + 2)*v^4 + 2*u^4 + + (3*u^4 + 4*u^2 + 1)*v^2 + u^2) du + + 4*(3*u^2*v - v^3)/(u^6 + v^6 + (3*u^2 + 2)*v^4 + 2*u^4 + + (3*u^4 + 4*u^2 + 1)*v^2 + u^2) dv + sage: s == a.contract(b) + True + + Example with `p=2` and `q=2`:: + + sage: a = M.multivector_field(2, name='a') + sage: a[e_xy,1,2] = x*y + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: a.display(e_xy) + a = x*y d/dx/\d/dy + sage: a.display(e_uv) + a = -u*v d/du/\d/dv + sage: s = a.interior_product(b); s + Scalar field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display() + i_a b: S^2 --> R + on U: (x, y) |--> 8*x*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) + on V: (u, v) |--> 8*u*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) + + Some checks:: + + sage: s == a.contract(0, 1, b, 0, 1) + True + sage: s.restrict(U) == 2 * a[[e_xy,1,2]] * b[[e_xy,1,2]] + True + sage: s.restrict(V) == 2 * a[[e_uv,1,2]] * b[[e_uv,1,2]] + True + + """ + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(form._domain): + if not self._ambient_domain.is_subset(form._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif form._domain.is_subset(self._domain): + if not form._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(form._domain) + ambient_dom_resu = self._ambient_domain.intersection(form._ambient_domain) + self_r = self.restrict(dom_resu) + form_r = form.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.interior_product(self_r, form_r) + # Otherwise, the result is created here: + # Name of the result + resu_name = None + if self._name is not None and form._name is not None: + sname = self._name + oname = form._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = 'i_' + sname + ' ' + oname + resu_latex_name = None + if self._latex_name is not None and form._latex_name is not None: + slname = self._latex_name + olname = form._latex_name + if not is_atomic(olname): + olname = r'\left(' + olname + r'\right)' + resu_latex_name = r'\iota_{' + slname + '} ' + olname + # Domain and computation of the result + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = form._tensor_rank - self._tensor_rank + resu = vmodule.alternating_form(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in form_r._restrictions: + resu._restrictions[dom] = \ + self_r._restrictions[dom].interior_product( + form_r._restrictions[dom]) + if resu_degree == 0: + if not resu._express: # only the restrictions to subdomains have + # been initialized + for chart in dom_resu.top_charts(): + resu._express[chart] = \ + resu.restrict(chart.domain()).coord_function(chart) + return resu + def degree(self): r""" Return the degree of ``self``. OUTPUT: - - integer `p` such that the multivector field is a `p`-vector field + - integer `p` such that ``self`` is a `p`-vector field EXAMPLES:: @@ -330,8 +502,8 @@ def degree(self): 2-vector field on the 3-dimensional differentiable manifold M sage: a.degree() 2 - sage: b = M.multivector_field(1); b - 1-vector field on the 3-dimensional differentiable manifold M + sage: b = M.vector_field(); b + Vector field on the 3-dimensional differentiable manifold M sage: b.degree() 1 @@ -395,8 +567,8 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: a = M.multivector_field(2, 'a') ; a 2-vector field a on the 4-dimensional differentiable manifold M sage: a.parent() - Free module A^2(M) of 2-vector fields on the 4-dimensional differentiable - manifold M + Free module A^2(M) of 2-vector fields on the 4-dimensional + differentiable manifold M A multivector field is a tensor field of purely contravariant type:: @@ -412,7 +584,8 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: a[1,0] -2 sage: a.comp() - Fully antisymmetric 2-indices components w.r.t. Coordinate frame (M, (d/dt,d/dx,d/dy,d/dz)) + Fully antisymmetric 2-indices components w.r.t. Coordinate frame + (M, (d/dt,d/dx,d/dy,d/dz)) sage: type(a.comp()) @@ -431,11 +604,11 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): displayed via the method :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.display`:: - sage: a.display() # expansion with respect to the default coframe (dt, dx, dy, dz) - a = 2 dt/\dx + 3 dx/\dy + sage: a.display() # expansion w.r.t. the default frame + a = 2 d/dt/\d/dx + 3 d/dx/\d/dy sage: latex(a.display()) # output for the notebook - a = 2 \mathrm{d} t\wedge \mathrm{d} x - + 3 \mathrm{d} x\wedge \mathrm{d} y + a = 2 \frac{\partial}{\partial t }\wedge \frac{\partial}{\partial x } + + 3 \frac{\partial}{\partial x }\wedge \frac{\partial}{\partial y } Multivector fields can be added or subtracted:: @@ -458,17 +631,18 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): [ 2 -3 0 0] [ 3 0 0 0] - An example of 3-vector field in `\RR^3` oordinates:: + An example of 3-vector field in `\RR^3` with Cartesian coordinates:: sage: M = Manifold(3, 'R3', '\RR^3', start_index=1) sage: c_cart. = M.chart() - sage: eps = M.multivector_field(3, 'epsilon', r'\epsilon') - sage: eps[1,2,3] = 1 # the only independent component - sage: eps[:] # all the components are set from the previous line: - [[[0, 0, 0], [0, 0, 1], [0, -1, 0]], [[0, 0, -1], [0, 0, 0], [1, 0, 0]], - [[0, 1, 0], [-1, 0, 0], [0, 0, 0]]] - sage: eps.display() - epsilon = dx/\dy/\dz + sage: a = M.multivector_field(3, name='a') + sage: a[1,2,3] = x^2+y^2+z^2 # the only independent component + sage: a[:] # all the components are set from the previous line: + [[[0, 0, 0], [0, 0, x^2 + y^2 + z^2], [0, -x^2 - y^2 - z^2, 0]], + [[0, 0, -x^2 - y^2 - z^2], [0, 0, 0], [x^2 + y^2 + z^2, 0, 0]], + [[0, x^2 + y^2 + z^2, 0], [-x^2 - y^2 - z^2, 0, 0], [0, 0, 0]]] + sage: a.display() + a = (x^2 + y^2 + z^2) d/dx/\d/dy/\d/dz Spherical components from the tensorial change-of-frame formula:: @@ -477,32 +651,39 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2), ....: atan2(sqrt(x^2+y^2),z), atan2(y, x)) - sage: eps.comp(c_spher.frame()) # computation of the components in the spherical frame + sage: a.comp(c_spher.frame()) # computation of the components in the spherical frame Fully antisymmetric 3-indices components w.r.t. Coordinate frame (R3, (d/dr,d/dth,d/dph)) - sage: eps.comp(c_spher.frame())[1,2,3, c_spher] - r^2*sin(th) - sage: eps.display(c_spher.frame()) - epsilon = sqrt(x^2 + y^2 + z^2)*sqrt(x^2 + y^2) dr/\dth/\dph - sage: eps.display(c_spher.frame(), c_spher) - epsilon = r^2*sin(th) dr/\dth/\dph + sage: a.comp(c_spher.frame())[1,2,3, c_spher] + 1/sin(th) + sage: a.display(c_spher.frame()) + a = sqrt(x^2 + y^2 + z^2)/sqrt(x^2 + y^2) d/dr/\d/dth/\d/dph + sage: a.display(c_spher.frame(), c_spher) + a = 1/sin(th) d/dr/\d/dth/\d/dph The exterior product of two multivector fields is performed via the method :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.wedge`:: - sage: a = M.one_form('A') + sage: a = M.vector_field(name='A') sage: a[:] = (x*y*z, -z*x, y*z) - sage: b = M.one_form('B') - sage: b[:] = (cos(z), sin(x), cos(y)) + sage: b = M.vector_field(name='B') + sage: b[:] = (y, z+y^2, x^2-z^2) sage: ab = a.wedge(b) ; ab 2-vector field A/\B on the 3-dimensional differentiable manifold R3 sage: ab[:] - [ 0 x*y*z*sin(x) + x*z*cos(z) x*y*z*cos(y) - y*z*cos(z)] - [-x*y*z*sin(x) - x*z*cos(z) 0 -(x*cos(y) + y*sin(x))*z] - [-x*y*z*cos(y) + y*z*cos(z) (x*cos(y) + y*sin(x))*z 0] + [ 0 x*y*z^2 + (x*y^3 + x*y)*z -x*y*z^3 + (x^3*y - y^2)*z] + [ -x*y*z^2 - (x*y^3 + x*y)*z 0 x*z^3 - y*z^2 - (x^3 + y^3)*z] + [ x*y*z^3 - (x^3*y - y^2)*z -x*z^3 + y*z^2 + (x^3 + y^3)*z 0] sage: ab.display() - A/\B = (x*y*z*sin(x) + x*z*cos(z)) dx/\dy + (x*y*z*cos(y) - y*z*cos(z)) dx/\dz - - (x*cos(y) + y*sin(x))*z dy/\dz + A/\B = (x*y*z^2 + (x*y^3 + x*y)*z) d/dx/\d/dy + (-x*y*z^3 + + (x^3*y - y^2)*z) d/dx/\d/dz + (x*z^3 - y*z^2 + - (x^3 + y^3)*z) d/dy/\d/dz + + Let us check the formula relating the exterior product to the tensor + product for vector fields:: + + sage: a.wedge(b) == a*b - b*a + True The tensor product of a vector field and a 2-vector field is not a 3-vector field but a tensor field of type `(3,0)` with less symmetries:: @@ -510,38 +691,21 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: c = a*ab ; c Tensor field A*(A/\B) of type (3,0) on the 3-dimensional differentiable manifold R3 - sage: c.symmetries() # the antisymmetry is only w.r.t. the last two arguments: + sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments: no symmetry; antisymmetry: (1, 2) sage: d = ab*a ; d Tensor field (A/\B)*A of type (3,0) on the 3-dimensional differentiable manifold R3 - sage: d.symmetries() # the antisymmetry is only w.r.t. the first two arguments: + sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments: no symmetry; antisymmetry: (0, 1) The Lie derivative of a 2-vector field is a 2-vector field:: - sage: v = M.vector_field('v') + sage: v = M.vector_field(name='v') sage: v[:] = (y*z, -x*z, x*y) - sage: ab.lie_der(v) # long time + sage: ab.lie_der(v) 2-vector field on the 3-dimensional differentiable manifold R3 - The exterior product of two vector fields is a 2-vector field:: - - sage: d = a.wedge(b) ; d - 2-vector field A/\B on the 3-dimensional differentiable manifold R3 - sage: d[:] - [ 0 -7 -14] - [ 7 0 -7] - [ 14 7 0] - sage: d.symmetries() - no symmetry; antisymmetry: (0, 1) - - We can check the standard formula relating the exterior product to the - tensor product:: - - sage: a.wedge(b) == a*b - b*a - True - """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -673,19 +837,19 @@ def __call__(self, *args): sage: a = M.multivector_field(2, name='a') sage: a[0,1] = x*y sage: a.display() - a = x*y dx/\dy - sage: u = M.vector_field(name='u') - sage: u[:] = [1+x, 2-y] - sage: v = M.vector_field(name='v') - sage: v[:] = [-y, x] - sage: s = a.__call__(u,v); s - Scalar field a(u,v) on the 2-dimensional differentiable manifold M + a = x*y d/dx/\d/dy + sage: b = M.one_form(name='b') + sage: b[:] = [1+x, 2-y] + sage: c = M.one_form(name='c') + sage: c[:] = [-y, x] + sage: s = a.__call__(b,c); s + Scalar field a(b,c) on the 2-dimensional differentiable manifold M sage: s.display() - a(u,v): M --> R + a(b,c): M --> R (x, y) |--> -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y - sage: s == a[[0,1]]*(u[[0]]*v[[1]] -u[[1]]*v[[0]]) + sage: s == a[[0,1]]*(b[[0]]*c[[1]] - b[[1]]*c[[0]]) True - sage: s == a(u,v) # indirect doctest + sage: s == a(b,c) # indirect doctest True """ @@ -711,18 +875,18 @@ def wedge(self, other): sage: M = Manifold(3, 'M', start_index=1) sage: X. = M.chart() - sage: a = M.one_form(name='a') + sage: a = M.vector_field(name='a') sage: a[:] = [2, 1+x, y*z] sage: b = M.multivector_field(2, name='b') sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, z^2 sage: a.display() - a = 2 dx + (x + 1) dy + y*z dz + a = 2 d/dx + (x + 1) d/dy + y*z d/dz sage: b.display() - b = y^2 dx/\dy + (x + z) dx/\dz + z^2 dy/\dz + b = y^2 d/dx/\d/dy + (x + z) d/dx/\d/dz + z^2 d/dy/\d/dz sage: s = a.wedge(b); s 3-vector field a/\b on the 3-dimensional differentiable manifold M sage: s.display() - a/\b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) dx/\dy/\dz + a/\b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) d/dx/\d/dy/\d/dz Check:: @@ -730,8 +894,6 @@ def wedge(self, other): True """ - from sage.tensor.modules.alternating_contr_tensor import \ - AlternatingContrTensor if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior " + @@ -744,3 +906,111 @@ def wedge(self, other): self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) return AlternatingContrTensor.wedge(self_r, other_r) + + def interior_product(self, form): + r""" + Interior product with a differential form. + + If ``self`` is a multivector field `A` of degree `p` and `B` is a + differential form of degree `q\geq p` on the same manifold as `A`, the + interior product of `A` by `B` is the differential form `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)_{i_1\ldots i_{q-p}} = A^{k_1\ldots k_p} + B_{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract` + + INPUT: + + - ``form`` -- differential form `B` (instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` + (case `p = M.chart() + sage: a = M.vector_field(name='a') + sage: a[:] = [x, 1+t^2, x*z, y-3] + sage: b = M.one_form(name='b') + sage: b[:] = [-z^2, 2, x*y, x-y] + sage: s = a.interior_product(b); s + Scalar field i_a b on the 4-dimensional differentiable manifold M + sage: s.display() + i_a b: M --> R + (t, x, y, z) |--> x^2*y*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 - 3*x + 2 + + In this case, we have `\iota_a b = a^i b_i = a(b) = b(a)`:: + + sage: all([s == a.contract(b), s == a(b), s == b(a)]) + True + + Case `p=1` and `q=3`:: + + sage: c = M.diff_form(3, name='c') + sage: c[0,1,2], c[0,1,3] = x*y - z, -3*t + sage: c[0,2,3], c[1,2,3] = t^2+x, y^2 + sage: s = a.interior_product(c); s + 2-form i_a c on the 4-dimensional differentiable manifold M + sage: s.display() + i_a c = (x^2*y*z - x*z^2 - 3*t*y + 9*t) dt/\dx + (-3*t^2 + - (t^2*x - t^2)*y + (t^2 + 1)*z - 3*x) dt/\dy + (3*t^3 + - (t^2*x + x^2)*z + 3*t) dt/\dz + (x^2*y + y^3 - 3*y^2 + - x*z) dx/\dy + (-x*y^2*z - 3*t*x) dx/\dz + (t^2*x + + (t^2 + 1)*y^2 + x^2) dy/\dz + sage: s == a.contract(c) + True + + Case `p=2` and `q=3`:: + + sage: d = M.multivector_field(2, name='d') + sage: d[0,1], d[0,2], d[0,3] = t-x, 2*z, y-1 + sage: d[1,2], d[1,3], d[2,3] = z^2, y*t, 4 + sage: s = d.interior_product(c); s + 1-form i_d c on the 4-dimensional differentiable manifold M + sage: s.display() + i_d c = (2*x*y*z^2 - 6*t^2*y - 2*z^3 + 8*t^2 + 8*x) dt + + (-4*x*y*z + 6*t*y + 8*y^2 + 4*z^2 - 6*t) dx + + (-2*t*y^3 + 2*t^2 - 2*(t^2 - (t - 1)*x + x^2)*y - 2*(t - x)*z + + 2*x) dy + (2*y^2*z^2 - 6*t^2 + 6*t*x + 4*(t^2 + x)*z) dz + sage: s == d.contract(0, 1, c, 0, 1) + True + + """ + if self._domain.is_subset(form._domain): + if not self._ambient_domain.is_subset(form._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif form._domain.is_subset(self._domain): + if not form._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(form._domain) + self_r = self.restrict(dom_resu) + form_r = form.restrict(dom_resu) + return AlternatingContrTensor.interior_product(self_r, form_r) diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index d0709bc5ce2..964104a42ad 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -36,6 +36,7 @@ - Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version - Marco Mancini (2015): parallelization of vector field plots - Travis Scrimshaw (2016): review tweaks +- Eric Gourgoulhon (2017): vector fields inherit from multivector fields REFERENCES: @@ -47,7 +48,7 @@ """ #****************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon +# Copyright (C) 2015, 2017 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2015 Marco Mancini # Copyright (C) 2016 Travis Scrimshaw @@ -59,11 +60,11 @@ #****************************************************************************** from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, MultivectorFieldParal) from sage.misc.decorators import options -class VectorField(TensorField): +class VectorField(MultivectorField): r""" Vector field along a differentiable manifold. @@ -229,10 +230,10 @@ def __init__(self, vector_field_module, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - TensorField.__init__(self, vector_field_module, (1,0), name=name, - latex_name=latex_name) + MultivectorField.__init__(self, vector_field_module, 1, name=name, + latex_name=latex_name) # Initialization of derived quantities: - TensorField._init_derived(self) + MultivectorField._init_derived(self) # Initialization of list of quantities depending on self: self._init_dependencies() @@ -360,7 +361,8 @@ def __call__(self, scalar): else: resu_name = None if self._latex_name is not None and scalar._latex_name is not None: - resu_latex = r"{}\left({}\right)".format(self._latex_name , scalar._latex_name) + resu_latex = r"{}\left({}\right)".format(self._latex_name , + scalar._latex_name) else: resu_latex = None resu = dom_resu.scalar_field(name=resu_name, latex_name=resu_latex) @@ -934,7 +936,8 @@ def bracket(self, other): #****************************************************************************** -class VectorFieldParal(FiniteRankFreeModuleElement, TensorFieldParal, VectorField): +class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, + VectorField): r""" Vector field along a differentiable manifold, with values on a parallelizable manifold. @@ -1146,13 +1149,13 @@ def __init__(self, vector_field_module, name=None, latex_name=None): """ FiniteRankFreeModuleElement.__init__(self, vector_field_module, name=name, latex_name=latex_name) - # TensorFieldParal attributes: + # MultivectorFieldParal attributes: self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain # VectorField attributes: self._vmodule = vector_field_module # Initialization of derived quantities: - TensorFieldParal._init_derived(self) + MultivectorFieldParal._init_derived(self) VectorField._init_derived(self) # Initialization of list of quantities depending on self: self._init_dependencies() @@ -1210,7 +1213,8 @@ def _del_derived(self, del_restrictions=True): sage: v._del_derived() """ - TensorFieldParal._del_derived(self, del_restrictions=del_restrictions) + MultivectorFieldParal._del_derived(self, + del_restrictions=del_restrictions) VectorField._del_derived(self) self._del_dependencies() diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 9adc6a62e69..511b3749abf 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -882,6 +882,8 @@ def alternating_form(self, degree, name=None, latex_name=None): for more examples and documentation. """ + if degree == 0: + return self._domain.scalar_field(name=name, latex_name=latex_name) return self.dual_exterior_power(degree).element_class(self, degree, name=name, latex_name=latex_name) From e2dee3319398f703dfd0699ddc4c8cc9dd11cbb7 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 11 Jul 2017 23:06:49 +0200 Subject: [PATCH 010/218] Complete implementation of interior products on manifolds --- .../differentiable/affine_connection.py | 12 +- .../differentiable/automorphismfield.py | 4 +- .../differentiable/automorphismfield_group.py | 36 ++-- .../manifolds/differentiable/diff_form.py | 200 +++++++++++++++++- .../differentiable/diff_form_module.py | 12 +- .../differentiable/levi_civita_connection.py | 14 +- src/sage/manifolds/differentiable/manifold.py | 20 +- src/sage/manifolds/differentiable/metric.py | 4 +- .../differentiable/multivector_module.py | 12 +- .../differentiable/multivectorfield.py | 22 +- .../manifolds/differentiable/tensorfield.py | 2 +- .../differentiable/tensorfield_module.py | 4 +- .../differentiable/tensorfield_paral.py | 2 +- .../manifolds/differentiable/vectorfield.py | 4 +- .../differentiable/vectorfield_module.py | 82 +++---- .../manifolds/differentiable/vectorframe.py | 2 +- 16 files changed, 308 insertions(+), 124 deletions(-) diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 0f6a47a72af..880aed00b46 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -42,7 +42,7 @@ class AffineConnection(SageObject): or `K=\CC`), let `C^\infty(M)` be the algebra of smooth functions `M\rightarrow K` (cf. :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`) - and let `\mathcal{X}(M)` be the `C^\infty(M)`-module of vector fields on + and let `\mathfrak{X}(M)` be the `C^\infty(M)`-module of vector fields on `M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). An *affine connection* on `M` is an operator @@ -50,14 +50,14 @@ class AffineConnection(SageObject): .. MATH:: \begin{array}{cccc} - \nabla: & \mathcal{X}(M)\times \mathcal{X}(M) & \longrightarrow & - \mathcal{X}(M) \\ + \nabla: & \mathfrak{X}(M)\times \mathfrak{X}(M) & \longrightarrow & + \mathfrak{X}(M) \\ & (u,v) & \longmapsto & \nabla_u v \end{array} that - - is `K`-bilinear, i.e. is bilinear when considering `\mathcal{X}(M)` as a + - is `K`-bilinear, i.e. is bilinear when considering `\mathfrak{X}(M)` as a vector space over `K` - is `C^\infty(M)`-linear w.r.t. the first argument: `\forall f\in C^\infty(M),\ \nabla_{fu} v = f\nabla_u v` @@ -83,13 +83,13 @@ class AffineConnection(SageObject): .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u v = \nabla v(., u) + \forall u \in\mathfrak{X}(M), \ \nabla_u v = \nabla v(., u) More generally for any tensor field `t\in T^{(k,l)}(M)`, we have .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u t = \nabla t(\ldots, u) + \forall u \in\mathfrak{X}(M), \ \nabla_u t = \nabla t(\ldots, u) .. NOTE:: diff --git a/src/sage/manifolds/differentiable/automorphismfield.py b/src/sage/manifolds/differentiable/automorphismfield.py index 29e146deb47..590ee5b82a3 100644 --- a/src/sage/manifolds/differentiable/automorphismfield.py +++ b/src/sage/manifolds/differentiable/automorphismfield.py @@ -66,7 +66,7 @@ class AutomorphismField(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``name`` -- (default: ``None``) name given to the field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the field; @@ -785,7 +785,7 @@ class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``name`` -- (default: ``None``) name given to the field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the field; diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index 00c8e182a03..7b8a66b01b1 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -5,15 +5,15 @@ `\Phi: U \rightarrow M` to a differentiable manifold `M` (possibly `U = M` and `\Phi=\mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group -`\mathrm{GL}(\mathcal{X}(U,\Phi))` of the module `\mathcal{X}(U,\Phi)` of +`\mathrm{GL}(\mathfrak{X}(U,\Phi))` of the module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). -Note that `\mathcal{X}(U, \Phi)` is a module over +Note that `\mathfrak{X}(U, \Phi)` is a module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. -Elements of `\mathrm{GL}(\mathcal{X}(U, \Phi))` are fields along `U` +Elements of `\mathrm{GL}(\mathfrak{X}(U, \Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. -Two classes implement `\mathrm{GL}(\mathcal{X}(U, \Phi))` depending +Two classes implement `\mathrm{GL}(\mathfrak{X}(U, \Phi))` depending whether `M` is parallelizable or not: :class:`AutomorphismFieldParalGroup` and :class:`AutomorphismFieldGroup`. @@ -57,12 +57,12 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): `\Phi: U \rightarrow M` to a differentiable manifold `M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group - `\mathrm{GL}(\mathcal{X}(U,\Phi))` of the module `\mathcal{X}(U,\Phi)` of + `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of the module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). - Note that `\mathcal{X}(U,\Phi)` is a module over + Note that `\mathfrak{X}(U,\Phi)` is a module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. - Elements of `\mathrm{GL}(\mathcal{X}(U,\Phi))` are fields along `U` of + Elements of `\mathrm{GL}(\mathfrak{X}(U,\Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. .. NOTE:: @@ -74,7 +74,7 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): - ``vector_field_module`` -- :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`; - module `\mathcal{X}(U,\Phi)` of vector fields along `U` with values on `M` + module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` EXAMPLES: @@ -95,7 +95,7 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): 2-dimensional differentiable manifold M ``G`` is the general linear group of the vector field module - `\mathcal{X}(M)`:: + `\mathfrak{X}(M)`:: sage: XM = M.vector_field_module() ; XM Module X(M) of vector fields on the 2-dimensional differentiable @@ -334,9 +334,9 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: G = M.automorphism_field_group() sage: G._latex_() - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) sage: latex(G) # indirect doctest - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) """ from sage.misc.latex import latex @@ -388,12 +388,12 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): `\Phi: U \rightarrow M` to a parallelizable manifold `M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group - `\mathrm{GL}(\mathcal{X}(U, \Phi))` of the module `\mathcal{X}(U, \Phi)` + `\mathrm{GL}(\mathfrak{X}(U, \Phi))` of the module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`). - Note that `\mathcal{X}(U, \Phi)` is a free module over `C^k(U)`, + Note that `\mathfrak{X}(U, \Phi)` is a free module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. - Elements of `\mathrm{GL}(\mathcal{X}(U, \Phi))` are fields along `U` of + Elements of `\mathrm{GL}(\mathfrak{X}(U, \Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. .. NOTE:: @@ -405,7 +405,7 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): - ``vector_field_module`` -- :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`; - free module `\mathcal{X}(U,\Phi)` of vector fields along `U` + free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` EXAMPLES: @@ -422,10 +422,10 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): General linear group of the Free module X(M) of vector fields on the 2-dimensional differentiable manifold M sage: latex(G) - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) ``G`` is nothing but the general linear group of the module - `\mathcal{X}(M)`:: + `\mathfrak{X}(M)`:: sage: G is XM.general_linear_group() True @@ -452,7 +452,7 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): sage: a.parent() is G True - As automorphisms of `\mathcal{X}(M)`, the elements of ``G`` map a vector + As automorphisms of `\mathfrak{X}(M)`, the elements of ``G`` map a vector field to a vector field:: sage: v = XM.an_element() ; v diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index 671e087d03b..666cf2a295b 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -103,7 +103,7 @@ class DiffForm(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the differential form (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the differential form @@ -598,6 +598,155 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + def interior_product(self, qvect): + r""" + Interior product with a multivector field. + + If ``self`` is a differential form `A` of degree `p` and `B` is a + multivector field of degree `q\geq p` on the same manifold, the + interior product of `A` by `B` is the multivector field `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p} + B^{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract` + + INPUT: + + - ``qvect`` -- multivector field `B` (instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + (case `p = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + 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: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.one_form(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.multivector_field(2, name='b') + sage: b[e_xy,1,2] = x*y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.interior_product(b); s + Vector field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + i_a b = -x^2*y d/dx + x*y^2 d/dy + sage: s.display(e_uv) + i_a b = (u^4*v - 3*u^2*v^3)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) d/du + + (3*u^3*v^2 - u*v^4)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) d/dv + sage: s == a.contract(b) + True + + Interior product of a 2-form with a 2-vector field:: + + sage: a = M.diff_form(2, name='a') + sage: a[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.interior_product(b); s + Scalar field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display() + i_a b: S^2 --> R + on U: (x, y) |--> 8*x*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) + on V: (u, v) |--> 8*u*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) + + Some checks:: + + sage: s == a.contract(0, 1, b, 0, 1) + True + sage: s.restrict(U) == 2 * a[[e_xy,1,2]] * b[[e_xy,1,2]] + True + sage: s.restrict(V) == 2 * a[[e_uv,1,2]] * b[[e_uv,1,2]] + True + + """ + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(qvect._domain): + if not self._ambient_domain.is_subset(qvect._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif qvect._domain.is_subset(self._domain): + if not qvect._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(qvect._domain) + ambient_dom_resu = self._ambient_domain.intersection(qvect._ambient_domain) + self_r = self.restrict(dom_resu) + qvect_r = qvect.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.interior_product(self_r, qvect_r) + # Otherwise, the result is created here: + # Name of the result + resu_name = None + if self._name is not None and qvect._name is not None: + sname = self._name + oname = qvect._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = 'i_' + sname + ' ' + oname + resu_latex_name = None + if self._latex_name is not None and qvect._latex_name is not None: + slname = self._latex_name + olname = qvect._latex_name + if not is_atomic(olname): + olname = r'\left(' + olname + r'\right)' + resu_latex_name = r'\iota_{' + slname + '} ' + olname + # Domain and computation of the result + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = qvect._tensor_rank - self._tensor_rank + resu = vmodule.alternating_contravariant_tensor(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in qvect_r._restrictions: + resu._restrictions[dom] = \ + self_r._restrictions[dom].interior_product( + qvect_r._restrictions[dom]) + if resu_degree == 0: + if not resu._express: # only the restrictions to subdomains have + # been initialized + for chart in dom_resu.top_charts(): + resu._express[chart] = \ + resu.restrict(chart.domain()).coord_function(chart) + return resu #****************************************************************************** @@ -638,7 +787,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the differential form (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the differential form @@ -1288,24 +1437,55 @@ def interior_product(self, qvect): INPUT: - ``qvect`` -- multivector field `B` (instance of - :class:`~sage.manifolds.differentiable.multivectorfield.MultiVectorFieldParal`); - the degree of `B` must be at least equal to the degree of ``self`` + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`); + the degree of `B` must be at least equal to the degree of + ``self`` OUTPUT: - scalar field (case `p=q`) or - :class:`~sage.manifolds.differentiable.multivectorfield.MultiVectorFieldParal` - (case `p = M.chart() + sage: a = M.one_form(name='a') + sage: a[:] = [2, 1+x, y*z] + sage: b = M.multivector_field(2, name='b') + sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, -z^2 + sage: s = a.interior_product(b); s + Vector field i_a b on the 3-dimensional differentiable + manifold M + sage: s.display() + i_a b = (-(x + 1)*y^2 - x*y*z - y*z^2) d/dx + + (y*z^3 + 2*y^2) d/dy + (-(x + 1)*z^2 + 2*x + 2*z) d/dz + sage: s == a.contract(b) + True + + Interior product of a 2-form with a 2-vector field:: + + sage: a = M.diff_form(2, name='a') + sage: a[1,2], a[1,3], a[2,3] = x*y, -3, z + sage: s = a.interior_product(b); s + Scalar field i_a b on the 3-dimensional differentiable manifold M + sage: s.display() + i_a b: M --> R + (x, y, z) |--> 2*x*y^3 - 2*z^3 - 6*x - 6*z + sage: s == a.contract(0,1,b,0,1) + True + """ if self._domain.is_subset(qvect._domain): if not self._ambient_domain.is_subset(qvect._ambient_domain): diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 648c5a0dee6..ae6eb11d925 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -68,7 +68,7 @@ class DiffFormModule(UniqueRepresentation, Parent): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U, \Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M` via the map `\Phi: U \rightarrow M` - ``degree`` -- positive integer; the degree `p` of the differential forms @@ -95,7 +95,7 @@ class DiffFormModule(UniqueRepresentation, Parent): \Omega^{2}\left(M\right) ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. - we have `\Omega^{2}(M) = \Lambda^2(\mathcal{X}(M)^*)`:: + we have `\Omega^{2}(M) = \Lambda^2(\mathfrak{X}(M)^*)`:: sage: A is XM.dual_exterior_power(2) True @@ -158,7 +158,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a.display(eV) a = (-3/4*u - 3/4*v) du/\dv - The module `\Omega^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathfrak{X}(M)` (the module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 @@ -568,7 +568,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow V` - ``degree`` -- positive integer; the degree `p` of the differential forms @@ -588,7 +588,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): \Omega^{2}\left(M\right) ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. - we have `\Omega^{2}(M) = \Lambda^2(\mathcal{X}(M)^*)` (see + we have `\Omega^{2}(M) = \Lambda^2(\mathfrak{X}(M)^*)` (see :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`):: sage: A is XM.dual_exterior_power(2) @@ -643,7 +643,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: a.display() a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz - The module `\Omega^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathfrak{X}(M)` (the free module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 0e6727b1b70..752fe334b79 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -42,7 +42,7 @@ class LeviCivitaConnection(AffineConnection): Let `C^\infty(M)` be the algebra of smooth functions `M\rightarrow \RR` (cf. :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`) - and let `\mathcal{X}(M)` be the `C^\infty(M)`-module of vector fields on + and let `\mathfrak{X}(M)` be the `C^\infty(M)`-module of vector fields on `M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). The *Levi-Civita connection associated with* `g` is the unique operator @@ -50,14 +50,14 @@ class LeviCivitaConnection(AffineConnection): .. MATH:: \begin{array}{cccc} - \nabla: & \mathcal{X}(M)\times \mathcal{X}(M) & \longrightarrow & - \mathcal{X}(M) \\ + \nabla: & \mathfrak{X}(M)\times \mathfrak{X}(M) & \longrightarrow & + \mathfrak{X}(M) \\ & (u,v) & \longmapsto & \nabla_u v \end{array} that - - is `\RR`-bilinear, i.e. is bilinear when considering `\mathcal{X}(M)` as + - is `\RR`-bilinear, i.e. is bilinear when considering `\mathfrak{X}(M)` as a vector space over `\RR` - is `C^\infty(M)`-linear w.r.t. the first argument: `\forall f\in C^\infty(M),\ \nabla_{fu} v = f\nabla_u v` @@ -65,7 +65,7 @@ class LeviCivitaConnection(AffineConnection): `\forall f\in C^\infty(M),\ \nabla_u (f v) = \mathrm{d}f(u)\, v + f \nabla_u v` - is torsion-free - is compatible with `g`: - `\forall (u,v,w)\in \mathcal{X}(M)^3,\ u(g(v,w)) = g(\nabla_u v, w) + g(v, \nabla_u w)` + `\forall (u,v,w)\in \mathfrak{X}(M)^3,\ u(g(v,w)) = g(\nabla_u v, w) + g(v, \nabla_u w)` The Levi-Civita connection `\nabla` gives birth to the *covariant derivative operator* acting on tensor fields, denoted by the same symbol: @@ -86,13 +86,13 @@ class LeviCivitaConnection(AffineConnection): .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u v = \nabla v(., u) + \forall u \in\mathfrak{X}(M), \ \nabla_u v = \nabla v(., u) More generally for any tensor field `t\in T^{(k,l)}(M)`, we have .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u t = \nabla t(\ldots, u) + \forall u \in\mathfrak{X}(M), \ \nabla_u t = \nabla t(\ldots, u) .. NOTE:: diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index ffc74bc6bb3..62d9623f049 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -1097,12 +1097,12 @@ def vector_field_module(self, dest_map=None, force_free=False): :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` (or if `N` is parallelizable, a :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`) - representing the module `\mathcal{X}(M,\Phi)` of vector fields on + representing the module `\mathfrak{X}(M,\Phi)` of vector fields on `M` taking values on `\Phi(M)\subset N` EXAMPLES: - Vector field module `\mathcal{X}(U) := \mathcal{X}(U,\mathrm{Id}_U)` + Vector field module `\mathfrak{X}(U) := \mathfrak{X}(U,\mathrm{Id}_U)` of the complement `U` of the two poles on the sphere `\mathbb{S}^2`:: sage: S2 = Manifold(2, 'S^2') @@ -1121,7 +1121,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.base_ring() is U.scalar_field_algebra() True - `\mathcal{X}(U)` is a free module because `U` is parallelizable + `\mathfrak{X}(U)` is a free module because `U` is parallelizable (being a chart domain):: sage: U.is_manifestly_parallelizable() @@ -1132,7 +1132,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.rank() 2 - The elements of `\mathcal{X}(U)` are vector fields on `U`:: + The elements of `\mathfrak{X}(U)` are vector fields on `U`:: sage: XU.an_element() Vector field on the Open subset U of the 2-dimensional @@ -1140,7 +1140,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.an_element().display() 2 d/dth + 2 d/dph - Vector field module `\mathcal{X}(U,\Phi)` of the + Vector field module `\mathfrak{X}(U,\Phi)` of the `\RR^3`-valued vector fields along `U`, associated with the embedding `\Phi` of `\mathbb{S}^2` into `\RR^3`:: @@ -1156,7 +1156,7 @@ def vector_field_module(self, dest_map=None, force_free=False): Algebra of differentiable scalar fields on the Open subset U of the 2-dimensional differentiable manifold S^2 - `\mathcal{X}(U,\Phi)` is a free module because `\RR^3` + `\mathfrak{X}(U,\Phi)` is a free module because `\RR^3` is parallelizable and its rank is 3:: sage: XU_R3.rank() @@ -1366,8 +1366,8 @@ def automorphism_field_group(self, dest_map=None): If `M` is the current manifold and `\Phi` a differentiable map `\Phi: M \rightarrow N`, where `N` is a differentiable manifold, this method called with ``dest_map`` being `\Phi` returns the - general linear group `\mathrm{GL}(\mathcal{X}(M, \Phi))` of the module - `\mathcal{X}(M, \Phi)` of vector fields along `M` with values in + general linear group `\mathrm{GL}(\mathfrak{X}(M, \Phi))` of the module + `\mathfrak{X}(M, \Phi)` of vector fields along `M` with values in `\Phi(M) \subset N`. INPUT: @@ -1386,7 +1386,7 @@ def automorphism_field_group(self, dest_map=None): (if `N` is parallelizable) or a :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldGroup` (if `N` is not parallelizable) representing - `\mathrm{GL}(\mathcal{X}(U, \Phi))` + `\mathrm{GL}(\mathfrak{X}(U, \Phi))` EXAMPLES: @@ -1472,7 +1472,7 @@ def vector_field(self, name=None, latex_name=None, dest_map=None): Vector field v on the Open subset U of the 3-dimensional differentiable manifold M - The vector fields on `U` form the set `\mathcal{X}(U)`, which is a + The vector fields on `U` form the set `\mathfrak{X}(U)`, which is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`:: diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index aee2e03dcc5..3cd6ad32357 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -69,7 +69,7 @@ class PseudoRiemannianMetric(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `\Phi(U)\subset M` - ``name`` -- name given to the metric - ``signature`` -- (default: ``None``) signature `S` of the metric as a @@ -1882,7 +1882,7 @@ class PseudoRiemannianMetricParal(PseudoRiemannianMetric, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `\Phi(U)\subset M` - ``name`` -- name given to the metric - ``signature`` -- (default: ``None``) signature `S` of the metric as a diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index 07daf8e4495..a2799a60331 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -67,7 +67,7 @@ class :class:`MultivectorFreeModule` must be used instead. INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U, \Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M` via the map `\Phi: U \rightarrow M` - ``degree`` -- positive integer; the degree `p` of the multivector @@ -98,7 +98,7 @@ class :class:`MultivectorFreeModule` must be used instead. A^{2}\left(M\right) ``A`` is nothing but the second exterior power of of ``XM``, i.e. - we have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))`:: + we have `A^{2}(M) = \Lambda^2(\mathfrak{X}(M))`:: sage: A is XM.exterior_power(2) True @@ -163,7 +163,7 @@ class :class:`MultivectorFreeModule` must be used instead. sage: a.display(eV) a = (-3*u - 3*v) d/du/\d/dv - The module `A^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `A^1(M)` is nothing but the dual of `\mathfrak{X}(M)` (the module of vector fields on `M`):: sage: A1 = M.multivector_module(1) ; A1 @@ -520,7 +520,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow V` - ``degree`` -- positive integer; the degree `p` of the multivector @@ -543,7 +543,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): A^{2}\left(M\right) ``A`` is nothing but the second exterior power of ``XM``, i.e. we - have `A^{2}(M) = \Lambda^2(\mathcal{X}(M))` (see + have `A^{2}(M) = \Lambda^2(\mathfrak{X}(M))` (see :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`):: sage: A is XM.exterior_power(2) @@ -601,7 +601,7 @@ class MultivectorFreeModule(ExtPowerFreeModule): sage: a.display() a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz - The module `A^1(M)` is nothing but `\mathcal{X}(M)` (the free module + The module `A^1(M)` is nothing but `\mathfrak{X}(M)` (the free module of vector fields on `M`):: sage: A1 = M.multivector_module(1) ; A1 diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 873cac2f9e9..26efc093816 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -79,7 +79,7 @@ class MultivectorField(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector fields + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the multivector field @@ -364,12 +364,12 @@ def interior_product(self, form): .. SEEALSO:: :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.interior_product` - for the interior product of an differential form by a multivector + for the interior product of a differential form with a multivector field EXAMPLES: - Interior product of a vector field (`p=1`) by a 2-form (`q=2`) on the + Interior product of a vector field (`p=1`) with a 2-form (`q=2`) on the 2-sphere:: sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2 @@ -550,7 +550,7 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the multivector field @@ -865,8 +865,8 @@ def wedge(self, other): OUTPUT: - - instance of :class:`MultivectorFieldParal` representing the exterior - product ``self/\other`` + - instance of :class:`MultivectorFieldParal` representing the + exterior product ``self/\other`` EXAMPLES: @@ -884,7 +884,8 @@ def wedge(self, other): sage: b.display() b = y^2 d/dx/\d/dy + (x + z) d/dx/\d/dz + z^2 d/dy/\d/dz sage: s = a.wedge(b); s - 3-vector field a/\b on the 3-dimensional differentiable manifold M + 3-vector field a/\b on the 3-dimensional differentiable + manifold M sage: s.display() a/\b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) d/dx/\d/dy/\d/dz @@ -946,8 +947,8 @@ def interior_product(self, form): .. SEEALSO:: :meth:`~sage.manifolds.differentiable.diff_form.DiffFormParal.interior_product` - for the interior product of an differential form by a multivector - field + for the interior product of a differential form with a + multivector field EXAMPLES: @@ -963,7 +964,8 @@ def interior_product(self, form): Scalar field i_a b on the 4-dimensional differentiable manifold M sage: s.display() i_a b: M --> R - (t, x, y, z) |--> x^2*y*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 - 3*x + 2 + (t, x, y, z) |--> x^2*y*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 + - 3*x + 2 In this case, we have `\iota_a b = a^i b_i = a(b) = b(a)`:: diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index e2ba35c4af0..7acc164701c 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -105,7 +105,7 @@ class TensorField(ModuleElement): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`) - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 02e78b11b10..8614ff2edf3 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -96,7 +96,7 @@ class TensorFieldModule(UniqueRepresentation, Parent): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank and `l` the covariant rank @@ -628,7 +628,7 @@ class TensorFieldFreeModule(TensorFreeModule): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank and `l` the covariant rank diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index b208f8b8825..3942affcc5a 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -342,7 +342,7 @@ class TensorFieldParal(FreeModuleTensor, TensorField): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`) - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index 964104a42ad..aa7c59673aa 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -102,7 +102,7 @@ class VectorField(MultivectorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset\Phi(U)` - ``name`` -- (default: ``None``) name given to the vector field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector @@ -976,7 +976,7 @@ class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset\Phi(U)` - ``name`` -- (default: ``None``) name given to the vector field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 511b3749abf..cd12df3ff7d 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -58,7 +58,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): \Phi:\ U \longrightarrow M, - the *vector field module* `\mathcal{X}(U,\Phi)` is the set of + the *vector field module* `\mathfrak{X}(U,\Phi)` is the set of all vector fields of the type .. MATH:: @@ -73,7 +73,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): where `T_{\Phi(p)}M` is the tangent space to `M` at the point `\Phi(p)`. - The set `\mathcal{X}(U,\Phi)` is a module over `C^k(U)`, the ring + The set `\mathfrak{X}(U,\Phi)` is a module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). Furthermore, it is a Lie algebroid under the Lie bracket (cf. @@ -89,7 +89,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): The standard case of vector fields *on* a differentiable manifold corresponds to `U = M` and `\Phi = \mathrm{Id}_M`; we then denote - `\mathcal{X}(M,\mathrm{Id}_M)` by merely `\mathcal{X}(M)`. Other common + `\mathfrak{X}(M,\mathrm{Id}_M)` by merely `\mathfrak{X}(M)`. Other common cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). @@ -126,7 +126,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): Module X(M) of vector fields on the 2-dimensional differentiable manifold M - `\mathcal{X}(M)` is a module over the algebra `C^k(M)`:: + `\mathfrak{X}(M)` is a module over the algebra `C^k(M)`:: sage: XM.category() Category of modules over Algebra of differentiable scalar fields on the @@ -134,7 +134,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: XM.base_ring() is M.scalar_field_algebra() True - `\mathcal{X}(M)` is not a free module:: + `\mathfrak{X}(M)` is not a free module:: sage: isinstance(XM, FiniteRankFreeModule) False @@ -162,8 +162,8 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: z.display(c_uv.frame()) zero = 0 - The module `\mathcal{X}(M)` coerces to any module of vector fields defined - on a subdomain of `M`, for instance `\mathcal{X}(U)`:: + The module `\mathfrak{X}(M)` coerces to any module of vector fields defined + on a subdomain of `M`, for instance `\mathfrak{X}(U)`:: sage: XU.has_coerce_map_from(XM) True @@ -209,7 +209,7 @@ def __init__(self, domain, dest_map=None): """ self._domain = domain name = "X(" + domain._name - latex_name = r"\mathcal{X}\left(" + domain._latex_name + latex_name = r"\mathfrak{X}\left(" + domain._latex_name if dest_map is None: dest_map = domain.identity_map() self._dest_map = dest_map @@ -362,9 +362,9 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM._latex_() - '\\mathcal{X}\\left(M\\right)' + '\\mathfrak{X}\\left(M\\right)' sage: latex(XM) # indirect doctest - \mathcal{X}\left(M\right) + \mathfrak{X}\left(M\right) """ if self._latex_name is None: @@ -376,7 +376,7 @@ def domain(self): r""" Return the domain of the vector fields in this module. - If the module is `\mathcal{X}(U,\Phi)`, returns the domain `U` of + If the module is `\mathfrak{X}(U,\Phi)`, returns the domain `U` of `\Phi`. OUTPUT: @@ -406,7 +406,7 @@ def ambient_domain(self): Return the manifold in which the vector fields of this module take their values. - If the module is `\mathcal{X}(U,\Phi)`, returns the codomain `M` of + If the module is `\mathfrak{X}(U,\Phi)`, returns the codomain `M` of `\Phi`. OUTPUT: @@ -441,7 +441,7 @@ def destination_map(self): \Phi:\ U \longrightarrow M - such that this module is the set `\mathcal{X}(U,\Phi)` of all + such that this module is the set `\mathfrak{X}(U,\Phi)` of all vector fields of the type .. MATH:: @@ -534,7 +534,7 @@ def exterior_power(self, p): r""" Return the `p`-th exterior power of ``self``. - If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, its `p`-th exterior power is the set `A^p(U, \Phi)` of `p`-vector fields along `U` with values on `\Phi(U)`. It is a module over `C^k(U)`, the ring (algebra) of differentiable @@ -548,7 +548,7 @@ def exterior_power(self, p): - for `p=0`, the base ring, i.e. `C^k(U)` - for `p=1`, the vector field module ``self``, since - `A^1(U, \Phi) = \mathcal{X}(U,\Phi)` + `A^1(U, \Phi) = \mathfrak{X}(U,\Phi)` - for `p \geq 2`, instance of :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` representing the module `A^p(U,\Phi)` @@ -592,7 +592,7 @@ def dual_exterior_power(self, p): Return the `p`-th exterior power of the dual of the vector field module. - If the vector field module is `\mathcal{X}(U,\Phi)`, the + If the vector field module is `\mathfrak{X}(U,\Phi)`, the `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `\Phi(U)`. It is a module over `C^k(U)`, the ring (algebra) of differentiable scalar @@ -659,17 +659,17 @@ def general_linear_group(self): r""" Return the general linear group of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the *general - linear group* is the group `\mathrm{GL}(\mathcal{X}(U,\Phi))` of - automorphisms of `\mathcal{X}(U, \Phi)`. Note that an automorphism - of `\mathcal{X}(U,\Phi)` can also be viewed as a *field* along `U` + If the vector field module is `\mathfrak{X}(U,\Phi)`, the *general + linear group* is the group `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of + automorphisms of `\mathfrak{X}(U, \Phi)`. Note that an automorphism + of `\mathfrak{X}(U,\Phi)` can also be viewed as a *field* along `U` of automorphisms of the tangent spaces of `M \supset \Phi(U)`. OUTPUT: - instance of class :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldGroup` - representing `\mathrm{GL}(\mathcal{X}(U,\Phi))` + representing `\mathrm{GL}(\mathfrak{X}(U,\Phi))` EXAMPLES:: @@ -837,6 +837,8 @@ def alternating_contravariant_tensor(self, degree, name=None, for more examples and documentation. """ + if degree == 0: + return self._domain.scalar_field(name=name, latex_name=latex_name) if degree == 1: return self.element_class(self, name=name, latex_name=latex_name) @@ -1084,7 +1086,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): \Phi:\ U \longrightarrow M - the *vector field module* `\mathcal{X}(U,\Phi)` is the set of all vector + the *vector field module* `\mathfrak{X}(U,\Phi)` is the set of all vector fields of the type .. MATH:: @@ -1099,7 +1101,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): where `T_{\Phi(p)} M` is the tangent space to `M` at the point `\Phi(p)`. - Since `M` is parallelizable, the set `\mathcal{X}(U,\Phi)` is a + Since `M` is parallelizable, the set `\mathfrak{X}(U,\Phi)` is a free module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). @@ -1108,14 +1110,14 @@ class VectorFieldFreeModule(FiniteRankFreeModule): The standard case of vector fields *on* a differentiable manifold corresponds to `U=M` and `\Phi = \mathrm{Id}_M`; we then denote - `\mathcal{X}(M,\mathrm{Id}_M)` by merely `\mathcal{X}(M)`. Other common + `\mathfrak{X}(M,\mathrm{Id}_M)` by merely `\mathfrak{X}(M)`. Other common cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). .. NOTE:: If `M` is not parallelizable, the class :class:`VectorFieldModule` - should be used instead, for `\mathcal{X}(U,\Phi)` is no longer a + should be used instead, for `\mathfrak{X}(U,\Phi)` is no longer a free module. INPUT: @@ -1182,7 +1184,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): over Algebra of differentiable scalar fields on the 1-dimensional differentiable manifold I - The rank of the free module `\mathcal{X}(I,\Phi)` is the dimension + The rank of the free module `\mathfrak{X}(I,\Phi)` is the dimension of the manifold `\RR^2`, namely two:: sage: XIM.rank() @@ -1274,8 +1276,8 @@ class VectorFieldFreeModule(FiniteRankFreeModule): sage: z.display(c_t.frame()) zero = 0 - The module `\mathcal{X}(S^1)` coerces to any module of vector fields - defined on a subdomain of `S^1`, for instance `\mathcal{X}(U)`:: + The module `\mathfrak{X}(S^1)` coerces to any module of vector fields + defined on a subdomain of `S^1`, for instance `\mathfrak{X}(U)`:: sage: XU = U.vector_field_module() ; XU Free module X(U) of vector fields on the Open subset U of the @@ -1324,7 +1326,7 @@ def __init__(self, domain, dest_map=None): self._dest_map = dest_map self._ambient_domain = self._dest_map._codomain name = "X(" + domain._name - latex_name = r"\mathcal{X}\left(" + domain._latex_name + latex_name = r"\mathfrak{X}\left(" + domain._latex_name if self._dest_map == domain.identity_map(): name += ")" latex_name += r"\right)" @@ -1451,7 +1453,7 @@ def domain(self): r""" Return the domain of the vector fields in ``self``. - If the module is `\mathcal{X}(U, \Phi)`, returns the domain `U` + If the module is `\mathfrak{X}(U, \Phi)`, returns the domain `U` of `\Phi`. OUTPUT: @@ -1483,7 +1485,7 @@ def ambient_domain(self): Return the manifold in which the vector fields of ``self`` take their values. - If the module is `\mathcal{X}(U, \Phi)`, returns the codomain `M` + If the module is `\mathfrak{X}(U, \Phi)`, returns the codomain `M` of `\Phi`. OUTPUT: @@ -1520,7 +1522,7 @@ def destination_map(self): \Phi:\ U \longrightarrow M - such that this module is the set `\mathcal{X}(U,\Phi)` of all vector + such that this module is the set `\mathfrak{X}(U,\Phi)` of all vector fields of the type .. MATH:: @@ -1617,7 +1619,7 @@ def exterior_power(self, p): r""" Return the `p`-th exterior power of ``self``. - If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, its `p`-th exterior power is the set `A^p(U, \Phi)` of `p`-vector fields along `U` with values on `\Phi(U)`. It is a free module over `C^k(U)`, the ring (algebra) of differentiable @@ -1631,7 +1633,7 @@ def exterior_power(self, p): - for `p=0`, the base ring, i.e. `C^k(U)` - for `p=1`, the vector field free module ``self``, since - `A^1(U, \Phi) = \mathcal{X}(U,\Phi)` + `A^1(U, \Phi) = \mathfrak{X}(U,\Phi)` - for `p \geq 2`, instance of :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule` representing the module `A^p(U,\Phi)` @@ -1675,7 +1677,7 @@ def dual_exterior_power(self, p): r""" Return the `p`-th exterior power of the dual of ``self``. - If the vector field module ``self`` is `\mathcal{X}(U,\Phi)`, + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, the `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `\Phi(U)`. It is a free module over `C^k(U)`, the ring (algebra) @@ -1729,17 +1731,17 @@ def general_linear_group(self): r""" Return the general linear group of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the *general - linear group* is the group `\mathrm{GL}(\mathcal{X}(U,\Phi))` of - automorphisms of `\mathcal{X}(U,\Phi)`. Note that an automorphism of - `\mathcal{X}(U,\Phi)` can also be viewed as a *field* along `U` of + If the vector field module is `\mathfrak{X}(U,\Phi)`, the *general + linear group* is the group `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of + automorphisms of `\mathfrak{X}(U,\Phi)`. Note that an automorphism of + `\mathfrak{X}(U,\Phi)` can also be viewed as a *field* along `U` of automorphisms of the tangent spaces of `V=\Phi(U)`. OUTPUT: - a :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldParalGroup` - representing `\mathrm{GL}(\mathcal{X}(U,\Phi))` + representing `\mathrm{GL}(\mathfrak{X}(U,\Phi))` EXAMPLES:: diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 8cb44524e26..fa26407ff68 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -199,7 +199,7 @@ class VectorFrame(FreeModuleBasis): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U, \Phi)` + - ``vector_field_module`` -- free module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` - ``symbol`` -- a letter (of a few letters) to denote a generic vector of the frame; can be set to None if the parameter From 19abb49155d25a9283dbfc64f64ee5f0e445b9b1 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 12 Jul 2017 19:11:02 +0200 Subject: [PATCH 011/218] Start implementation of Schouten-Nijenhuis bracket (work in progress) --- .../differentiable/multivectorfield.py | 127 ++++++++++++++++++ .../manifolds/differentiable/vectorfield.py | 5 +- .../differentiable/vectorfield_module.py | 66 +++++---- .../tensor/modules/finite_rank_free_module.py | 20 +-- src/sage/tensor/modules/free_module_basis.py | 8 +- 5 files changed, 184 insertions(+), 42 deletions(-) diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 26efc093816..08b119a0999 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -1016,3 +1016,130 @@ def interior_product(self, form): self_r = self.restrict(dom_resu) form_r = form.restrict(dom_resu) return AlternatingContrTensor.interior_product(self_r, form_r) + + def bracket(self, other): + r""" + Schouten-Nijenhuis bracket of ``self`` with another multivector field. + + INPUT: + + - ``other`` -- another multivector field + + OUTPUT: + + - instance of :class:`MultivectorFieldParal` representing the + Schouten-Nijenhuis bracket ``[self,other]`` + + EXAMPLES: + + On a 3-dimensional manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: a = M.vector_field('a') + sage: a[:] = x, -x*y, z*x + sage: b = M.vector_field('b') + sage: b[:] = x*z^2, x*y*z, x+y + sage: s = a.bracket(b) ; s + + """ + from sage.tensor.modules.comp import (Components, CompWithSym, + CompFullyAntiSym) + from sage.manifolds.differentiable.scalarfield import DiffScalarField + pp = self._tensor_rank + mp1 = (-1)**(pp+1) + if isinstance(other, DiffScalarField): + resu = other.differential().interior_product(self) + if mp1 == 1: + return resu + return - resu + # Some checks: + if not isinstance(other, (MultivectorField, MultivectorFieldParal)): + raise TypeError("{} is not a multivector field".format(other)) + if (self._vmodule.destination_map() is not self._domain.identity_map() + or other._vmodule.destination_map() is not + other._domain.identity_map()): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + + "only for fields with a trivial destination map") + # Search for a common domain + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + # Search for a common coordinate frame: + coord_frame = self_r._common_coord_frame(other_r) + if coord_frame is None: + raise ValueError("no common coordinate frame found") + chart = coord_frame.chart() + print "chart: ", chart + dom_resu = chart.domain() + fmodule = dom_resu.vector_field_module() + print "fmodule: ", fmodule + ring = fmodule.base_ring() # same as dom_resu.scalar_field_algebra() + aa = self_r.comp(coord_frame) # components A^{i_1...i_p} + bb = other_r.comp(coord_frame) # components B^{j_1...j_q} + qq = other._tensor_rank + deg_resu = pp + qq - 1 # degree of the result + nn = dom_resu.dim() + print "aa : ", aa + print "bb : ", bb + if deg_resu == 1: + resuc = Components(ring, coord_frame, 1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + resuc = CompFullyAntiSym(ring, coord_frame, deg_resu, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + # Partial derivatives of the components of self: + if pp == 1: + daa = Components(ring, coord_frame, 2, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + daa = CompWithSym(ring, coord_frame, pp+1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter, + antisym=range(pp)) + for ind, val in aa._comp.items(): + for k in fmodule.irange(): + daa[[ind+(k,)]] = val.coord_function(chart).diff(k) + # Partial derivatives of the components of other: + if qq == 1: + dbb = Components(ring, coord_frame, 2, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + dbb = CompWithSym(ring, coord_frame, qq+1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter, + antisym=range(qq)) + for ind, val in bb._comp.items(): + for k in fmodule.irange(): + dbb[[ind+(k,)]] = val.coord_function(chart).diff(k) + # Computation + print "mp1 : ", mp1 + for ind_a, val_a in aa._comp.items(): + for ind_b in bb._comp: + ind_db = ind_b + (ind_a[0],) + ind = ind_a[1:] + ind_b + print "ind_a, ind_b, ind_db, ind : ", ind_a, ind_b, ind_db, ind + if len(ind) == len(set(ind)): # all indices are different + resuc[[ind]] += mp1 * val_a * dbb[[ind_db]] + for ind_b, val_b in bb._comp.items(): + for ind_a in aa._comp: + ind_da = ind_a + (ind_b[0],) + ind = ind_a + ind_b[1:] + print "ind_a, ind_b, ind_da, ind : ", ind_a, ind_b, ind_da, ind + if len(ind) == len(set(ind)): # all indices are different + resuc[[ind]] -= val_b * daa[[ind_da]] + # Name of the result: + resu_name = None ; resu_latex_name = None + if self._name is not None and other._name is not None: + resu_name = '[' + self._name + ',' + other._name + ']' + if self._latex_name is not None and other._latex_name is not None: + resu_latex_name = r'\left[' + self._latex_name + ',' + \ + other._latex_name + r'\right]' + # Creation of the multivector with the components obtained above: + resu = fmodule.tensor_from_comp((deg_resu, 0), resuc, name=resu_name, + latex_name=resu_latex_name) + return resu diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index aa7c59673aa..b04099989d3 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -932,7 +932,10 @@ def bracket(self, other): sage: vw.display() (-x^2 + y + 2) d/dy + (-y - z) d/dz """ - return other.lie_der(self) + #!# + # return other.lie_der(self) + #!# provisory: + return MultivectorFieldParal.bracket(self, other) #****************************************************************************** diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index cd12df3ff7d..35c7751c2ea 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -44,7 +44,8 @@ from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.differentiable.vectorfield import (VectorField, VectorFieldParal) +from sage.manifolds.differentiable.vectorfield import (VectorField, + VectorFieldParal) class VectorFieldModule(UniqueRepresentation, Parent): r""" @@ -114,9 +115,9 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole - sage: c_xy. = U.chart() # stereographic coordinates from the North pole + sage: c_xy. = U.chart() # stereographic coordinates from North pole sage: V = M.open_subset('V') # complement of the South pole - sage: c_uv. = V.chart() # stereographic coordinates from the South pole + sage: c_uv. = V.chart() # stereographic coordinates from South pole sage: M.declare_union(U,V) # S^2 is the union of U and V 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, @@ -169,8 +170,10 @@ class VectorFieldModule(UniqueRepresentation, Parent): True sage: XU.coerce_map_from(XM) Coercion map: - From: Module X(M) of vector fields on the 2-dimensional differentiable manifold M - To: Free module X(U) of vector fields on the Open subset U of the 2-dimensional differentiable manifold M + From: Module X(M) of vector fields on the 2-dimensional + differentiable manifold M + To: Free module X(U) of vector fields on the Open subset U of the + 2-dimensional differentiable manifold M The conversion map is actually the restriction of vector fields defined on `M` to `U`. @@ -187,9 +190,9 @@ def __init__(self, domain, dest_map=None): sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole - sage: c_xy. = U.chart() # stereographic coordinates from the North pole + sage: c_xy. = U.chart() # stereographic coordinates from North pole sage: V = M.open_subset('V') # complement of the South pole - sage: c_uv. = V.chart() # stereographic coordinates from the South pole + sage: c_uv. = V.chart() # stereographic coordinates from South pole sage: M.declare_union(U,V) # S^2 is the union of U and V 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, @@ -222,20 +225,21 @@ def __init__(self, domain, dest_map=None): self._ambient_domain = self._dest_map._codomain self._name = name self._latex_name = latex_name - # the member self._ring is created for efficiency (to avoid + # The member self._ring is created for efficiency (to avoid # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() Parent.__init__(self, base=self._ring, category=Modules(self._ring)) # Dictionary of the tensor modules built on self # (keys = (k,l) --the tensor type) - self._tensor_modules = {(1,0): self} # self is considered as the - # set of tensors of type (1,0) - # Dictionary of exterior powers of self - # (keys = p --the power degree) : - self._exterior_powers = {} - # Dictionary of exterior powers of the dual of self - # (keys = p --the power degree) : + # This dictionary is to be extended on need by the method tensor_module + self._tensor_modules = {(1,0): self} # self is considered as the set + # of tensors of type (1,0) + # Dictionaries of exterior powers of self and of its dual + # (keys = p --the power degree) + # These dictionaries are to be extended on need by the methods + # exterior_power and dual_exterior_power + self._exterior_powers = {1: self} self._dual_exterior_powers = {} #### Parent methods @@ -525,7 +529,8 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import TensorFieldModule + from sage.manifolds.differentiable.tensorfield_module import \ + TensorFieldModule if (k,l) not in self._tensor_modules: self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) return self._tensor_modules[(k,l)] @@ -578,11 +583,9 @@ def exterior_power(self, p): """ from sage.manifolds.differentiable.multivector_module import \ - MultivectorModule + MultivectorModule if p == 0: return self._ring - if p == 1: - return self if p not in self._exterior_powers: self._exterior_powers[p] = MultivectorModule(self, p) return self._exterior_powers[p] @@ -633,7 +636,8 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import DiffFormModule + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormModule if p == 0: return self._ring if p not in self._dual_exterior_powers: @@ -685,7 +689,8 @@ def general_linear_group(self): for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import \ + AutomorphismFieldGroup return AutomorphismFieldGroup(self) def tensor(self, tensor_type, name=None, latex_name=None, sym=None, @@ -1286,8 +1291,10 @@ class VectorFieldFreeModule(FiniteRankFreeModule): True sage: XU.coerce_map_from(XM) Coercion map: - From: Free module X(S^1) of vector fields on the 1-dimensional differentiable manifold S^1 - To: Free module X(U) of vector fields on the Open subset U of the 1-dimensional differentiable manifold S^1 + From: Free module X(S^1) of vector fields on the 1-dimensional + differentiable manifold S^1 + To: Free module X(U) of vector fields on the Open subset U of the + 1-dimensional differentiable manifold S^1 The conversion map is actually the restriction of vector fields defined on `S^1` to `U`. @@ -1610,7 +1617,8 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import \ + TensorFieldFreeModule if (k,l) not in self._tensor_modules: self._tensor_modules[(k,l)] = TensorFieldFreeModule(self, (k,l)) return self._tensor_modules[(k,l)] @@ -1664,11 +1672,9 @@ def exterior_power(self, p): """ from sage.manifolds.differentiable.multivector_module import \ - MultivectorFreeModule + MultivectorFreeModule if p == 0: return self._ring - if p == 1: - return self if p not in self._exterior_powers: self._exterior_powers[p] = MultivectorFreeModule(self, p) return self._exterior_powers[p] @@ -1758,7 +1764,8 @@ def general_linear_group(self): for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import \ + AutomorphismFieldParalGroup return AutomorphismFieldParalGroup(self) def basis(self, symbol=None, latex_symbol=None, from_frame=None): @@ -2103,6 +2110,7 @@ def metric(self, name, signature=None, latex_name=None): for more documentation. """ - from sage.manifolds.differentiable.metric import PseudoRiemannianMetricParal + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetricParal return PseudoRiemannianMetricParal(self, name, signature=signature, latex_name=latex_name) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 869ad5d44e6..2052126ee50 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -779,14 +779,18 @@ def __init__(self, ring, rank, name=None, latex_name=None, start_index=0, self._sindex = start_index self._output_formatter = output_formatter # Dictionary of the tensor modules built on self - # (keys = (k,l) --the tensor type) : - self._tensor_modules = {(1,0): self} # self is considered as the set of - # tensors of type (1,0) - # Dictionary of exterior powers of self and of the dual of self: - # (keys = p --the power degree) : - self._exterior_powers = {} + # (keys = (k,l) --the tensor type) + # This dictionary is to be extended on need by the method tensor_module + self._tensor_modules = {(1,0): self} # self is considered as the set + # of tensors of type (1,0) + # Dictionaries of exterior powers of self and of its dual + # (keys = p --the power degree) + # These dictionaries are to be extended on need by the methods + # exterior_power and dual_exterior_power + self._exterior_powers = {1: self} self._dual_exterior_powers = {} - self._known_bases = [] # List of known bases on the free module + # List of known bases on the free module: + self._known_bases = [] self._def_basis = None # default basis self._basis_changes = {} # Dictionary of the changes of bases # Zero element: @@ -1022,8 +1026,6 @@ def exterior_power(self, p): from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule if p == 0: return self._ring - if p == 1: - return self if p not in self._exterior_powers: self._exterior_powers[p] = ExtPowerFreeModule(self, p) return self._exterior_powers[p] diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 5a34f03a31f..9233350897e 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -266,15 +266,17 @@ def __init__(self, fmodule, symbol, latex_symbol=None): # Initialization of the components w.r.t the current basis of the zero # elements of all tensor modules constructed up to now (including the # base module itself, since it is considered as a type-(1,0) tensor - # module) + # module): for t in fmodule._tensor_modules.values(): t._zero_element._components[self] = t._zero_element._new_comp(self) # (since new components are initialized to zero) # Initialization of the components w.r.t the current basis of the zero - # elements of all exterior powers constructed up to now + # elements of all exterior powers of the module and its dual + # constructed up to now: + for t in fmodule._exterior_powers.values(): + t._zero_element._components[self] = t._zero_element._new_comp(self) for t in fmodule._dual_exterior_powers.values(): t._zero_element._components[self] = t._zero_element._new_comp(self) - # (since new components are initialized to zero) # The dual basis: self._dual_basis = self._init_dual_basis() From 7398cc8d42a7e21b4e6b6a55fede9dfa043044ed Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 13 Jul 2017 01:03:44 +0200 Subject: [PATCH 012/218] Complete implementation of Schouten-Nijenhuis bracket on parallelizable manifolds --- .../differentiable/multivectorfield.py | 127 ++++++++++++++---- 1 file changed, 103 insertions(+), 24 deletions(-) diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 08b119a0999..57c06f7f296 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -1036,13 +1036,73 @@ def bracket(self, other): sage: M = Manifold(3, 'M') sage: X. = M.chart() - sage: a = M.vector_field('a') - sage: a[:] = x, -x*y, z*x - sage: b = M.vector_field('b') - sage: b[:] = x*z^2, x*y*z, x+y - sage: s = a.bracket(b) ; s + sage: a = M.vector_field(name='a') + sage: a[:] = x*y+z, x^2+y-z, z^2-2*x+y + sage: b = M.vector_field(name='b') + sage: b[:] = y*z-x, x^2-y+z, z*x-1 + sage: s = a.bracket(b); s + Vector field [a,b] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,b] = (-x^3 + (y - 1)*z^2 - x*y + y^2 + (x^2 - y^2 - 2*x + y - 1)*z + 1) d/dx + + ((2*x^2 + 1)*y - (2*x*y - 3*x)*z + z^2 - 2*x - 1) d/dy + + (-(x - 1)*z^2 - 3*x^2 + (x + 1)*y + ((x + 2)*y + 1)*z - 2*x) d/dz + sage: s == b.lie_derivative(a) + True + sage: c = M.multivector_field(2, name='c') + sage: c[0,1], c[0,2], c[1,2] = x+y^2+z, x*y*z, z*x-y + sage: s = a.bracket(c); s + 2-vector field [a,c] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,c] = (2*x^2*y - y^3 + y^2 + ((x - 3)*y + x)*z + z^2 - 3*x) + d/dx/\d/dy + ((x - 1)*y^2 - ((x - 1)*y + x)*z^2 - (2*x^2 - x)*y + + (x^3 - x^2 + x*y - 1)*z - x) d/dx/\d/dz + (-(x - 1)*z^2 - 3*x^2 + + x*y - 2*y^2 - ((2*x^2 - x - 2)*y + x + 1)*z - 2*x) d/dy/\d/dz + sage: s == c.lie_derivative(a) + True + sage: d = M.multivector_field(2, name='d') + sage: d[0,1], d[0,2], d[1,2] = x^2-z, y*z+x, z-x+y^2-1 + sage: s = c.bracket(d); s + 3-vector field [c,d] on the 3-dimensional differentiable manifold M + sage: s.display() + [c,d] = (-x*y^3 - y*z^2 + (x^2 + 5*x + 2)*y + 2*y^2 + - ((x^2 + 1)*y - 2)*z) d/dx/\d/dy/\d/dz + sage: s[0,1,2] == - sum(c[i,0]*d[1,2].diff(i) + ....: + c[i,1]*d[2,0].diff(i) + c[i,2]*d[0,1].diff(i) + ....: + d[i,0]*c[1,2].diff(i) + d[i,1]*c[2,0].diff(i) + ....: + d[i,2]*c[0,1].diff(i) for i in M.irange()) + True + sage: e = M.multivector_field(3, name='e') + sage: e[0,1,2] = x^2+y*z-z+2 + sage: s = a.bracket(e); s + 3-vector field [a,e] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,e] = (-y*z^2 - x^2 + (x^2 - 2*x - 3)*y + y^2 - (x^2 + y^2 - 2*x - y + 3)*z + 2*x - 2) d/dx/\d/dy/\d/dz + sage: s == e.lie_derivative(a) + True + sage: s = c.bracket(e); s + 4-vector field [c,e] on the 3-dimensional differentiable manifold M + sage: s.display() + [c,e] = 0 + sage: a.bracket(b) == - b.bracket(a) + True + sage: a.bracket(c) == - c.bracket(a) + True + sage: c.bracket(d) == d.bracket(c) + True + sage: a.bracket(b.wedge(c)) == a.bracket(b).wedge(c) + b.wedge(a.bracket(c)) + True + sage: c.bracket(a.wedge(b)) == c.bracket(a).wedge(b) - a.wedge(c.bracket(b)) + True + sage: a.bracket(b.bracket(c)) + b.bracket(c.bracket(a)) \ + ....: + c.bracket(a.bracket(b)) == 0 + True + sage: a.bracket(c.bracket(d)) + c.bracket(d.bracket(a)) \ + ....: - d.bracket(a.bracket(c)) == 0 + True """ + from sage.sets.set import Set + from sage.combinat.permutation import Permutation from sage.tensor.modules.comp import (Components, CompWithSym, CompFullyAntiSym) from sage.manifolds.differentiable.scalarfield import DiffScalarField @@ -1070,18 +1130,14 @@ def bracket(self, other): if coord_frame is None: raise ValueError("no common coordinate frame found") chart = coord_frame.chart() - print "chart: ", chart dom_resu = chart.domain() fmodule = dom_resu.vector_field_module() - print "fmodule: ", fmodule ring = fmodule.base_ring() # same as dom_resu.scalar_field_algebra() aa = self_r.comp(coord_frame) # components A^{i_1...i_p} bb = other_r.comp(coord_frame) # components B^{j_1...j_q} qq = other._tensor_rank deg_resu = pp + qq - 1 # degree of the result nn = dom_resu.dim() - print "aa : ", aa - print "bb : ", bb if deg_resu == 1: resuc = Components(ring, coord_frame, 1, start_index=fmodule._sindex, @@ -1117,21 +1173,44 @@ def bracket(self, other): for k in fmodule.irange(): dbb[[ind+(k,)]] = val.coord_function(chart).diff(k) # Computation - print "mp1 : ", mp1 - for ind_a, val_a in aa._comp.items(): - for ind_b in bb._comp: - ind_db = ind_b + (ind_a[0],) - ind = ind_a[1:] + ind_b - print "ind_a, ind_b, ind_db, ind : ", ind_a, ind_b, ind_db, ind - if len(ind) == len(set(ind)): # all indices are different - resuc[[ind]] += mp1 * val_a * dbb[[ind_db]] - for ind_b, val_b in bb._comp.items(): - for ind_a in aa._comp: - ind_da = ind_a + (ind_b[0],) - ind = ind_a + ind_b[1:] - print "ind_a, ind_b, ind_da, ind : ", ind_a, ind_b, ind_da, ind - if len(ind) == len(set(ind)): # all indices are different - resuc[[ind]] -= val_b * daa[[ind_da]] + for ind in resuc.non_redundant_index_generator(): + sind = Set(ind) # {i_1, i_2, ..., i_{p+q-1}} + # Term a^{l j_2 ... j_p} \partial_l b^{k_1 ... k_q} + # with (j_2,...,j_p,k_1,...,k_q) spanning all permutations of + # (i_1, i_2, ..., i_{p+q-1}) + sub_sind_p = sind.subsets(pp-1) + for sind_a in sub_sind_p: + sind_b = sind.difference(sind_a) + ind_a = tuple(sorted(sind_a)) + ind_b = tuple(sorted(sind_b)) + ## print 'ind, ind_a, ind_b:', ind, ind_a, ind_b + sum = 0 + for l in fmodule.irange(): + sum += aa[[(l,) + ind_a]] * dbb[[ind_b + (l,)]] + ind_ab = ind_a + ind_b + sign = Permutation([ind_ab.index(i) + 1 for i in ind]).signature() + if mp1*sign == 1: + resuc[[ind]] += sum + else: + resuc[[ind]] -= sum + # Term b^{l k_2 ... k_q} \partial_l a^{j_1 ... j_p} + # with (j_1,...,j_p,k_2,...,k_q) spanning all permutations of + # (i_1, i_2, ..., i_{p+q-1}) + sub_sind_q = sind.subsets(qq-1) + for sind_b in sub_sind_q: + sind_a = sind.difference(sind_b) + ind_a = tuple(sorted(sind_a)) + ind_b = tuple(sorted(sind_b)) + ## print 'ind, ind_a, ind_b:', ind, ind_a, ind_b + sum = 0 + for l in fmodule.irange(): + sum += bb[[(l,) + ind_b]] * daa[[ind_a + (l,)]] + ind_ab = ind_a + ind_b + sign = Permutation([ind_ab.index(i) + 1 for i in ind]).signature() + if sign == 1: + resuc[[ind]] -= sum + else: + resuc[[ind]] += sum # Name of the result: resu_name = None ; resu_latex_name = None if self._name is not None and other._name is not None: From 42c4106dc340606e68627d35fde40ac51d80d0ab Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 13 Jul 2017 17:05:53 +0200 Subject: [PATCH 013/218] Add doctests and documentation for the Schouten-Nijenhuis bracket --- src/doc/en/reference/references/index.rst | 29 +- .../differentiable/multivector_module.py | 3 +- .../differentiable/multivectorfield.py | 327 +++++++++++++----- .../manifolds/differentiable/scalarfield.py | 124 +++++++ .../manifolds/differentiable/vectorfield.py | 6 +- 5 files changed, 393 insertions(+), 96 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 6599ef60e2f..95c4cc7f01f 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -235,10 +235,13 @@ REFERENCES: .. [Bir1975] \J. Birman. *Braids, Links, and Mapping Class Groups*, Princeton University Press, 1975 +.. [BG1980] \R. L. Bishop and S. L. Goldberg, *Tensor analysis on + Manifolds*, Dover (New York) (1980) + .. [BK1992] \U. Brehm and W. Kuhnel, "15-vertex triangulations of an 8-manifold", Math. Annalen 294 (1992), no. 1, 167-193. -.. [BK2001] W. Bruns and R. Koch, Computing the integral closure of an +.. [BK2001] \W. Bruns and R. Koch, Computing the integral closure of an affine semigroup. Uni. Iaggelonicae Acta Math. 39, (2001), 59-70 @@ -1049,11 +1052,15 @@ REFERENCES: 1998), Advanced Studies in Pure Mathematics, 30, 177-196, 2000. -.. [Koh2007] \A. Kohnert, Constructing two-weight codes with prescribed - groups of automorphisms, Discrete applied mathematics 155, +.. [Koh2007] \A. Kohnert, *Constructing two-weight codes with prescribed + groups of automorphisms*, Discrete applied mathematics 155, no. 11 (2007): 1451-1457. http://linearcodes.uni-bayreuth.de/twoweight/ +.. [Kos1985] \J.-L. Koszul, *Crochet de Schouten-Nijenhuis et + cohomologie*, in *Élie Cartan et les mathématiques + d'aujourd'hui*, Astérisque hors série (1985), p. 257 + .. [KP2002] Volker Kaibel and Marc E. Pfetsch, "Computing the Face Lattice of a Polytope from its Vertex-Facet Incidences", Computational Geometry: Theory and Applications, Volume @@ -1157,6 +1164,10 @@ REFERENCES: Mathematics. Springer-Verlag, New York, 1997. ISBN 0-387-98254-X +.. [Lic1977] \A. Lichnerowicz, *Les variétés de Poisson et leurs + algèbres de Lie associées*, Journal of Differential + Geometry **12**, 253 (1977); :doi:`10.4310/jdg/1214433987` + .. [Lin1999] \J. van Lint, Introduction to coding theory, 3rd ed., Springer-Verlag GTM, 86, 1999. @@ -1248,6 +1259,10 @@ REFERENCES: Notes in Computer Science, volume 5856, pp 272-278, Springer, Berlin (2009). +.. [Mar1997] \C.-M. Marle, *The Schouten-Nijenhuis bracket and interior + products*, Journal of Geometry and Physics **23**, 350 + (1997); :doi:`10.1016/S0393-0440(97)80009-5` + .. [Mas1969] James L. Massey, "Shift-Register Synthesis and BCH Decoding." IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan 1969. @@ -1335,6 +1350,10 @@ REFERENCES: .. [Nie] Johan S. R. Nielsen, Codinglib, https://bitbucket.org/jsrn/codinglib/. +.. [Nij1955] \A. Nijenhuis, *Jacobi-type identities for bilinear + differential concomitants of certain tensor fields. I*, + Indagationes Mathematicae (Proceedings) **58**, 390 (1955). + .. [NN2007] Nisan, Noam, et al., eds. *Algorithmic game theory.* Cambridge University Press, 2007. @@ -1688,6 +1707,10 @@ REFERENCES: **V** +.. [Vai1994] \I. Vaisman, *Lectures on the Geometry of Poisson + Manifolds*, Springer Basel AG (Basel) (1994); + :doi:`10.1007/978-3-0348-8495-2` + .. [Vat2008] \D. Vatne, *The mutation class of `D_n` quivers*, :arxiv:`0810.4789v1`. .. [VB1996] \E. Viterbo, E. Biglieri. *Computing the Voronoi Cell of a diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index a2799a60331..014fed0f7e3 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -20,7 +20,8 @@ REFERENCES: -- C.-M. Marle (1997) +- R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ +- C.-M. Marle (1997) [Mar1997]_ """ #****************************************************************************** diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 57c06f7f296..a672e96735d 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -23,7 +23,8 @@ REFERENCES: -- C.-M. Marle (1997) +- \R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ +- \C.-M. Marle (1997) [Mar1997]_ """ @@ -236,6 +237,29 @@ def _new_instance(self): """ return type(self)(self._vmodule, self._tensor_rank) + def degree(self): + r""" + Return the degree of ``self``. + + OUTPUT: + + - integer `p` such that ``self`` is a `p`-vector field + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2); a + 2-vector field on the 3-dimensional differentiable manifold M + sage: a.degree() + 2 + sage: b = M.vector_field(); b + Vector field on the 3-dimensional differentiable manifold M + sage: b.degree() + 1 + + """ + return self._tensor_rank + def wedge(self, other): r""" Exterior product with another multivector field. @@ -384,7 +408,7 @@ def interior_product(self, form): sage: W = U.intersection(V) # The complement of the two poles sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() sage: a = M.vector_field(name='a') - sage: a[e_xy,:] = y, x + sage: a[e_xy,:] = -y, x sage: a.add_comp_by_continuation(e_uv, W, c_uv) sage: b = M.diff_form(2, name='b') sage: b[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form @@ -397,12 +421,10 @@ def interior_product(self, form): 1-form i_a b on the 2-dimensional differentiable manifold S^2 sage: s.display(e_xy) i_a b = -4*x/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx - + 4*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy + - 4*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy sage: s.display(e_uv) - i_a b = 4*(u^3 - 3*u*v^2)/(u^6 + v^6 + (3*u^2 + 2)*v^4 + 2*u^4 - + (3*u^4 + 4*u^2 + 1)*v^2 + u^2) du - + 4*(3*u^2*v - v^3)/(u^6 + v^6 + (3*u^2 + 2)*v^4 + 2*u^4 - + (3*u^4 + 4*u^2 + 1)*v^2 + u^2) dv + i_a b = 4*u/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du + + 4*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) dv sage: s == a.contract(b) True @@ -487,28 +509,112 @@ def interior_product(self, form): resu.restrict(chart.domain()).coord_function(chart) return resu - def degree(self): + def bracket(self, other): r""" - Return the degree of ``self``. + Schouten-Nijenhuis bracket of ``self`` with another multivector field. + + INPUT: + + - ``other`` -- another multivector field OUTPUT: - - integer `p` such that ``self`` is a `p`-vector field + - instance of :class:`MultivectorField` representing the + Schouten-Nijenhuis bracket ``[self,other]`` - EXAMPLES:: + EXAMPLES: - sage: M = Manifold(3, 'M') - sage: a = M.multivector_field(2); a - 2-vector field on the 3-dimensional differentiable manifold M - sage: a.degree() - 2 - sage: b = M.vector_field(); b - Vector field on the 3-dimensional differentiable manifold M - sage: b.degree() - 1 + Bracket of two vector fields on the 2-sphere:: + + sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2 + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # S^2 is the union of U and V + sage: c_xy. = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + 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: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.vector_field(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.vector_field(name='b') + sage: b[e_xy,:] = x*y, x-y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.bracket(b); s + Vector field [a,b] on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + [a,b] = (x^2 + y^2 - x + y) d/dx + (-(x - 1)*y - x) d/dy + + For two vector fields, the bracket coincides with the Lie derivative:: + + sage: s == b.lie_derivative(a) + True + + Schouten-Nijenhuis bracket of a 2-vector field and a 1-vector field:: + + sage: c = a.wedge(b); c + 2-vector field a/\b on the 2-dimensional differentiable + manifold S^2 + sage: s = c.bracket(a); s + 2-vector field [a/\b,a] on the 2-dimensional differentiable + manifold S^2 + sage: s.display(e_xy) + [a/\b,a] = (x^3 + (2*x - 1)*y^2 - x^2 + 2*x*y) d/dx/\d/dy + + Since `a` is a vector field, we have in this case:: + + sage: s == - c.lie_derivative(a) + True + + .. SEEALSO:: + + :meth:`MultivectorFieldParal.bracket` for more examples and check + of standards identities involving the Schouten-Nijenhuis bracket """ - return self._tensor_rank + from sage.manifolds.differentiable.scalarfield import DiffScalarField + pp = self._tensor_rank + mp1 = (-1)**(pp+1) + if isinstance(other, DiffScalarField): + resu = other.differential().interior_product(self) + if mp1 == 1: + return resu + return - resu + # Some checks: + if not isinstance(other, (MultivectorField, MultivectorFieldParal)): + raise TypeError("{} is not a multivector field".format(other)) + if (self._vmodule.destination_map() is not self._domain.identity_map() + or other._vmodule.destination_map() is not + other._domain.identity_map()): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + + "only for fields with a trivial destination map") + # Search for a common domain + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + if dom_resu.is_manifestly_parallelizable(): + # call of the MultivectorFieldParal version: + return MultivectorFieldParal.bracket(self_r, other_r) + # otherwise, the result is created here: + # Name of the result: + resu_name = None ; resu_latex_name = None + if self._name is not None and other._name is not None: + resu_name = '[' + self._name + ',' + other._name + ']' + if self._latex_name is not None and other._latex_name is not None: + resu_latex_name = r'\left[' + self._latex_name + ',' + \ + other._latex_name + r'\right]' + vmodule = dom_resu.vector_field_module() + deg_resu = pp + other._tensor_rank - 1 # degree of the result + resu = vmodule.alternating_contravariant_tensor(deg_resu, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in other_r._restrictions: + resu._restrictions[dom] = self_r._restrictions[dom].bracket( + other_r._restrictions[dom]) + return resu #****************************************************************************** @@ -580,9 +686,9 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: a.symmetries() no symmetry; antisymmetry: (0, 1) - sage: a[0,1] = 2 + sage: a[0,1] = 2*x sage: a[1,0] - -2 + -2*x sage: a.comp() Fully antisymmetric 2-indices components w.r.t. Coordinate frame (M, (d/dt,d/dx,d/dy,d/dz)) @@ -605,31 +711,23 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.display`:: sage: a.display() # expansion w.r.t. the default frame - a = 2 d/dt/\d/dx + 3 d/dx/\d/dy + a = 2*x d/dt/\d/dx + 3 d/dx/\d/dy sage: latex(a.display()) # output for the notebook - a = 2 \frac{\partial}{\partial t }\wedge \frac{\partial}{\partial x } + a = 2 \, x \frac{\partial}{\partial t }\wedge \frac{\partial}{\partial x } + 3 \frac{\partial}{\partial x }\wedge \frac{\partial}{\partial y } Multivector fields can be added or subtracted:: sage: b = M.multivector_field(2) - sage: b[0,1], b[0,2], b[0,3] = (1,2,3) + sage: b[0,1], b[0,2], b[0,3] = y, 2, x+z sage: s = a + b ; s 2-vector field on the 4-dimensional differentiable manifold M - sage: a[:], b[:], s[:] - ( - [ 0 2 0 0] [ 0 1 2 3] [ 0 3 2 3] - [-2 0 3 0] [-1 0 0 0] [-3 0 3 0] - [ 0 -3 0 0] [-2 0 0 0] [-2 -3 0 0] - [ 0 0 0 0], [-3 0 0 0], [-3 0 0 0] - ) + sage: s.display() + (2*x + y) d/dt/\d/dx + 2 d/dt/\d/dy + (x + z) d/dt/\d/dz + 3 d/dx/\d/dy sage: s = a - b ; s 2-vector field on the 4-dimensional differentiable manifold M - sage: s[:] - [ 0 1 -2 -3] - [-1 0 3 0] - [ 2 -3 0 0] - [ 3 0 0 0] + sage: s.display() + (2*x - y) d/dt/\d/dx - 2 d/dt/\d/dy + (-x - z) d/dt/\d/dz + 3 d/dx/\d/dy An example of 3-vector field in `\RR^3` with Cartesian coordinates:: @@ -651,7 +749,7 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2), ....: atan2(sqrt(x^2+y^2),z), atan2(y, x)) - sage: a.comp(c_spher.frame()) # computation of the components in the spherical frame + sage: a.comp(c_spher.frame()) # computation of components w.r.t. spherical frame Fully antisymmetric 3-indices components w.r.t. Coordinate frame (R3, (d/dr,d/dth,d/dph)) sage: a.comp(c_spher.frame())[1,2,3, c_spher] @@ -665,19 +763,14 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.wedge`:: sage: a = M.vector_field(name='A') - sage: a[:] = (x*y*z, -z*x, y*z) + sage: a[:] = (x*y, -z*x, y) sage: b = M.vector_field(name='B') - sage: b[:] = (y, z+y^2, x^2-z^2) + sage: b[:] = (y, z+y, x^2-z^2) sage: ab = a.wedge(b) ; ab 2-vector field A/\B on the 3-dimensional differentiable manifold R3 - sage: ab[:] - [ 0 x*y*z^2 + (x*y^3 + x*y)*z -x*y*z^3 + (x^3*y - y^2)*z] - [ -x*y*z^2 - (x*y^3 + x*y)*z 0 x*z^3 - y*z^2 - (x^3 + y^3)*z] - [ x*y*z^3 - (x^3*y - y^2)*z -x*z^3 + y*z^2 + (x^3 + y^3)*z 0] sage: ab.display() - A/\B = (x*y*z^2 + (x*y^3 + x*y)*z) d/dx/\d/dy + (-x*y*z^3 - + (x^3*y - y^2)*z) d/dx/\d/dz + (x*z^3 - y*z^2 - - (x^3 + y^3)*z) d/dy/\d/dz + A/\B = (x*y^2 + 2*x*y*z) d/dx/\d/dy + (x^3*y - x*y*z^2 - y^2) d/dx/\d/dz + + (x*z^3 - y^2 - (x^3 + y)*z) d/dy/\d/dz Let us check the formula relating the exterior product to the tensor product for vector fields:: @@ -693,19 +786,14 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): manifold R3 sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments: no symmetry; antisymmetry: (1, 2) - sage: d = ab*a ; d - Tensor field (A/\B)*A of type (3,0) on the 3-dimensional differentiable - manifold R3 - sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments: - no symmetry; antisymmetry: (0, 1) The Lie derivative of a 2-vector field is a 2-vector field:: - sage: v = M.vector_field(name='v') - sage: v[:] = (y*z, -x*z, x*y) - sage: ab.lie_der(v) + sage: ab.lie_der(a) 2-vector field on the 3-dimensional differentiable manifold R3 + + """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -959,12 +1047,12 @@ def interior_product(self, form): sage: a = M.vector_field(name='a') sage: a[:] = [x, 1+t^2, x*z, y-3] sage: b = M.one_form(name='b') - sage: b[:] = [-z^2, 2, x*y, x-y] + sage: b[:] = [-z^2, 2, x, x-y] sage: s = a.interior_product(b); s Scalar field i_a b on the 4-dimensional differentiable manifold M sage: s.display() i_a b: M --> R - (t, x, y, z) |--> x^2*y*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 + (t, x, y, z) |--> x^2*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 - 3*x + 2 In this case, we have `\iota_a b = a^i b_i = a(b) = b(a)`:: @@ -976,15 +1064,15 @@ def interior_product(self, form): sage: c = M.diff_form(3, name='c') sage: c[0,1,2], c[0,1,3] = x*y - z, -3*t - sage: c[0,2,3], c[1,2,3] = t^2+x, y^2 + sage: c[0,2,3], c[1,2,3] = t+x, y sage: s = a.interior_product(c); s 2-form i_a c on the 4-dimensional differentiable manifold M sage: s.display() - i_a c = (x^2*y*z - x*z^2 - 3*t*y + 9*t) dt/\dx + (-3*t^2 - - (t^2*x - t^2)*y + (t^2 + 1)*z - 3*x) dt/\dy + (3*t^3 - - (t^2*x + x^2)*z + 3*t) dt/\dz + (x^2*y + y^3 - 3*y^2 - - x*z) dx/\dy + (-x*y^2*z - 3*t*x) dx/\dz + (t^2*x - + (t^2 + 1)*y^2 + x^2) dy/\dz + i_a c = (x^2*y*z - x*z^2 - 3*t*y + 9*t) dt/\dx + + (-(t^2*x - t)*y + (t^2 + 1)*z - 3*t - 3*x) dt/\dy + + (3*t^3 - (t*x + x^2)*z + 3*t) dt/\dz + + ((x^2 - 3)*y + y^2 - x*z) dx/\dy + + (-x*y*z - 3*t*x) dx/\dz + (t*x + x^2 + (t^2 + 1)*y) dy/\dz sage: s == a.contract(c) True @@ -992,14 +1080,14 @@ def interior_product(self, form): sage: d = M.multivector_field(2, name='d') sage: d[0,1], d[0,2], d[0,3] = t-x, 2*z, y-1 - sage: d[1,2], d[1,3], d[2,3] = z^2, y*t, 4 + sage: d[1,2], d[1,3], d[2,3] = z, y+t, 4 sage: s = d.interior_product(c); s 1-form i_d c on the 4-dimensional differentiable manifold M sage: s.display() - i_d c = (2*x*y*z^2 - 6*t^2*y - 2*z^3 + 8*t^2 + 8*x) dt - + (-4*x*y*z + 6*t*y + 8*y^2 + 4*z^2 - 6*t) dx - + (-2*t*y^3 + 2*t^2 - 2*(t^2 - (t - 1)*x + x^2)*y - 2*(t - x)*z - + 2*x) dy + (2*y^2*z^2 - 6*t^2 + 6*t*x + 4*(t^2 + x)*z) dz + i_d c = (2*x*y*z - 6*t^2 - 6*t*y - 2*z^2 + 8*t + 8*x) dt + + (-4*x*y*z + 2*(3*t + 4)*y + 4*z^2 - 6*t) dx + + (2*((t - 1)*x - x^2 - 2*t)*y - 2*y^2 - 2*(t - x)*z + 2*t + + 2*x) dy + (-6*t^2 + 6*t*x + 2*(2*t + 2*x + y)*z) dz sage: s == d.contract(0, 1, c, 0, 1) True @@ -1019,64 +1107,127 @@ def interior_product(self, form): def bracket(self, other): r""" - Schouten-Nijenhuis bracket of ``self`` with another multivector field. + Return the Schouten-Nijenhuis bracket of ``self`` with another + multivector field. + + The Schouten-Nijenhuis bracket extends the Lie bracket of + vector fields (cf. + :meth:`~sage.manifolds.differentiable.vectorfield.VectorField.bracket`) + to multivector fields. + + Denoting by `A^p(M)` the `C^k(M)`-module of `p`-vector fields on the + `C^k`-differentiable manifold `M` over the field `K` (cf. + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule`), + the *Schouten-Nijenhuis bracket* is a `K`-bilinear map + + .. MATH:: + + \begin{array}{ccc} + A^p(M)\times A^q(M) & \longrightarrow & A^{p+q-1}(M) \\ + (a,b) & \longmapsto & [a,b] + \end{array} + + which obeys the following properties: + + - if `p=0` and `q=0`, (i.e. `a` and `b` are two scalar fields), `[a,b]=0` + - if `p=0` (i.e. `a` is a scalar field) and `q\geq 1`, + `[a,b] = - \iota_{\mathrm{d}a} b` (minus the interior product of + the differential of `a` by `b`) + - if `p=1` (i.e. `a` is a vector field), `[a,b] = \mathcal{L}_a b` + (the Lie derivative of `b` along `a`) + - `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` + - for any multivector field `c` and `(a,b) \in A^p(M)\times A^q(M)`, + + .. MATH:: + + [a,b\wedge c] = [a,b]\wedge c + (-1)^{(p-1)q} b\wedge [a,c] + + .. NOTE:: + + There are two definitions of the Schouten-Nijenhuis bracket in + the literature, which differ from each other when `p` is even + by an overall sign. The definition adopted here is that of + [Mar1997]_, [Kos1985]_ and :wikipedia:`Schouten-Nijenhuis_bracket`. + The other definition, adopted e.g. by [Nij1955]_, [Lic1977]_ + and [Vai1994]_, is `[a,b]' = (-1)^{p+1} [a,b]`. INPUT: - - ``other`` -- another multivector field + - ``other`` -- a multivector field, `b` say OUTPUT: - instance of :class:`MultivectorFieldParal` representing the - Schouten-Nijenhuis bracket ``[self,other]`` + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` EXAMPLES: - On a 3-dimensional manifold:: + Let us consider two vector fields on a 3-dimensional manifold:: sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: a = M.vector_field(name='a') - sage: a[:] = x*y+z, x^2+y-z, z^2-2*x+y + sage: a[:] = x*y+z, x+y-z, z-2*x+y sage: b = M.vector_field(name='b') - sage: b[:] = y*z-x, x^2-y+z, z*x-1 + sage: b[:] = y+2*z-x, x^2-y+z, z-x + + and form their Schouten-Nijenhuis bracket:: + sage: s = a.bracket(b); s Vector field [a,b] on the 3-dimensional differentiable manifold M sage: s.display() - [a,b] = (-x^3 + (y - 1)*z^2 - x*y + y^2 + (x^2 - y^2 - 2*x + y - 1)*z + 1) d/dx - + ((2*x^2 + 1)*y - (2*x*y - 3*x)*z + z^2 - 2*x - 1) d/dy - + (-(x - 1)*z^2 - 3*x^2 + (x + 1)*y + ((x + 2)*y + 1)*z - 2*x) d/dz + [a,b] = (-x^3 + (x + 3)*y - y^2 - (x + 2*y + 1)*z - 2*x) d/dx + + (2*x^2*y - x^2 + 2*x*z - 3*x) d/dy + + (-x^2 - (x - 4)*y - 3*x + 2*z) d/dz + + Check that `[a,b]` is actually the Lie bracket:: + + sage: f = M.scalar_field({X: x+y*z}, name='f') + sage: s(f) == a(b(f)) - b(a(f)) + True + + Check that `[a,b]` coincides with the Lie derivative of `b` along `a`:: + sage: s == b.lie_derivative(a) True + + Schouten-Nijenhuis bracket for `p=1` and `q=2`:: + sage: c = M.multivector_field(2, name='c') - sage: c[0,1], c[0,2], c[1,2] = x+y^2+z, x*y*z, z*x-y + sage: c[0,1], c[0,2], c[1,2] = x+z+1, x*y+z, x-y sage: s = a.bracket(c); s 2-vector field [a,c] on the 3-dimensional differentiable manifold M sage: s.display() - [a,c] = (2*x^2*y - y^3 + y^2 + ((x - 3)*y + x)*z + z^2 - 3*x) - d/dx/\d/dy + ((x - 1)*y^2 - ((x - 1)*y + x)*z^2 - (2*x^2 - x)*y - + (x^3 - x^2 + x*y - 1)*z - x) d/dx/\d/dz + (-(x - 1)*z^2 - 3*x^2 - + x*y - 2*y^2 - ((2*x^2 - x - 2)*y + x + 1)*z - 2*x) d/dy/\d/dz + [a,c] = ((x - 1)*y - (y - 2)*z - 2*x - 1) d/dx/\d/dy + + ((x + 1)*y - (x + 1)*z - 3*x - 1) d/dx/\d/dz + + (-5*x + y - z - 2) d/dy/\d/dz + + Again, since `a` is a vector field, the Schouten-Nijenhuis bracket + coincides with the Lie derivative:: + sage: s == c.lie_derivative(a) True + + Schouten-Nijenhuis bracket for `p=2` and `q=2`:: + sage: d = M.multivector_field(2, name='d') - sage: d[0,1], d[0,2], d[1,2] = x^2-z, y*z+x, z-x+y^2-1 + sage: d[0,1], d[0,2], d[1,2] = x-y^2, x+z, z-x-1 sage: s = c.bracket(d); s 3-vector field [c,d] on the 3-dimensional differentiable manifold M sage: s.display() - [c,d] = (-x*y^3 - y*z^2 + (x^2 + 5*x + 2)*y + 2*y^2 - - ((x^2 + 1)*y - 2)*z) d/dx/\d/dy/\d/dz + [c,d] = (-y^3 + (3*x + 1)*y - y^2 - x - z + 2) d/dx/\d/dy/\d/dz sage: s[0,1,2] == - sum(c[i,0]*d[1,2].diff(i) ....: + c[i,1]*d[2,0].diff(i) + c[i,2]*d[0,1].diff(i) ....: + d[i,0]*c[1,2].diff(i) + d[i,1]*c[2,0].diff(i) ....: + d[i,2]*c[0,1].diff(i) for i in M.irange()) True sage: e = M.multivector_field(3, name='e') - sage: e[0,1,2] = x^2+y*z-z+2 + sage: e[0,1,2] = x+y*z+1 sage: s = a.bracket(e); s 3-vector field [a,e] on the 3-dimensional differentiable manifold M sage: s.display() - [a,e] = (-y*z^2 - x^2 + (x^2 - 2*x - 3)*y + y^2 - (x^2 + y^2 - 2*x - y + 3)*z + 2*x - 2) d/dx/\d/dy/\d/dz + [a,e] = (-(2*x + 1)*y + y^2 - (y^2 - x - 1)*z - z^2 + - 2*x - 2) d/dx/\d/dy/\d/dz sage: s == e.lie_derivative(a) True sage: s = c.bracket(e); s diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 9e10f6a88da..72b6290908b 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -929,3 +929,127 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + + def bracket(self, other): + r""" + Return the Schouten-Nijenhuis bracket of ``self``, considered as a + multivector field of degree 0, with a multivector field. + + See + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.bracket` + for details. + + INPUT: + + - ``other`` -- a multivector field, of degree `p` + + OUTPUT: + + - if `p=0`, a zero scalar field + - if `p=1`, an instance of :class:`DiffScalarField` representing + the Schouten-Nijenhuis bracket ``[self,other]`` + - if `p\geq 2`, an instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + representing the Schouten-Nijenhuis bracket ``[self,other]`` + + EXAMPLES: + + The Schouten-Nijenhuis bracket of two scalar fields is identically + zero:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}, name='f') + sage: g = M.scalar_field({X: y-x}, name='g') + sage: s = f.bracket(g); s + Scalar field zero on the 2-dimensional differentiable manifold M + sage: s.display() + zero: M --> R + (x, y) |--> 0 + + while the Schouten-Nijenhuis bracket of a scalar field `f` with a + multivector field `a` is equal to minus the interior product of the + differential of `f` with `a`:: + + sage: a = M.multivector_field(2, name='a') + sage: a[0,1] = x*y ; a.display() + a = x*y d/dx/\d/dy + sage: s = f.bracket(a); s + Vector field -i_df a on the 2-dimensional differentiable manifold M + sage: s.display() + -i_df a = 2*x*y^2 d/dx - x*y d/dy + + See + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.bracket` + for other examples. + + """ + if isinstance(other, DiffScalarField): + return self._domain.intersection(other._domain).zero_scalar_field() + return - self.differential().interior_product(other) + + def wedge(self, other): + r""" + Return the exterior product of ``self``, considered as a differential + form of degree 0 or a multivector field of degree 0, with ``other``. + + See + :meth:`~sage.manifolds.differentiable.diff_form.DiffFormParal.wedge` + (exterior product of differential forms) or + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.wedge` + (exterior product of multivector fields) for details. + + For a scalar field `f` and a `p`-form (or `p`-vector field) `a`, the + exterior product reduces to the standard product on the left by an + element of the base ring of the module of `p`-forms (or `p`-vector + fields): `f\wedge a = f a`. + + INPUT: + + - ``other`` -- a differential form or a multivector field `a` + + OUTPUT: + + - the product `f a`, where `f` is ``self`` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}, name='f') + sage: a = M.diff_form(2, name='a') + sage: a[0,1] = x*y + sage: s = f.wedge(a); s + 2-form on the 2-dimensional differentiable manifold M + sage: s.display() + (x*y^3 + x^2*y) dx/\dy + + """ + return self*other + + def degree(self): + r""" + Return the degree of ``self``, considered as a differential + form or a multivector field, i.e. zero. + + This trivial method is provided for consistency with the exterior + calculus scheme, cf. the methods + :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.degree` + (differential forms) and + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorField.degree` + (multivector fields). + + OUTPUT: + + - 0 + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}) + sage: f.degree() + 0 + + """ + return 0 diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index b04099989d3..c2d2d142a4c 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -932,10 +932,8 @@ def bracket(self, other): sage: vw.display() (-x^2 + y + 2) d/dy + (-y - z) d/dz """ - #!# - # return other.lie_der(self) - #!# provisory: - return MultivectorFieldParal.bracket(self, other) + # Call of the Schouten-Nijenhuis bracket + return MultivectorField.bracket(self, other) #****************************************************************************** From 3ef506fefbd77db9a6acbcee247e3b284246f483 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 13 Jul 2017 23:26:17 +0200 Subject: [PATCH 014/218] Complete doctests and documentation for the Schouten-Nijenhuis bracket --- .../differentiable/multivector_module.py | 6 +- .../differentiable/multivectorfield.py | 146 ++++++++++++++++-- .../manifolds/differentiable/vectorfield.py | 21 ++- 3 files changed, 160 insertions(+), 13 deletions(-) diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index 014fed0f7e3..17fb0abd96b 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -1,5 +1,5 @@ r""" -Multivector fields Modules +Multivector Field Modules The set `A^p(U, \Phi)` of `p`-vector fields along a differentiable manifold `U` with values on a differentiable manifold `M` via a @@ -20,8 +20,8 @@ REFERENCES: -- R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ -- C.-M. Marle (1997) [Mar1997]_ +- \R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ +- \C.-M. Marle (1997) [Mar1997]_ """ #****************************************************************************** diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index a672e96735d..8411f47a7b8 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -511,16 +511,69 @@ def interior_product(self, form): def bracket(self, other): r""" - Schouten-Nijenhuis bracket of ``self`` with another multivector field. + Return the Schouten-Nijenhuis bracket of ``self`` with another + multivector field. + + The Schouten-Nijenhuis bracket extends the Lie bracket of + vector fields (cf. + :meth:`~sage.manifolds.differentiable.vectorfield.VectorField.bracket`) + to multivector fields. + + Denoting by `A^p(M)` the `C^k(M)`-module of `p`-vector fields on the + `C^k`-differentiable manifold `M` over the field `K` (cf. + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule`), + the *Schouten-Nijenhuis bracket* is a `K`-bilinear map + + .. MATH:: + + \begin{array}{ccc} + A^p(M)\times A^q(M) & \longrightarrow & A^{p+q-1}(M) \\ + (a,b) & \longmapsto & [a,b] + \end{array} + + which obeys the following properties: + + - if `p=0` and `q=0`, (i.e. `a` and `b` are two scalar fields), `[a,b]=0` + - if `p=0` (i.e. `a` is a scalar field) and `q\geq 1`, + `[a,b] = - \iota_{\mathrm{d}a} b` (minus the interior product of + the differential of `a` by `b`) + - if `p=1` (i.e. `a` is a vector field), `[a,b] = \mathcal{L}_a b` + (the Lie derivative of `b` along `a`) + - `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` + - for any multivector field `c` and `(a,b) \in A^p(M)\times A^q(M)`, + `[a,.]` obeys the *graded Leibniz rule* + + .. MATH:: + + [a,b\wedge c] = [a,b]\wedge c + (-1)^{(p-1)q} b\wedge [a,c] + + - for `(a,b,c) \in A^p(M)\times A^q(M)\times A^r(M)`, the *graded + Jacobi identity* holds: + + .. MATH:: + + (-1)^{(p-1)(r-1)}[a,[b,c]] + (-1)^{(q-1)(p-1)}[b,[c,a]] + + (-1)^{(r-1)(q-1)}[c,[a,b]] = 0 + + .. NOTE:: + + There are two definitions of the Schouten-Nijenhuis bracket in + the literature, which differ from each other when `p` is even + by an overall sign. The definition adopted here is that of + [Mar1997]_, [Kos1985]_ and :wikipedia:`Schouten-Nijenhuis_bracket`. + The other definition, adopted e.g. by [Nij1955]_, [Lic1977]_ + and [Vai1994]_, is `[a,b]' = (-1)^{p+1} [a,b]`. INPUT: - - ``other`` -- another multivector field + - ``other`` -- a multivector field, `b` say OUTPUT: - - instance of :class:`MultivectorField` representing the - Schouten-Nijenhuis bracket ``[self,other]`` + - instance of :class:`MultivectorField` (or of + :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` + if `p=1` and `q=0`) representing the + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` EXAMPLES: @@ -1137,11 +1190,20 @@ def bracket(self, other): (the Lie derivative of `b` along `a`) - `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` - for any multivector field `c` and `(a,b) \in A^p(M)\times A^q(M)`, + `[a,.]` obeys the *graded Leibniz rule* .. MATH:: [a,b\wedge c] = [a,b]\wedge c + (-1)^{(p-1)q} b\wedge [a,c] + - for `(a,b,c) \in A^p(M)\times A^q(M)\times A^r(M)`, the *graded + Jacobi identity* holds: + + .. MATH:: + + (-1)^{(p-1)(r-1)}[a,[b,c]] + (-1)^{(q-1)(p-1)}[b,[c,a]] + + (-1)^{(r-1)(q-1)}[c,[a,b]] = 0 + .. NOTE:: There are two definitions of the Schouten-Nijenhuis bracket in @@ -1157,7 +1219,9 @@ def bracket(self, other): OUTPUT: - - instance of :class:`MultivectorFieldParal` representing the + - instance of :class:`MultivectorFieldParal` (or of + :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` + if `p=1` and `q=0`) representing the Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` EXAMPLES: @@ -1191,10 +1255,36 @@ def bracket(self, other): sage: s == b.lie_derivative(a) True - Schouten-Nijenhuis bracket for `p=1` and `q=2`:: + Schouten-Nijenhuis bracket for `p=0` and `q=1`:: + + sage: s = f.bracket(a); s + Scalar field -i_df a on the 3-dimensional differentiable manifold M + sage: s.display() + -i_df a: M --> R + (x, y, z) |--> x*y - y^2 - (x + 2*y + 1)*z + z^2 + + Check that `[f,a] = - \iota_{\mathrm{d}f} a = - \mathrm{d}f(a)`:: + + sage: s == - f.differential()(a) + True + + Schouten-Nijenhuis bracket for `p=0` and `q=2`:: sage: c = M.multivector_field(2, name='c') sage: c[0,1], c[0,2], c[1,2] = x+z+1, x*y+z, x-y + sage: s = f.bracket(c); s + Vector field -i_df c on the 3-dimensional differentiable manifold M + sage: s.display() + -i_df c = (x*y^2 + (x + y + 1)*z + z^2) d/dx + + (x*y - y^2 - x - z - 1) d/dy + (-x*y - (x - y + 1)*z) d/dz + + Check that `[f,c] = - \iota_{\mathrm{d}f} c`:: + + sage: s == - f.differential().interior_product(c) + True + + Schouten-Nijenhuis bracket for `p=1` and `q=2`:: + sage: s = a.bracket(c); s 2-vector field [a,c] on the 3-dimensional differentiable manifold M sage: s.display() @@ -1216,11 +1306,19 @@ def bracket(self, other): 3-vector field [c,d] on the 3-dimensional differentiable manifold M sage: s.display() [c,d] = (-y^3 + (3*x + 1)*y - y^2 - x - z + 2) d/dx/\d/dy/\d/dz + + Let us check the component formula (with respect to the manifold's + default coordinate chart, i.e. ``X``) for `p=q=2`, taking into + account the tensor antisymmetries:: + sage: s[0,1,2] == - sum(c[i,0]*d[1,2].diff(i) ....: + c[i,1]*d[2,0].diff(i) + c[i,2]*d[0,1].diff(i) ....: + d[i,0]*c[1,2].diff(i) + d[i,1]*c[2,0].diff(i) ....: + d[i,2]*c[0,1].diff(i) for i in M.irange()) True + + Schouten-Nijenhuis bracket for `p=1` and `q=3`:: + sage: e = M.multivector_field(3, name='e') sage: e[0,1,2] = x+y*z+1 sage: s = a.bracket(e); s @@ -1228,25 +1326,55 @@ def bracket(self, other): sage: s.display() [a,e] = (-(2*x + 1)*y + y^2 - (y^2 - x - 1)*z - z^2 - 2*x - 2) d/dx/\d/dy/\d/dz + + Again, since `p=1`, the bracket coincides with the Lie derivative:: + sage: s == e.lie_derivative(a) True + + Schouten-Nijenhuis bracket for `p=2` and `q=3`:: + sage: s = c.bracket(e); s 4-vector field [c,e] on the 3-dimensional differentiable manifold M + + Since on a 3-dimensional manifold, any 4-vector field is zero, we have:: + sage: s.display() [c,e] = 0 - sage: a.bracket(b) == - b.bracket(a) + + Let us check the graded commutation law + `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` for various values of `p` and `q`:: + + sage: f.bracket(a) == - a.bracket(f) # p=0 and q=1 + True + sage: f.bracket(c) == c.bracket(f) # p=0 and q=2 + True + sage: a.bracket(b) == - b.bracket(a) # p=1 and q=1 True - sage: a.bracket(c) == - c.bracket(a) + sage: a.bracket(c) == - c.bracket(a) # p=1 and q=2 True - sage: c.bracket(d) == d.bracket(c) + sage: c.bracket(d) == d.bracket(c) # p=2 and q=2 True + + Let us check the graded Leibniz rule for `p=1` and `q=1`:: + sage: a.bracket(b.wedge(c)) == a.bracket(b).wedge(c) + b.wedge(a.bracket(c)) True + + as well as for `p=2` and `q=1`:: + sage: c.bracket(a.wedge(b)) == c.bracket(a).wedge(b) - a.wedge(c.bracket(b)) True + + Finally let us check the graded Jacobi identity for `p=1`, `q=1` and + `r=2`:: + sage: a.bracket(b.bracket(c)) + b.bracket(c.bracket(a)) \ ....: + c.bracket(a.bracket(b)) == 0 True + + as well as for `p=1`, `q=2` and `r=2`:: + sage: a.bracket(c.bracket(d)) + c.bracket(d.bracket(a)) \ ....: - d.bracket(a.bracket(c)) == 0 True diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index c2d2d142a4c..56647f32fd3 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -921,9 +921,17 @@ def bracket(self, other): """ Return the Lie bracket ``[self, other]``. + INPUT: + + - ``other`` -- a :class:`VectorField` + + OUTPUT: + + - the :class:`VectorField` ``[self, other]`` + EXAMPLES:: - sage: M = Manifold(3, 'M', structure='smooth') + sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: v = -X.frame()[0] + 2*X.frame()[1] - (x^2 - y)*X.frame()[2] sage: w = (z + y) * X.frame()[1] - X.frame()[2] @@ -931,6 +939,17 @@ def bracket(self, other): Vector field on the 3-dimensional differentiable manifold M sage: vw.display() (-x^2 + y + 2) d/dy + (-y - z) d/dz + + Some checks:: + + sage: vw == - w.bracket(v) + True + sage: f = M.scalar_field({X: x+y*z}) + sage: vw(f) == v(w(f)) - w(v(f)) + True + sage: vw == w.lie_derivative(v) + True + """ # Call of the Schouten-Nijenhuis bracket return MultivectorField.bracket(self, other) From 7926b41de6ec7eb654ae7dfcb4599b62f131f85f Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 21 Jul 2017 20:25:09 +0000 Subject: [PATCH 015/218] Moving code for fraction_field and integer_ring, and enabling fraction fields for fixed-mod --- src/sage/rings/padics/local_generic.py | 3 +- src/sage/rings/padics/padic_base_generic.py | 57 -------------- src/sage/rings/padics/padic_base_leaves.py | 29 ++----- .../rings/padics/padic_extension_generic.py | 61 --------------- .../rings/padics/padic_extension_leaves.py | 15 ++++ src/sage/rings/padics/padic_generic.py | 78 +++++++++++++++++++ 6 files changed, 103 insertions(+), 140 deletions(-) diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 900a37d551e..9c682bac8bd 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -382,7 +382,8 @@ def get_unramified_modulus(q, res_name): if self._prec_type() == 'capped-abs': kwds['type'] = 'capped-rel' elif self._prec_type() == 'fixed-mod': - raise TypeError('You must specify the type explicitly') + kwds['type'] = 'floating-point' + kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. elif ring.is_field(): ring = ring.ring_of_integers() for atr in ('p', 'prec', 'type'): diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index c0fd9b487e2..1c22c0e7104 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -101,63 +101,6 @@ def _repr_(self, do_latex=False): return r"\ZZ_{%s}" % self.prime() return "%s-adic %s %s"%(self.prime(), "Field" if self.is_field() else "Ring", precprint(self._prec_type(), self.precision_cap(), self.prime())) - def fraction_field(self, print_mode=None): - r""" - Returns the fraction field of ``self``. - - INPUT: - - - ``print_mode`` - a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the fraction field of ``self``. - - EXAMPLES:: - - sage: R = Zp(5, print_mode='digits') - sage: K = R.fraction_field(); repr(K(1/3))[3:] - '31313131313131313132' - sage: L = R.fraction_field({'max_ram_terms':4}); repr(L(1/3))[3:] - '3132' - """ - if self.is_field() and print_mode is None: - return self - from sage.rings.padics.factory import Qp - if self.is_floating_point(): - mode = 'floating-point' - else: - mode = 'capped-rel' - return Qp(self.prime(), self.precision_cap(), mode, print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) - - def integer_ring(self, print_mode=None): - r""" - Returns the integer ring of ``self``, possibly with - ``print_mode`` changed. - - INPUT: - - - ``print_mode`` - a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - The ring of integral elements in ``self``. - - EXAMPLES:: - - sage: K = Qp(5, print_mode='digits') - sage: R = K.integer_ring(); repr(R(1/3))[3:] - '31313131313131313132' - sage: S = K.integer_ring({'max_ram_terms':4}); repr(S(1/3))[3:] - '3132' - """ - if not self.is_field() and print_mode is None: - return self - from sage.rings.padics.factory import Zp - return Zp(self.prime(), self.precision_cap(), self._prec_type(), print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) - def exact_field(self): """ Returns the rational field. diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 8c97e4edbd0..cd600684cdf 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -472,6 +472,14 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(skip='_test_log') sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^4)], max_runs = 2^6, skip='_test_log') # long time sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) + + Fraction fields work after :trac:`23510`:: + + sage: R = ZpFM(5) + sage: K = R.fraction_field(); K + 5-adic Field with floating precision 20 + sage: K(R(90)) + 3*5 + 3*5^2 """ pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFixedModElement) @@ -510,27 +518,6 @@ def _coerce_map_from_(self, R): self._printer.richcmp_modes(R._printer, op_LE)): return True - def fraction_field(self, print_mode = None): - r""" - Would normally return `\mathbb{Q}_p`, but there is no - implementation of `\mathbb{Q}_p` matching this ring so this - raises an error - - If you want to be able to divide with elements of a fixed - modulus `p`-adic ring, you must cast explicitly. - - EXAMPLES:: - - sage: ZpFM(5).fraction_field() - Traceback (most recent call last): - ... - TypeError: This implementation of the p-adic ring does not support fields of fractions. - - sage: a = ZpFM(5)(4); b = ZpFM(5)(5) - """ - raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") - - class pAdicFieldCappedRelative(pAdicFieldBaseGeneric, pAdicCappedRelativeFieldGeneric): r""" An implementation of `p`-adic fields with capped relative precision. diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index 6285240bcdd..546ecf78a32 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -321,67 +321,6 @@ def construction(self): implementation=self._implementation), self.base_ring()) - def fraction_field(self, print_mode=None): - r""" - Returns the fraction field of this extension, which is just - the extension of base.fraction_field() determined by the - same polynomial. - - INPUT: - - - print_mode -- a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the fraction field of self. - - EXAMPLES:: - - sage: U. = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) - sage: U.fraction_field() - Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Field - sage: U.fraction_field({"pos":False}) == U.fraction_field() - False - """ - if self.is_field() and print_mode is None: - return self - if print_mode is None: - return self.change(field=True) - else: - return self.change(field=True, **print_mode) - - def integer_ring(self, print_mode=None): - r""" - Returns the ring of integers of self, which is just the - extension of base.integer_ring() determined by the same - polynomial. - - INPUT: - - - print_mode -- a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the ring of elements of self with nonnegative valuation. - - EXAMPLES:: - - sage: U. = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) - sage: U.integer_ring() - Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Ring - sage: U.fraction_field({"pos":False}) == U.fraction_field() - False - """ - #Currently does not support fields with non integral defining polynomials. This should change when the padic_general_extension framework gets worked out. - if not self.is_field() and print_mode is None: - return self - if print_mode is None: - return self.change(field=False) - else: - return self.change(field=False, **print_mode) - #def hasGNB(self): # raise NotImplementedError diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index 857b814da04..881ba3f79cf 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -642,6 +642,21 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._implementation = implementation EisensteinExtensionGeneric.__init__(self, poly, prec, print_mode, names, pAdicZZpXFMElement) + def fraction_field(self): + """ + Eisenstein extensions with fixed modulus do not support fraction fields. + + EXAMPLES:: + + sage: S. = ZZ[] + sage: R. = ZpFM(5).extension(x^2 - 5) + sage: R.fraction_field() + Traceback (most recent call last): + ... + TypeError: This implementation of the p-adic ring does not support fields of fractions. + """ + raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") + #def coerce_map_explicit(self, S): # from sage.rings.padics.morphism import Morphism_ZZ_EisFM, Morphism_ZpFM_EisFM # if S is ZZ: diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index a38f5c3b8e6..54a8f23d6a7 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -357,6 +357,84 @@ def residue_system(self): """ return [self(i) for i in self.residue_class_field()] + def fraction_field(self, print_mode=None): + r""" + Returns the fraction field of this ring or field. + + For `\ZZ_p`, this is the `p`-adic field with the same options, + and for extensions, it is just the extension of the fraction + field of the base determined by the same polynomial. + + The fraction field of a capped absolute ring is capped relative, + and that of a fixed modulus ring is floating point. + + INPUT: + + - ``print_mode`` -- a dictionary containing print options. + Defaults to the same options as this ring. + + OUTPUT: + + - the fraction field of this ring. + + EXAMPLES:: + + sage: R = Zp(5, print_mode='digits') + sage: K = R.fraction_field(); repr(K(1/3))[3:] + '31313131313131313132' + sage: L = R.fraction_field({'max_ram_terms':4}); repr(L(1/3))[3:] + '3132' + sage: U. = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: U.fraction_field() + Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Field + sage: U.fraction_field({"pos":False}) == U.fraction_field() + False + """ + if self.is_field() and print_mode is None: + return self + if print_mode is None: + return self.change(field=True) + else: + return self.change(field=True, **print_mode) + + def integer_ring(self, print_mode=None): + r""" + Returns the ring of integers of this ring or field. + + For `\QQ_p`, this is the `p`-adic ring with the same options, + and for extensions, it is just the extension of the ring + of integers of the base determined by the same polynomial. + + INPUT: + + - ``print_mode`` -- a dictionary containing print options. + Defaults to the same options as this ring. + + OUTPUT: + + - the ring of elements of this field with nonnegative valuation. + + EXAMPLES:: + + sage: K = Qp(5, print_mode='digits') + sage: R = K.integer_ring(); repr(R(1/3))[3:] + '31313131313131313132' + sage: S = K.integer_ring({'max_ram_terms':4}); repr(S(1/3))[3:] + '3132' + sage: U. = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: U.integer_ring() + Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Ring + sage: U.fraction_field({"pos":False}) == U.fraction_field() + False + """ + #Currently does not support fields with non integral defining polynomials. This should change when the padic_general_extension framework gets worked out. + if not self.is_field() and print_mode is None: + return self + if print_mode is None: + return self.change(field=False) + else: + return self.change(field=False, **print_mode) + def teichmuller(self, x, prec = None): r""" Returns the teichmuller representative of x. From 16fb79bdb7f6f269726446c52a7ac6c1be18ff20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Sat, 29 Jul 2017 11:03:40 +0800 Subject: [PATCH 016/218] Check that fraction_field() works as expected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is probably going to lead to many doctests failing. I don't mind reverting it and putting it into a different ticket then. But let's see how bad things are… --- src/sage/categories/integral_domains.py | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 2587f37b221..3ecf218e21b 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -107,5 +107,31 @@ def is_integral_domain(self): """ return True + def _test_fraction_field(self, **options): + r""" + Test that the fraction field, if it is implemented, works + correctly. + + EXAMPLES:: + + sage: ZZ._test_fraction_field() + + """ + tester = self._tester(**options) + try: + fraction_field = self.fraction_field() + except Exception: + # some integral domains do not implement fraction_field() yet + if self in Fields(): + raise + return + + for x in tester.some_elements(): + # check that we can coerce into the fraction field + y = fraction_field.coerce(x) + # and convert back from it + z = self(x) + tester.assertEqual(x, z) + class ElementMethods: pass From 182d7d30a5f6ab340209e5f26c9dc61f4b43c6bd Mon Sep 17 00:00:00 2001 From: Emile Nadeau Date: Mon, 31 Jul 2017 22:08:10 -0400 Subject: [PATCH 017/218] Trac #23131: Add methods to compute longest common extension in words. --- src/sage/combinat/words/finite_word.py | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 27f69f11d01..42b7a7551f9 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2205,6 +2205,65 @@ def is_cadence(self, seq): return False return True + def longest_forward_extension(self,x,y): + r""" + Compute the length of le longest factor of self that starts at x and that + matches a factor that starts at y. Returns 0 if x or y are not valid + position in self. + + INPUTS: + + x,y - positions in self + + EXAMPLES: + + sage:w=Word('0011001') + sage:w.longest_forward_extension(0,5) + 3 + sage:w.longest_forward_extension(0,2) + 0 + sage:w.longest_forward_extension(-3,2) + 0 + """ + length=self.length() + if not (0<=x and 0<=y): + return 0 + l=0 + while x=0 and y>=0 and self[x]==self[y]: + l+=1 + x-=1 + y-=1 + return l + def longest_common_suffix(self, other): r""" Return the longest common suffix of ``self`` and ``other``. From 070176fe563b0df608092b77c6b9fd7d7e49acfb Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 1 Aug 2017 16:42:14 +0100 Subject: [PATCH 018/218] arb update to 2.11.1 --- build/pkgs/arb/checksums.ini | 6 +- build/pkgs/arb/package-version.txt | 2 +- build/pkgs/arb/patches/flint_includes.patch | 1032 ------------------- 3 files changed, 4 insertions(+), 1036 deletions(-) delete mode 100644 build/pkgs/arb/patches/flint_includes.patch diff --git a/build/pkgs/arb/checksums.ini b/build/pkgs/arb/checksums.ini index f572b72e7a8..78909d583ff 100644 --- a/build/pkgs/arb/checksums.ini +++ b/build/pkgs/arb/checksums.ini @@ -1,4 +1,4 @@ tarball=arb-VERSION.tar.gz -sha1=fcca9134006e77cde5f2024f36150e823bf731ae -md5=b6b94a39b71293b6811a191cb9542096 -cksum=248634837 +sha1=2f06bfb433cdaecde0e824c5e638094fd666a0d1 +md5=d63cdd1147104790826c93bc8651104f +cksum=2745482665 diff --git a/build/pkgs/arb/package-version.txt b/build/pkgs/arb/package-version.txt index e007c342d8c..99993ffae4c 100644 --- a/build/pkgs/arb/package-version.txt +++ b/build/pkgs/arb/package-version.txt @@ -1 +1 @@ -2.8.1.p1 +2.11.1.p0 diff --git a/build/pkgs/arb/patches/flint_includes.patch b/build/pkgs/arb/patches/flint_includes.patch deleted file mode 100644 index 083d87107af..00000000000 --- a/build/pkgs/arb/patches/flint_includes.patch +++ /dev/null @@ -1,1032 +0,0 @@ -Fix FLINT include paths - -See https://github.com/fredrik-johansson/arb/pull/55 - -diff -ru a/acb/test/t-rising2_ui_bs.c b/acb/test/t-rising2_ui_bs.c ---- a/acb/test/t-rising2_ui_bs.c 2015-12-30 11:06:48.862989805 +0100 -+++ b/acb/test/t-rising2_ui_bs.c 2015-12-30 11:13:35.255807240 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb/test/t-rising2_ui.c b/acb/test/t-rising2_ui.c ---- a/acb/test/t-rising2_ui.c 2015-12-30 11:06:48.862989805 +0100 -+++ b/acb/test/t-rising2_ui.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb/test/t-rising2_ui_rs.c b/acb/test/t-rising2_ui_rs.c ---- a/acb/test/t-rising2_ui_rs.c 2015-12-30 11:06:48.863989817 +0100 -+++ b/acb/test/t-rising2_ui_rs.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb_hypgeom/airy.c b/acb_hypgeom/airy.c ---- a/acb_hypgeom/airy.c 2015-12-30 11:06:48.865989841 +0100 -+++ b/acb_hypgeom/airy.c 2015-12-30 11:19:50.205169366 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "acb_hypgeom.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - #define LOG2 0.69314718055994530942 - #define EXP1 2.7182818284590452354 -diff -ru a/acb_mat/exp.c b/acb_mat/exp.c ---- a/acb_mat/exp.c 2015-12-30 11:06:48.870989901 +0100 -+++ b/acb_mat/exp.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "acb_mat.h" - - slong _arb_mat_exp_choose_N(const mag_t norm, slong prec); -diff -ru a/acb_mat.h b/acb_mat.h ---- a/acb_mat.h 2015-12-30 11:06:48.869989889 +0100 -+++ b/acb_mat.h 2015-12-30 11:13:35.256807251 +0100 -@@ -34,8 +34,8 @@ - - #include "arb.h" - #include "acb.h" --#include "fmpz_mat.h" --#include "fmpq_mat.h" -+#include "flint/fmpz_mat.h" -+#include "flint/fmpq_mat.h" - #include "arb_mat.h" - #include "acb_poly.h" - -diff -ru a/acb_modular/test/t-delta.c b/acb_modular/test/t-delta.c ---- a/acb_modular/test/t-delta.c 2015-12-30 11:06:48.872989925 +0100 -+++ b/acb_modular/test/t-delta.c 2015-12-30 11:13:35.256807251 +0100 -@@ -25,7 +25,7 @@ - - #include "acb_modular.h" - --#include "profiler.h" -+#include "flint/profiler.h" - - int main() - { -diff -ru a/acb_modular/test/t-epsilon_arg.c b/acb_modular/test/t-epsilon_arg.c ---- a/acb_modular/test/t-epsilon_arg.c 2015-12-30 11:06:48.873989937 +0100 -+++ b/acb_modular/test/t-epsilon_arg.c 2015-12-30 11:13:35.256807251 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "acb_modular.h" --#include "arith.h" -+#include "flint/arith.h" - - static void - acb_modular_epsilon_arg_naive(fmpq_t arg, const psl2z_t g) -diff -ru a/acb_modular/test/t-hilbert_class_poly.c b/acb_modular/test/t-hilbert_class_poly.c ---- a/acb_modular/test/t-hilbert_class_poly.c 2015-12-30 11:06:48.873989937 +0100 -+++ b/acb_modular/test/t-hilbert_class_poly.c 2015-12-30 11:29:32.413167018 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - #include "acb_modular.h" - - /* reference values h_(-d)(2015) mod 31337 computed using sage */ -diff -ru a/arb/bell_fmpz.c b/arb/bell_fmpz.c ---- a/arb/bell_fmpz.c 2015-12-30 11:06:48.884990069 +0100 -+++ b/arb/bell_fmpz.c 2015-12-30 11:17:49.662745942 +0100 -@@ -24,8 +24,8 @@ - ******************************************************************************/ - - #include "arb.h" --#include "arith.h" --#include "double_extras.h" -+#include "flint/arith.h" -+#include "flint/double_extras.h" - - /* \sum_{k=0}^{a-1} \frac{k^n}{k!} */ - /* b = a * \frac{(a-1)^n}{(a-1)!} */ -diff -ru a/arb/digamma.c b/arb/digamma.c ---- a/arb/digamma.c 2015-12-30 11:06:48.886990093 +0100 -+++ b/arb/digamma.c 2015-12-30 11:13:35.256807251 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "arith.h" -+#include "flint/arith.h" - - void arb_gamma_stirling_choose_param(int * reflect, slong * r, slong * n, - const arb_t x, int use_reflect, int digamma, slong prec); -diff -ru a/arb/rising_ui_rs.c b/arb/rising_ui_rs.c ---- a/arb/rising_ui_rs.c 2015-12-30 11:06:48.890990141 +0100 -+++ b/arb/rising_ui_rs.c 2015-12-30 11:13:35.257807263 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - - void -diff -ru a/arb/sin_cos.c b/arb/sin_cos.c ---- a/arb/sin_cos.c 2015-12-30 11:06:48.891990153 +0100 -+++ b/arb/sin_cos.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - #define TMP_ALLOC_LIMBS(__n) TMP_ALLOC((__n) * sizeof(mp_limb_t)) - -diff -ru a/arb/sin_cos_pi_fmpq_algebraic.c b/arb/sin_cos_pi_fmpq_algebraic.c ---- a/arb/sin_cos_pi_fmpq_algebraic.c 2015-12-30 11:06:48.891990153 +0100 -+++ b/arb/sin_cos_pi_fmpq_algebraic.c 2015-12-30 11:13:35.257807263 +0100 -@@ -29,8 +29,8 @@ - - - /* include minpoly code here until it appears in a flint release */ --#include "fmpz_poly.h" --#include "ulong_extras.h" -+#include "flint/fmpz_poly.h" -+#include "flint/ulong_extras.h" - - /* Use a lookup table for small n. We skip 53, 59 and 61, as the - coefficients do not fit in 16 bits. */ -diff -ru a/arb/test/t-addmul_si.c b/arb/test/t-addmul_si.c ---- a/arb/test/t-addmul_si.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-addmul_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-addmul_ui.c b/arb/test/t-addmul_ui.c ---- a/arb/test/t-addmul_ui.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-addmul_ui.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-add_si.c b/arb/test/t-add_si.c ---- a/arb/test/t-add_si.c 2015-12-30 11:06:48.893990177 +0100 -+++ b/arb/test/t-add_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-add_ui.c b/arb/test/t-add_ui.c ---- a/arb/test/t-add_ui.c 2015-12-30 11:06:48.893990177 +0100 -+++ b/arb/test/t-add_ui.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-atan_taylor_rf.c b/arb/test/t-atan_taylor_rf.c ---- a/arb/test/t-atan_taylor_rf.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-atan_taylor_rf.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-div_si.c b/arb/test/t-div_si.c ---- a/arb/test/t-div_si.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-div_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-div_ui.c b/arb/test/t-div_ui.c ---- a/arb/test/t-div_ui.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-div_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-exp_taylor_rf.c b/arb/test/t-exp_taylor_rf.c ---- a/arb/test/t-exp_taylor_rf.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-exp_taylor_rf.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-mul_si.c b/arb/test/t-mul_si.c ---- a/arb/test/t-mul_si.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-mul_si.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-mul_ui.c b/arb/test/t-mul_ui.c ---- a/arb/test/t-mul_ui.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-mul_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-rising2_ui_bs.c b/arb/test/t-rising2_ui_bs.c ---- a/arb/test/t-rising2_ui_bs.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui_bs.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-rising2_ui.c b/arb/test/t-rising2_ui.c ---- a/arb/test/t-rising2_ui.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-rising2_ui_rs.c b/arb/test/t-rising2_ui_rs.c ---- a/arb/test/t-rising2_ui_rs.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui_rs.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-sin_cos_taylor_rf.c b/arb/test/t-sin_cos_taylor_rf.c ---- a/arb/test/t-sin_cos_taylor_rf.c 2015-12-30 11:06:48.898990237 +0100 -+++ b/arb/test/t-sin_cos_taylor_rf.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-submul_si.c b/arb/test/t-submul_si.c ---- a/arb/test/t-submul_si.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-submul_si.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-submul_ui.c b/arb/test/t-submul_ui.c ---- a/arb/test/t-submul_ui.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-submul_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-sub_si.c b/arb/test/t-sub_si.c ---- a/arb/test/t-sub_si.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-sub_si.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-sub_ui.c b/arb/test/t-sub_ui.c ---- a/arb/test/t-sub_ui.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-sub_ui.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/zeta_ui.c b/arb/zeta_ui.c ---- a/arb/zeta_ui.c 2015-12-30 11:06:48.900990261 +0100 -+++ b/arb/zeta_ui.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - - void -diff -ru a/arb_mat/exp.c b/arb_mat/exp.c ---- a/arb_mat/exp.c 2015-12-30 11:06:48.901990273 +0100 -+++ b/arb_mat/exp.c 2015-12-30 11:13:35.259807285 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "arb_mat.h" - - #define LOG2_OVER_E 0.25499459743395350926 -diff -ru a/arb_mat.h b/arb_mat.h ---- a/arb_mat.h 2015-12-30 11:06:48.900990261 +0100 -+++ b/arb_mat.h 2015-12-30 11:13:35.259807285 +0100 -@@ -33,9 +33,9 @@ - #endif - - #include "arb.h" --#include "fmpz_mat.h" --#include "fmpq_mat.h" --#include "perm.h" -+#include "flint/fmpz_mat.h" -+#include "flint/fmpq_mat.h" -+#include "flint/perm.h" - #include "arb_poly.h" - - #ifdef __cplusplus -diff -ru a/arb_poly.h b/arb_poly.h ---- a/arb_poly.h 2015-12-30 11:06:48.903990297 +0100 -+++ b/arb_poly.h 2015-12-30 11:13:35.259807285 +0100 -@@ -34,8 +34,8 @@ - - #include "arb.h" - #include "acb.h" --#include "fmpz_poly.h" --#include "fmpq_poly.h" -+#include "flint/fmpz_poly.h" -+#include "flint/fmpq_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/arf/div.c b/arf/div.c ---- a/arf/div.c 2015-12-30 11:06:48.912990405 +0100 -+++ b/arf/div.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - #if !defined(__MPIR_VERSION) - #define USE_GMP_DIV_Q 1 -diff -ru a/arf/get_d.c b/arf/get_d.c ---- a/arf/get_d.c 2015-12-30 11:06:48.912990405 +0100 -+++ b/arf/get_d.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - /* most double: (2^53-1) * 2^971 */ - /* least normal: 2^-1022 */ -diff -ru a/arf/set_d.c b/arf/set_d.c ---- a/arf/set_d.c 2015-12-30 11:06:48.913990417 +0100 -+++ b/arf/set_d.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - void - arf_set_d(arf_t x, double v) -diff -ru a/arf/test/t-addmul_si.c b/arf/test/t-addmul_si.c ---- a/arf/test/t-addmul_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-addmul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_addmul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-add_si.c b/arf/test/t-add_si.c ---- a/arf/test/t-add_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-add_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_add_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-add_ui.c b/arf/test/t-add_ui.c ---- a/arf/test/t-add_ui.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-add_ui.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_add_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-mul_si.c b/arf/test/t-mul_si.c ---- a/arf/test/t-mul_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-mul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_mul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-mul_ui.c b/arf/test/t-mul_ui.c ---- a/arf/test/t-mul_ui.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-mul_ui.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_mul_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-submul_si.c b/arf/test/t-submul_si.c ---- a/arf/test/t-submul_si.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-submul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_submul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-sub_si.c b/arf/test/t-sub_si.c ---- a/arf/test/t-sub_si.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-sub_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_sub_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-sub_ui.c b/arf/test/t-sub_ui.c ---- a/arf/test/t-sub_ui.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-sub_ui.c 2015-12-30 11:13:35.261807308 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_sub_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf.h b/arf.h ---- a/arf.h 2015-12-30 11:06:48.911990393 +0100 -+++ b/arf.h 2015-12-30 11:13:35.261807308 +0100 -@@ -36,7 +36,7 @@ - #endif - - #include --#include "flint.h" -+#include "flint/flint.h" - #include "fmpr.h" - #include "mag.h" - -diff -ru a/bernoulli/test/t-fmpq_ui.c b/bernoulli/test/t-fmpq_ui.c ---- a/bernoulli/test/t-fmpq_ui.c 2015-12-30 11:06:48.916990453 +0100 -+++ b/bernoulli/test/t-fmpq_ui.c 2015-12-30 11:13:35.261807308 +0100 -@@ -25,8 +25,8 @@ - - #include - #include --#include "fmpz_vec.h" --#include "arith.h" -+#include "flint/fmpz_vec.h" -+#include "flint/arith.h" - #include "bernoulli.h" - - int main() -diff -ru a/bernoulli/test/t-rev.c b/bernoulli/test/t-rev.c ---- a/bernoulli/test/t-rev.c 2015-12-30 11:06:48.916990453 +0100 -+++ b/bernoulli/test/t-rev.c 2015-12-30 11:13:35.261807308 +0100 -@@ -26,9 +26,9 @@ - #include - #include - #include "bernoulli.h" --#include "ulong_extras.h" --#include "nmod_poly.h" --#include "nmod_vec.h" -+#include "flint/ulong_extras.h" -+#include "flint/nmod_poly.h" -+#include "flint/nmod_vec.h" - - int main() - { -diff -ru a/bernoulli.h b/bernoulli.h ---- a/bernoulli.h 2015-12-30 11:06:48.915990441 +0100 -+++ b/bernoulli.h 2015-12-30 11:13:35.261807308 +0100 -@@ -27,11 +27,11 @@ - #define BERNOULLI_H - - #include --#include "flint.h" --#include "fmpz.h" --#include "fmpz_vec.h" --#include "fmpq.h" --#include "arith.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" -+#include "flint/fmpz_vec.h" -+#include "flint/fmpq.h" -+#include "flint/arith.h" - #include "fmprb.h" - #include "arb.h" - -diff -ru a/configure b/configure ---- a/configure 2015-12-30 11:06:48.916990453 +0100 -+++ b/configure 2015-12-30 11:13:35.261807308 +0100 -@@ -262,10 +262,6 @@ - exit 1 - fi - --if [ -d "${FLINT_INC_DIR}/flint" ]; then -- FLINT_INC_DIR="${FLINT_INC_DIR}/flint" --fi -- - LIB_DIRS="${LIB_DIRS} ${FLINT_LIB_DIR}" - INC_DIRS="${INC_DIRS} ${FLINT_INC_DIR}" - LIBS="${LIBS} flint" -diff -ru a/examples/hilbert_matrix.c b/examples/hilbert_matrix.c ---- a/examples/hilbert_matrix.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/hilbert_matrix.c 2015-12-30 11:13:35.261807308 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "arb_mat.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int main(int argc, char *argv[]) - { -diff -ru a/examples/integrals.c b/examples/integrals.c ---- a/examples/integrals.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/integrals.c 2015-12-30 11:13:35.262807319 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "acb_calc.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int - sinx(acb_ptr out, const acb_t inp, void * params, slong order, slong prec) -diff -ru a/examples/keiper_li.c b/examples/keiper_li.c ---- a/examples/keiper_li.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/keiper_li.c 2015-12-30 11:13:35.262807319 +0100 -@@ -4,7 +4,7 @@ - #include "arb.h" - #include "acb.h" - #include "arb_poly.h" --#include "profiler.h" -+#include "flint/profiler.h" - - void - keiper_li_series(arb_ptr z, slong len, slong prec) -diff -ru a/examples/pi.c b/examples/pi.c ---- a/examples/pi.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/pi.c 2015-12-30 11:13:35.262807319 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "arb.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int main(int argc, char *argv[]) - { -diff -ru a/examples/poly_roots.c b/examples/poly_roots.c ---- a/examples/poly_roots.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/poly_roots.c 2015-12-30 11:13:35.262807319 +0100 -@@ -3,8 +3,8 @@ - #include - #include "acb.h" - #include "acb_poly.h" --#include "arith.h" --#include "profiler.h" -+#include "flint/arith.h" -+#include "flint/profiler.h" - - int check_accuracy(acb_ptr vec, slong len, slong prec) - { -diff -ru a/examples/real_roots.c b/examples/real_roots.c ---- a/examples/real_roots.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/real_roots.c 2015-12-30 11:13:56.258045629 +0100 -@@ -3,7 +3,7 @@ - #include - #include "arb_calc.h" - #include "acb_hypgeom.h" --#include "profiler.h" -+#include "flint/profiler.h" - - slong eval_count = 0; - -diff -ru a/fmpr/test/t-mul_si.c b/fmpr/test/t-mul_si.c ---- a/fmpr/test/t-mul_si.c 2015-12-30 11:06:48.923990538 +0100 -+++ b/fmpr/test/t-mul_si.c 2015-12-30 11:13:35.262807319 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "fmpr.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - static slong - fmpr_mul_si_naive(fmpr_t z, const fmpr_t x, slong y, slong prec, fmpr_rnd_t rnd) -diff -ru a/fmpr/test/t-mul_ui.c b/fmpr/test/t-mul_ui.c ---- a/fmpr/test/t-mul_ui.c 2015-12-30 11:06:48.923990538 +0100 -+++ b/fmpr/test/t-mul_ui.c 2015-12-30 11:13:35.262807319 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "fmpr.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - static slong - fmpr_mul_ui_naive(fmpr_t z, const fmpr_t x, ulong y, slong prec, fmpr_rnd_t rnd) -diff -ru a/fmprb.h b/fmprb.h ---- a/fmprb.h 2015-12-30 11:06:48.924990550 +0100 -+++ b/fmprb.h 2015-12-30 11:13:35.263807331 +0100 -@@ -27,7 +27,7 @@ - #define FMPRB_H - - #include "fmpr.h" --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/fmpr.h b/fmpr.h ---- a/fmpr.h 2015-12-30 11:06:48.920990501 +0100 -+++ b/fmpr.h 2015-12-30 11:13:35.263807331 +0100 -@@ -33,12 +33,12 @@ - #include - #include - #include --#include "flint.h" --#include "fmpz.h" --#include "fmpq.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" -+#include "flint/fmpq.h" - #include "fmpz_extras.h" - --#include "config.h" -+#include "flint/config.h" - #ifdef HAVE_TLS - #if HAVE_TLS - #define TLS_PREFIX __thread -diff -ru a/fmpz_extras.h b/fmpz_extras.h ---- a/fmpz_extras.h 2015-12-30 11:06:48.926990574 +0100 -+++ b/fmpz_extras.h 2015-12-30 11:13:35.263807331 +0100 -@@ -27,8 +27,8 @@ - #define FMPZ_EXTRAS_H - - #include --#include "flint.h" --#include "fmpz.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/hypgeom/bound.c b/hypgeom/bound.c ---- a/hypgeom/bound.c 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom/bound.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "hypgeom.h" - - slong -diff -ru a/hypgeom/estimate_terms_d.c b/hypgeom/estimate_terms_d.c ---- a/hypgeom/estimate_terms_d.c 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom/estimate_terms_d.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "hypgeom.h" - - #define LOG2 0.69314718055994530942 -diff -ru a/hypgeom.h b/hypgeom.h ---- a/hypgeom.h 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom.h 2015-12-30 11:13:35.263807331 +0100 -@@ -29,7 +29,7 @@ - #include "fmprb.h" - #include "arb.h" - #include "mag.h" --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/mag/d_log.c b/mag/d_log.c ---- a/mag/d_log.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/d_log.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - /* - This is a bad implementation the logarithm function, -diff -ru a/mag/exp.c b/mag/exp.c ---- a/mag/exp.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/exp.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - static const double inverse_factorials[] = { - 1.0, -diff -ru a/mag/get_d.c b/mag/get_d.c ---- a/mag/get_d.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/get_d.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - double -diff -ru a/mag/log1p.c b/mag/log1p.c ---- a/mag/log1p.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/log1p.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - void - mag_log1p(mag_t z, const mag_t x) -diff -ru a/mag/test/t-cmp_2exp_si.c b/mag/test/t-cmp_2exp_si.c ---- a/mag/test/t-cmp_2exp_si.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-cmp_2exp_si.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/mag/test/t-d_log_lower_bound.c b/mag/test/t-d_log_lower_bound.c ---- a/mag/test/t-d_log_lower_bound.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-d_log_lower_bound.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-d_log_upper_bound.c b/mag/test/t-d_log_upper_bound.c ---- a/mag/test/t-d_log_upper_bound.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-d_log_upper_bound.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-mul_2exp_si.c b/mag/test/t-mul_2exp_si.c ---- a/mag/test/t-mul_2exp_si.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-mul_2exp_si.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/mag/test/t-set_d_2exp_fmpz.c b/mag/test/t-set_d_2exp_fmpz.c ---- a/mag/test/t-set_d_2exp_fmpz.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-set_d_2exp_fmpz.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-set_d.c b/mag/test/t-set_d.c ---- a/mag/test/t-set_d.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-set_d.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag.h b/mag.h ---- a/mag.h 2015-12-30 11:06:48.927990586 +0100 -+++ b/mag.h 2015-12-30 11:13:35.264807342 +0100 -@@ -33,8 +33,8 @@ - #endif - - #include --#include "flint.h" --#include "fmpz.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" - #include "fmpz_extras.h" - - #ifdef __cplusplus -diff -ru a/partitions/hrr_sum_arb.c b/partitions/hrr_sum_arb.c ---- a/partitions/hrr_sum_arb.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/hrr_sum_arb.c 2015-12-30 11:13:35.265807353 +0100 -@@ -25,7 +25,7 @@ - - #include "partitions.h" - --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - #include "math.h" - -diff -ru a/partitions/test/t-partitions_fmpz_ui.c b/partitions/test/t-partitions_fmpz_ui.c ---- a/partitions/test/t-partitions_fmpz_ui.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 generated with Sage */ -diff -ru a/partitions/test/t-partitions_fmpz_ui_threaded.c b/partitions/test/t-partitions_fmpz_ui_threaded.c ---- a/partitions/test/t-partitions_fmpz_ui_threaded.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui_threaded.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 */ -diff -ru a/partitions/test/t-partitions_fmpz_ui_using_doubles.c b/partitions/test/t-partitions_fmpz_ui_using_doubles.c ---- a/partitions/test/t-partitions_fmpz_ui_using_doubles.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui_using_doubles.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 generated with Sage */ -diff -ru a/partitions.h b/partitions.h ---- a/partitions.h 2015-12-30 11:06:48.930990622 +0100 -+++ b/partitions.h 2015-12-30 11:13:35.265807353 +0100 -@@ -27,8 +27,8 @@ - #define PARTITIONS_H - - #include --#include "flint.h" --#include "arith.h" -+#include "flint/flint.h" -+#include "flint/arith.h" - #include "arb.h" - - #ifdef __cplusplus From ab828b9a92667b8104e5444f38b1ab0c4a74e7ae Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 1 Aug 2017 20:43:58 +0100 Subject: [PATCH 019/218] arb doctest fixes; few more, less obvious, might be needed it can also be that ellipses would be needed to make some doctests pass on all platforms. Needs more testing (on OSX, on 32-bit, etc) --- src/sage/rings/complex_arb.pyx | 145 +++++++++--------- .../polynomial/polynomial_complex_arb.pyx | 5 +- src/sage/rings/real_arb.pyx | 6 +- 3 files changed, 75 insertions(+), 81 deletions(-) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 775c1b4ba9c..9255ee38ef2 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -1968,7 +1968,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(-2, 1)/CBF(1, 1/3) - [-1.50000000000000 +/- 1.27e-15] + [1.500000000000000 +/- 8.94e-16]*I + [-1.500000000000000 +/- 8.83e-16] + [1.500000000000000 +/- 5.64e-16]*I sage: CBF(2+I)/CBF(0) [+/- inf] + [+/- inf]*I sage: CBF(1)/CBF(0) @@ -2114,7 +2114,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1).rising_factorial(5) 120.0000000000000 sage: CBF(1/3, 1/2).rising_factorial(300) - [-3.87949484514e+612 +/- 5.24e+600] + [-3.52042209763e+612 +/- 5.56e+600]*I + [-3.87949484514e+612 +/- 5.23e+600] + [-3.52042209763e+612 +/- 5.55e+600]*I sage: CBF(1).rising_factorial(-1) nan @@ -2123,7 +2123,7 @@ cdef class ComplexBall(RingElement): sage: ComplexBallField(128)(1).rising_factorial(2**64) [2.343691126796861348e+347382171305201285713 +/- 4.71e+347382171305201285694] sage: CBF(1/2).rising_factorial(CBF(2,3)) - [-0.123060451458124 +/- 4.46e-16] + [0.040641263167655 +/- 3.75e-16]*I + [-0.123060451458124 +/- 4.43e-16] + [0.040641263167655 +/- 3.72e-16]*I """ cdef ComplexBall result = self._new() @@ -2264,7 +2264,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(pi/2, 1/10).tan() - [+/- 2.87e-14] + [10.0333111322540 +/- 3.16e-14]*I + [+/- 2.87e-14] + [10.0333111322540 +/- 2.36e-14]*I sage: CBF(pi/2).tan() [+/- inf] """ @@ -2281,7 +2281,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(pi, 1/10).cot() - [+/- 5.74e-14] + [-10.0333111322540 +/- 4.05e-14]*I + [+/- 5.74e-14] + [-10.0333111322540 +/- 2.81e-14]*I sage: CBF(pi).cot() [+/- inf] """ @@ -2393,15 +2393,15 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).gamma() - [0.49801566811836 +/- 4.98e-15] + [-0.154949828301811 +/- 7.67e-16]*I + [0.498015668118356 +/- 9.16e-16] + [-0.154949828301811 +/- 7.08e-16]*I sage: CBF(-1).gamma() nan sage: CBF(1, 1).gamma(0) - [0.49801566811836 +/- 4.98e-15] + [-0.154949828301811 +/- 7.67e-16]*I + [0.498015668118356 +/- 9.16e-16] + [-0.154949828301811 +/- 7.08e-16]*I sage: CBF(1, 1).gamma(100) - [-3.6143867454139e-45 +/- 7.26e-59] + [-3.7022961377791e-44 +/- 4.71e-58]*I + [-3.6143867454139e-45 +/- 6.88e-59] + [-3.7022961377791e-44 +/- 4.41e-58]*I sage: CBF(1, 1).gamma(CLF(i)) - [0.32886684193500 +/- 5.49e-15] + [-0.18974945045621 +/- 1.49e-15]*I + [0.32886684193500 +/- 5.04e-15] + [-0.18974945045621 +/- 1.26e-15]*I """ cdef ComplexBall my_z cdef ComplexBall res = self._new() @@ -2467,7 +2467,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).psi() - [0.0946503206224770 +/- 7.34e-17] + [1.076674047468581 +/- 2.63e-16]*I + [0.0946503206224770 +/- 7.74e-17] + [1.076674047468581 +/- 2.58e-16]*I sage: CBF(-1).psi() nan sage: CBF(1,1).psi(10) @@ -2496,9 +2496,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).zeta() - [0.5821580597520036 +/- 5.27e-17] + [-0.9268485643308071 +/- 2.81e-17]*I + [0.5821580597520036 +/- 5.26e-17] + [-0.9268485643308071 +/- 2.80e-17]*I sage: CBF(1, 1).zeta(1) - [0.5821580597520036 +/- 5.27e-17] + [-0.9268485643308071 +/- 2.81e-17]*I + [0.5821580597520036 +/- 5.26e-17] + [-0.9268485643308071 +/- 2.80e-17]*I sage: CBF(1, 1).zeta(1/2) [1.497919876084167 +/- 2.91e-16] + [0.2448655353684164 +/- 4.22e-17]*I sage: CBF(1, 1).zeta(CBF(1, 1)) @@ -2528,7 +2528,7 @@ cdef class ComplexBall(RingElement): sage: CBF(2).polylog(1) [+/- 4.65e-15] + [-3.14159265358979 +/- 8.15e-15]*I sage: CBF(1, 1).polylog(CBF(1, 1)) - [0.3708160030469 +/- 2.38e-14] + [2.7238016577979 +/- 4.22e-14]*I + [0.3708160030469 +/- 2.38e-14] + [2.7238016577979 +/- 4.20e-14]*I TESTS:: @@ -2564,7 +2564,7 @@ cdef class ComplexBall(RingElement): sage: CBF(8).barnes_g() 24883200.00000000 sage: CBF(500,10).barnes_g() - [4.54078781e+254873 +/- 5.43e+254864] + [8.65835455e+254873 +/- 7.27e+254864]*I + [4.54078781e+254873 +/- 5.43e+254864] + [8.65835455e+254873 +/- 7.28e+254864]*I """ cdef ComplexBall res = self._new() if _do_sig(prec(self)): sig_on() @@ -2602,7 +2602,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(0, -1).agm1() - [0.5990701173678 +/- 1.14e-14] + [-0.5990701173678 +/- 1.22e-14]*I + [0.5990701173678 +/- 1.15e-14] + [-0.5990701173678 +/- 1.19e-14]*I """ cdef ComplexBall res = self._new() if _do_sig(prec(self)): sig_on() @@ -2653,15 +2653,15 @@ cdef class ComplexBall(RingElement): [+/- 7.72e-16] + [2.71828182845904 +/- 6.45e-15]*I sage: CBF(1, pi).hypergeometric([1/4], [1/4]) - [-2.7182818284590 +/- 8.63e-14] + [+/- 3.69e-14]*I + [-2.7182818284590 +/- 7.11e-14] + [+/- 2.25e-14]*I sage: CBF(1000, 1000).hypergeometric([10], [AA(sqrt(2))]) - [9.79300951360e+454 +/- 4.83e+442] + [5.522579106816e+455 +/- 3.39e+442]*I + [9.79300951360e+454 +/- 5.01e+442] + [5.522579106816e+455 +/- 3.56e+442]*I sage: CBF(1000, 1000).hypergeometric([100], [AA(sqrt(2))]) - [+/- 8.88e+596] + [+/- 8.88e+596]*I + [1.27967355557e+590 +/- 8.60e+578] + [-9.32333491987e+590 +/- 8.18e+578]*I sage: CBF(0, 1).hypergeometric([], [1/2, 1/3, 1/4]) - [-3.7991962344383 +/- 4.98e-14] + [23.8780971778049 +/- 5.40e-14]*I + [-3.7991962344383 +/- 8.78e-14] + [23.878097177805 +/- 3.87e-13]*I sage: CBF(0).hypergeometric([1], []) 1.000000000000000 @@ -2669,9 +2669,9 @@ cdef class ComplexBall(RingElement): 1.000000000000000*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) - [0.7871684267473 +/- 3.57e-14] + [0.2749254173721 +/- 6.45e-14]*I + [0.7871684267473 +/- 7.34e-14] + [0.2749254173721 +/- 9.23e-14]*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2],regularized=True) - [0.4441122268685 +/- 1.83e-14] + [0.1551100567338 +/- 4.07e-14]*I + [0.4441122268685 +/- 3.96e-14] + [0.1551100567338 +/- 5.75e-14]*I sage: CBF(5).hypergeometric([2,3], [-5]) nan + nan*I @@ -2679,7 +2679,7 @@ cdef class ComplexBall(RingElement): [5106.925964355 +/- 5.41e-10] sage: CBF(2016).hypergeometric([], [2/3]) - [2.0256426923278e+38 +/- 8.90e+24] + [2.025642692328e+38 +/- 3.00e+25] sage: CBF(-2016).hypergeometric([], [2/3], regularized=True) [-0.0005428550847 +/- 5.00e-14] @@ -2687,12 +2687,12 @@ cdef class ComplexBall(RingElement): 0.0002441406250000000 sage: CBF(0, 3).hypergeometric([CBF(1,1)], [-4], regularized=True) - [239.5140007528 +/- 5.01e-11] + [105.1751573490 +/- 2.36e-11]*I + [239.514000752841 +/- 8.03e-13] + [105.175157349015 +/- 6.28e-13]*I TESTS:: sage: CBF(0, 1).hypergeometric([QQbar(sqrt(2)), RLF(pi)], [1r, 1/2]) - [-8.7029449215408 +/- 6.89e-14] + [-0.8499070546106 +/- 4.98e-14]*I + [-8.7029449215408 +/- 6.17e-14] + [-0.8499070546106 +/- 5.21e-14]*I """ cdef ComplexBall tmp, my_a, my_b, my_c @@ -2766,7 +2766,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1000, 1000).hypergeometric_U(RLF(pi), -100) - [-7.261605907166e-11 +/- 4.89e-24] + [-7.928136216391e-11 +/- 5.36e-24]*I + [-7.261605907166e-11 +/- 5.04e-24] + [-7.928136216391e-11 +/- 5.52e-24]*I sage: CBF(1000, 1000).hypergeometric_U(0, -100) 1.000000000000000 """ @@ -2785,7 +2785,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).erf() - [1.31615128169795 +/- 8.80e-15] + [0.19045346923783 +/- 9.19e-15]*I + [1.316151281697947 +/- 7.26e-16] + [0.1904534692378347 +/- 6.03e-17]*I """ cdef ComplexBall result = self._new() @@ -2801,9 +2801,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(20).erfc() - [5.3958656116079e-176 +/- 1.08e-190] + [5.39586561160790e-176 +/- 6.73e-191] sage: CBF(100, 100).erfc() - [0.00065234366376858 +/- 6.52e-18] + [-0.00393572636292141 +/- 5.16e-18]*I + [0.00065234366376858 +/- 8.37e-18] + [-0.00393572636292141 +/- 7.21e-18]*I """ cdef ComplexBall result = self._new() if _do_sig(prec(self)): sig_on() @@ -2905,9 +2905,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_J(1) - [0.614160334922903 +/- 8.48e-16] + [0.365028028827088 +/- 6.62e-16]*I + [0.614160334922903 +/- 6.38e-16] + [0.365028028827088 +/- 3.96e-16]*I sage: CBF(100, -100).bessel_J(1/3) - [1.108431870251e+41 +/- 5.53e+28] + [-8.952577603125e+41 +/- 2.91e+28]*I + [1.108431870251e+41 +/- 5.53e+28] + [-8.952577603125e+41 +/- 2.93e+28]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2925,9 +2925,9 @@ cdef class ComplexBall(RingElement): sage: J, Y = CBF(1, 1).bessel_J_Y(1) sage: J - CBF(1, 1).bessel_J(1) - [+/- 7.95e-16] + [+/- 6.84e-16]*I + [+/- 3.75e-16] + [+/- 2.64e-16]*I sage: Y - CBF(1, 1).bessel_Y(1) - [+/- 2.31e-14] + [+/- 2.26e-14]*I + [+/- 1.64e-14] + [+/- 1.62e-14]*I """ cdef ComplexBall result1 = self._new() @@ -2947,9 +2947,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_Y(1) - [-0.6576945355913 +/- 5.62e-14] + [0.6298010039929 +/- 2.77e-14]*I + [-0.6576945355913 +/- 5.29e-14] + [0.6298010039929 +/- 2.45e-14]*I sage: CBF(100, -100).bessel_Y(1/3) - [-8.952577603125e+41 +/- 4.65e+28] + [-1.108431870251e+41 +/- 6.29e+28]*I + [-8.952577603125e+41 +/- 4.66e+28] + [-1.108431870251e+41 +/- 6.31e+28]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2966,9 +2966,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_I(1) - [0.365028028827088 +/- 6.62e-16] + [0.614160334922903 +/- 8.48e-16]*I + [0.365028028827088 +/- 3.96e-16] + [0.614160334922903 +/- 6.38e-16]*I sage: CBF(100, -100).bessel_I(1/3) - [5.4362189595644e+41 +/- 6.48e+27] + [7.1989436985321e+41 +/- 2.69e+27]*I + [5.4362189595644e+41 +/- 6.40e+27] + [7.1989436985321e+41 +/- 2.92e+27]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2987,9 +2987,9 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).bessel_K(0) [0.08019772694652 +/- 3.19e-15] + [-0.35727745928533 +/- 1.08e-15]*I sage: CBF(1, 1).bessel_K(1) - [0.02456830552374 +/- 6.22e-15] + [-0.45971947380119 +/- 6.74e-15]*I + [0.02456830552374 +/- 4.84e-15] + [-0.45971947380119 +/- 5.35e-15]*I sage: CBF(100, 100).bessel_K(QQbar(i)) - [3.8693896656383e-45 +/- 2.38e-59] + [5.5071004234177e-46 +/- 5.86e-60]*I + [3.8693896656383e-45 +/- 2.76e-59] + [5.507100423418e-46 +/- 4.01e-59]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -3006,9 +3006,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1+i).exp_integral_e(1) - [0.00028162445198 +/- 2.78e-15] + [-0.17932453503936 +/- 2.56e-15]*I + [0.00028162445198 +/- 2.79e-15] + [-0.17932453503936 +/- 2.12e-15]*I sage: CBF(1+i).exp_integral_e(QQbar(i)) - [-0.10396361883964 +/- 4.92e-15] + [-0.16268401277783 +/- 4.78e-15]*I + [-0.10396361883964 +/- 3.78e-15] + [-0.16268401277783 +/- 3.69e-15]*I """ cdef ComplexBall res = self._new() cdef ComplexBall my_s = self._parent.coerce(s) @@ -3024,7 +3024,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).ei() - [1.76462598556385 +/- 6.65e-15] + [2.38776985151052 +/- 4.34e-15]*I + [1.76462598556385 +/- 5.82e-15] + [2.38776985151052 +/- 4.29e-15]*I sage: CBF(0).ei() nan """ @@ -3041,7 +3041,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).si() - [1.10422265823558 +/- 2.16e-15] + [0.88245380500792 +/- 3.15e-15]*I + [1.10422265823558 +/- 2.48e-15] + [0.88245380500792 +/- 3.36e-15]*I sage: CBF(0).si() 0 """ @@ -3058,7 +3058,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).ci() - [0.882172180555936 +/- 4.85e-16] + [0.287249133519956 +/- 3.47e-16]*I + [0.882172180555936 +/- 4.85e-16] + [0.287249133519956 +/- 3.92e-16]*I sage: CBF(0).ci() nan + nan*I """ @@ -3075,7 +3075,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).shi() - [0.88245380500792 +/- 3.15e-15] + [1.10422265823558 +/- 2.16e-15]*I + [0.88245380500792 +/- 3.36e-15] + [1.10422265823558 +/- 2.48e-15]*I sage: CBF(0).shi() 0 """ @@ -3093,7 +3093,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).chi() - [0.882172180555936 +/- 4.85e-16] + [1.28354719327494 +/- 1.05e-15]*I + [0.882172180555936 +/- 4.85e-16] + [1.28354719327494 +/- 1.07e-15]*I sage: CBF(0).chi() nan + nan*I """ @@ -3112,7 +3112,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).li() - [0.61391166922119 +/- 7.03e-15] + [2.05958421419258 +/- 8.25e-15]*I + [0.61391166922120 +/- 6.40e-15] + [2.05958421419258 +/- 5.61e-15]*I sage: CBF(0).li() 0 sage: CBF(0).li(offset=True) @@ -3158,10 +3158,7 @@ cdef class ComplexBall(RingElement): [0.969386075665498 +/- 4.65e-16] + [-0.030613917822067 +/- 1.89e-16]*I) sage: CBF(3,-1/2).jacobi_theta(CBF(1/4,-2)) - ([+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I) + (nan + nan*I, nan + nan*I, nan + nan*I, nan + nan*I) sage: CBF(0).jacobi_theta(CBF(0,1)) (0, @@ -3224,11 +3221,11 @@ cdef class ComplexBall(RingElement): sage: tau = CBF(sqrt(2),pi) sage: tau.modular_lambda() - [-0.00022005123884157 +/- 6.64e-18] + [-0.0007978734645994 +/- 5.23e-17]*I + [-0.00022005123884157 +/- 6.41e-18] + [-0.0007978734645994 +/- 5.15e-17]*I sage: (tau + 2).modular_lambda() - [-0.00022005123884157 +/- 6.64e-18] + [-0.0007978734645994 +/- 5.23e-17]*I + [-0.00022005123884157 +/- 6.41e-18] + [-0.0007978734645994 +/- 5.15e-17]*I sage: (tau / (1 - 2*tau)).modular_lambda() - [-0.00022005123884 +/- 2.75e-15] + [-0.00079787346460 +/- 3.34e-15]*I + [-0.00022005123884 +/- 2.53e-15] + [-0.00079787346460 +/- 2.85e-15]*I """ cdef ComplexBall result = self._new() @@ -3248,7 +3245,7 @@ cdef class ComplexBall(RingElement): sage: a, b, c, d = 2, 5, 1, 3 sage: tau = CBF(1,3) sage: ((a*tau+b)/(c*tau+d)).modular_delta() - [0.20921376655 +/- 6.94e-12] + [1.5761192552 +/- 3.49e-11]*I + [0.20921376655 +/- 6.94e-12] + [1.5761192552 +/- 3.47e-11]*I sage: (c*tau+d)^12 * tau.modular_delta() [0.20921376654986 +/- 4.89e-15] + [1.5761192552253 +/- 4.45e-14]*I @@ -3275,7 +3272,7 @@ cdef class ComplexBall(RingElement): [2.0081609898081 +/- 3.67e-14], [2.0019857082706 +/- 4.60e-14]] sage: ((a*tau+b)/(c*tau+d)).eisenstein(3)[2] - [331011.200433 +/- 1.36e-7] + [-711178.165575 +/- 5.18e-7]*I + [331011.2004330 +/- 9.33e-8] + [-711178.1655746 +/- 7.51e-8]*I sage: (c*tau+d)^8 * tau.eisenstein(3)[2] [331011.20043304 +/- 7.62e-9] + [-711178.1655746 +/- 1.34e-8]*I @@ -3309,20 +3306,20 @@ cdef class ComplexBall(RingElement): sage: tau = CBF(1,4) sage: z = CBF(sqrt(2), sqrt(3)) sage: z.elliptic_p(tau) - [-3.28920996772709 +/- 7.68e-15] + [-0.000367376730293 +/- 3.58e-16]*I + [-3.28920996772709 +/- 7.63e-15] + [-0.0003673767302933 +/- 6.04e-17]*I sage: (z + tau).elliptic_p(tau) - [-3.28920996772709 +/- 8.87e-15] + [-0.00036737673029 +/- 4.37e-15]*I + [-3.28920996772709 +/- 7.97e-15] + [-0.000367376730293 +/- 6.51e-16]*I sage: (z + 1).elliptic_p(tau) - [-3.28920996772709 +/- 7.68e-15] + [-0.000367376730293 +/- 3.58e-16]*I + [-3.28920996772709 +/- 7.63e-15] + [-0.0003673767302933 +/- 6.04e-17]*I sage: z.elliptic_p(tau, 3) - [[-3.28920996772709 +/- 7.66e-15] + [-0.000367376730293 +/- 3.45e-16]*I, - [0.00247305579431 +/- 2.06e-15] + [0.00385955404027 +/- 4.07e-15]*I, - [-0.0129908756171 +/- 2.12e-14] + [0.0072502752191 +/- 6.05e-14]*I] + [[-3.28920996772709 +/- 7.62e-15] + [-0.0003673767302933 +/- 5.40e-17]*I, + [0.002473055794309 +/- 5.01e-16] + [0.003859554040267 +/- 4.45e-16]*I, + [-0.01299087561709 +/- 4.72e-15] + [0.00725027521915 +/- 4.32e-15]*I] sage: (z + 3 + 4*tau).elliptic_p(tau, 3) - [[-3.2892099677271 +/- 3.40e-14] + [-0.0003673767303 +/- 2.49e-14]*I, - [0.00247305579 +/- 6.04e-12] + [0.00385955404 +/- 1.86e-12]*I, - [-0.012990876 +/- 4.77e-10] + [0.007250275 +/- 3.20e-10]*I] + [[-3.2892099677271 +/- 2.29e-14] + [-0.00036737673029 +/- 8.58e-15]*I, + [0.002473055794 +/- 6.59e-13] + [0.003859554040 +/- 6.17e-13]*I, + [-0.0129908756 +/- 3.39e-11] + [0.0072502752 +/- 3.60e-11]*I] """ cdef ComplexBall my_tau = self._parent.coerce(tau) @@ -3358,7 +3355,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(2,3).elliptic_k() - [1.0429132919285 +/- 5.77e-14] + [0.6296824723086 +/- 7.16e-14]*I + [1.0429132919285 +/- 3.65e-14] + [0.6296824723086 +/- 6.15e-14]*I """ cdef ComplexBall result = self._new() @@ -3375,7 +3372,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(2,3).elliptic_e() - [1.472797144959 +/- 5.13e-13] + [-1.231604783936 +/- 1.61e-13]*I + [1.472797144959 +/- 4.82e-13] + [-1.231604783936 +/- 1.25e-13]*I """ cdef ComplexBall result = self._new() @@ -3432,7 +3429,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(5,-6).jacobi_P(8, CBF(1,2), CBF(2,3)) - [-920983000.460 +/- 7.60e-4] + [6069919969.93 +/- 2.03e-3]*I + [-920983000.45982 +/- 2.22e-6] + [6069919969.92857 +/- 4.77e-6]*I """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3477,7 +3474,7 @@ cdef class ComplexBall(RingElement): sage: CBF(10).laguerre_L(3, 2) [-6.666666666667 +/- 4.15e-13] sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) - [5515.31503027 +/- 7.93e-9] + [-12386.94284527 +/- 8.00e-9]*I + [5515.315030271 +/- 4.37e-10] + [-12386.942845271 +/- 5.47e-10]*I """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3499,7 +3496,7 @@ cdef class ComplexBall(RingElement): sage: CBF(10).hermite_H(1) 20.00000000000000 sage: CBF(10).hermite_H(30) - [8.05746709617e+37 +/- 1.32e+25] + [8.0574670961707e+37 +/- 3.28e+23] """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3524,7 +3521,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1/2).legendre_P(5) 0.08984375000000000 sage: CBF(1,2).legendre_P(CBF(2,3), CBF(0,1)) - [0.10996180744 +/- 4.71e-12] + [0.14312767804 +/- 1.62e-12]*I + [0.10996180744364 +/- 7.45e-15] + [0.14312767804055 +/- 8.38e-15]*I sage: CBF(-10).legendre_P(5, 325/100) [-22104403.487377 +/- 6.81e-7] + [53364750.687392 +/- 7.25e-7]*I sage: CBF(-10).legendre_P(5, 325/100, type=3) @@ -3556,13 +3553,13 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1/2).legendre_Q(5) - [0.55508089057168 +/- 5.32e-15] + [0.55508089057168 +/- 2.79e-15] sage: CBF(1,2).legendre_Q(CBF(2,3), CBF(0,1)) - [0.167678710 +/- 5.89e-10] + [-0.161558598 +/- 8.76e-10]*I + [0.167678710 +/- 4.60e-10] + [-0.161558598 +/- 7.47e-10]*I sage: CBF(-10).legendre_Q(5, 325/100) - [-83825154.36008 +/- 4.95e-6] + [-34721515.80396 +/- 5.40e-6]*I + [-83825154.36008 +/- 4.94e-6] + [-34721515.80396 +/- 5.40e-6]*I sage: CBF(-10).legendre_Q(5, 325/100, type=3) - [-4.797306921692e-6 +/- 6.92e-19] + [-4.797306921692e-6 +/- 6.68e-19]*I + [-4.797306921692e-6 +/- 6.82e-19] + [-4.797306921692e-6 +/- 6.57e-19]*I """ cdef ComplexBall my_n = self._parent.coerce(n) diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 7332dc213ea..37383c41aa2 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -334,10 +334,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol. = CBF[] sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) - (([0.1428571428571428 +/- 7.70e-17])*x^2 + - ([-0.448798950512828 +/- 6.74e-16])*x - + [1.40994348586991 +/- 3.34e-15], - [-4.42946809718569 +/- 9.00e-15] - I) + (([0.1428571428571428 +/- 7.70e-17])*x^2 + ([-0.448798950512828 +/- 6.74e-16])*x + [1.40994348586991 +/- 3.04e-15], [-4.42946809718569 +/- 7.86e-15] - I) sage: Pol(0).quo_rem(x + 1) (0, 0) diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 6968a26b410..1945114895d 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1868,7 +1868,7 @@ cdef class RealBall(RingElement): EXAMPLES:: sage: RBF(0).union(1).endpoints() - (0.000000000000000, 1.00000000000000) + (-9.31322574615479e-10, 1.00000000093133) """ cdef RealBall my_other = self._parent.coerce(other) cdef RealBall res = self._new() @@ -3420,7 +3420,7 @@ cdef class RealBall(RingElement): sage: RBF(-1).zeta(1) [-0.0833333333333333 +/- 4.26e-17] sage: RBF(-1).zeta(2) - [-1.083333333333333 +/- 4.08e-16] + [-1.083333333333333 +/- 4.96e-16] """ cdef RealBall a_ball cdef RealBall res = self._new() @@ -3457,7 +3457,7 @@ cdef class RealBall(RingElement): TESTS:: sage: RBF(1/3).polylog(2r) - [0.36621322997706 +/- 4.62e-15] + [0.366213229977063 +/- 5.85e-16] """ cdef RealBall s_as_ball cdef Integer s_as_Integer From 20c5508517c97d7755905b75705328bec4468307 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 2 Aug 2017 08:45:29 +0100 Subject: [PATCH 020/218] one more arb-related doctest fix --- src/sage/functions/other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 2fd46fbd6c0..dfe2b0c46da 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1500,7 +1500,7 @@ def __init__(self): sage: RBF=RealBallField(53) sage: factorial(RBF(4.2)) - [32.5780960503313 +/- 6.71e-14] + [32.5780960503313 +/- 6.72e-14] Test pickling:: From 58cc73ba6fcb01141103b1e822a2b257eb750ae5 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 2 Aug 2017 14:45:22 +0100 Subject: [PATCH 021/218] merged more doctests from #18386, updated output Now arb can do all these computations just fine, no NaNs! --- src/sage/functions/log.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index fb5491a14b2..c2470035af3 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -442,23 +442,23 @@ def __init__(self): sage: polylog(2.0, 1) 1.64493406684823 sage: polylog(2, 1.0) - NaN + 1.64493406684823 sage: polylog(2.0, 1.0) - NaN + 1.64493406684823 sage: BF = RealBallField(100) sage: polylog(2, BF(1/3)) - [0.3662132299770634876167462976 +/- 8.13e-29] + [0.36621322997706348761674629766 +/- 4.51e-30] sage: polylog(2, BF(4/3)) nan sage: parent(_) Real ball field with 100 bits precision sage: polylog(2, CBF(1/3)) - [0.36621322997706 +/- 4.62e-15] + [0.366213229977063 +/- 5.85e-16] sage: parent(_) Complex ball field with 53 bits precision sage: polylog(2, CBF(1)) - nan + nan*I + [1.644934066848226 +/- 6.59e-16] sage: parent(_) Complex ball field with 53 bits precision """ @@ -537,7 +537,7 @@ def __init__(self): sage: dilog(1) 1/6*pi^2 sage: dilog(1.) - NaN + 1.64493406684823 sage: dilog(1).n() 1.64493406684823 sage: float(dilog(1)) From 07aad1a5e740a693a02e607ac727fd9745fbba50 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 2 Aug 2017 14:57:30 +0100 Subject: [PATCH 022/218] arb-related numerical noise in pynac --- src/sage/libs/pynac/pynac.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index edfef8c1267..3ede7738d90 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -1815,7 +1815,7 @@ cdef py_atan2(x, y): sage: atan2(CC(I), CC(I+1)) 0.553574358897045 + 0.402359478108525*I sage: atan2(CBF(I), CBF(I+1)) - [0.55357435889705 +/- 5.75e-15] + [0.40235947810852 +/- 6.01e-15]*I + [0.55357435889705 +/- 5.58e-15] + [0.402359478108525 +/- 7.11e-16]*I """ from sage.symbolic.constants import pi, NaN from sage.rings.real_arb import RealBallField From 788470ca4f99ee9e68a8f2a4bf12660c6d90d630 Mon Sep 17 00:00:00 2001 From: Emile Nadeau Date: Thu, 3 Aug 2017 10:47:32 -0400 Subject: [PATCH 023/218] Trac #23131: Correct code and doc formating --- src/sage/combinat/words/finite_word.py | 67 +++++++++++++------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 42b7a7551f9..256c704f13e 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2207,61 +2207,62 @@ def is_cadence(self, seq): def longest_forward_extension(self,x,y): r""" - Compute the length of le longest factor of self that starts at x and that - matches a factor that starts at y. Returns 0 if x or y are not valid + Compute the length of le longest factor of ``self`` that starts at ``x`` and that + matches a factor that starts at ``y``. Return 0 if ``x`` or ``y`` are not valid position in self. - INPUTS: + INPUT: - x,y - positions in self + - ``x``, ``y`` -- positions in ``self`` - EXAMPLES: + EXAMPLES:: - sage:w=Word('0011001') - sage:w.longest_forward_extension(0,5) + sage:w = Word('0011001') + sage:w.longest_forward_extension(0, 5) 3 - sage:w.longest_forward_extension(0,2) + sage:w.longest_forward_extension(0, 2) 0 - sage:w.longest_forward_extension(-3,2) + sage:w.longest_forward_extension(-3, 2) 0 """ - length=self.length() - if not (0<=x and 0<=y): + length = self.length() + if not (0 <= x and 0 <= y): return 0 - l=0 - while x=0 and y>=0 and self[x]==self[y]: - l+=1 - x-=1 - y-=1 + l = 0 + while x >= 0 and y >= 0 and self[x] == self[y]: + l += 1 + x -= 1 + y -= 1 return l def longest_common_suffix(self, other): From 59bf6aff82c88d5889ed3100e3aca63a2065a1c1 Mon Sep 17 00:00:00 2001 From: David Roe Date: Thu, 3 Aug 2017 19:38:51 +0000 Subject: [PATCH 024/218] Working on adding fraction field conversions to FM_template --- src/sage/rings/padics/FM_template.pxi | 361 +++++++++++++++++- src/sage/rings/padics/FM_template_header.pxi | 6 + .../rings/padics/padic_extension_generic.py | 2 + .../rings/padics/padic_fixed_mod_element.pxd | 1 + src/sage/rings/padics/qadic_flint_FM.pxd | 1 + 5 files changed, 370 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index 4f72ea20ee4..6aa786e6a23 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -1129,9 +1129,368 @@ cdef class pAdicConvert_QQ_FM(Morphism): cconv_mpq_t(ans.value, (x).value, ans.prime_pow.prec_cap, True, ans.prime_pow) return ans +cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): + """ + The canonical inclusion of Zq into its fraction field. + + EXAMPLES:: + + sage: R. = ZqFM(27, implementation='FLINT') + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R); f + Ring morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + + TESTS:: + + sage: TestSuite(f).run() + + """ + def __init__(self, R, K): + """ + Initialization. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R); type(f) + + """ + RingHomomorphism.__init__(self, R.Hom(K)) + self._zero = K(0) + self._section = pAdicConvert_FM_frac_field(K, R) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f(a) + a + """ + cdef FMElement x = _x + cdef FPElement ans = self._zero._new_c() + ans.ordp = cremove(ans.unit, x.value, x.prime_pow.ram_prec_cap, x.prime_pow) + return ans + + cpdef Element _call_with_args(self, _x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in + (relative or absolute or both). + + See the documentation for + :meth:`pAdicCappedAbsoluteElement.__init__` for more details. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f(a, 3) + a + sage: b = 117*a + sage: f(b, 3) + a*3^2 + sage: f(b, 4, 1) + a*3^2 + sage: f(b, 4, 3) + a*3^2 + a*3^3 + sage: f(b, absprec=4) + a*3^2 + a*3^3 + sage: f(b, relprec=3) + a*3^2 + a*3^3 + a*3^4 + sage: f(b, absprec=1) + 0 + sage: f(R(0)) + 0 + """ + cdef long aprec, rprec + cdef FMElement x = _x + if ciszero(x.value): + return self._zero + cdef FPElement ans = self._zero._new_c() + cdef bint reduce = False + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, ans.prime_pow) + ans.ordp = cremove(ans.unit, x.value, aprec, x.prime_pow) + if aprec < ans.ordp + rprec: + rprec = aprec - ans.ordp + if rprec <= 0: + return self._zero + creduce(ans.unit, ans.unit, rprec, ans.prime_pow) + return ans + + def section(self): + """ + Returns a map back to the ring that converts elements of + non-negative valuation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f(K.gen()) + a + O(3^20) + """ + return self._section + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: g = copy(f) # indirect doctest + sage: g + Ring morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + sage: g == f + True + sage: g is f + False + sage: g(a) + a + sage: g(a) == f(a) + True + + """ + _slots['_zero'] = self._zero + _slots['_section'] = self._section + return RingHomomorphism._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: g = copy(f) # indirect doctest + sage: g + Ring morphism: + From: Unramified Extension in a defined by x^2 + 2*x + 2 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^2 + 2*x + 2 with floating precision 20 over 3-adic Field + sage: g == f + True + sage: g is f + False + sage: g(a) + a + O(3^20) + sage: g(a) == f(a) + True + + """ + self._zero = _slots['_zero'] + self._section = _slots['_section'] + RingHomomorphism._update_slots(self, _slots) + + def is_injective(self): + r""" + Return whether this map is injective. + + EXAMPLES:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f.is_injective() + True + + """ + return True + + def is_surjective(self): + r""" + Return whether this map is surjective. + + EXAMPLES:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f.is_surjective() + False + + """ + return False + + +cdef class pAdicConvert_FM_frac_field(Morphism): + """ + The section of the inclusion from `\ZZ_q`` to its fraction field. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); f + Generic morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + """ + def __init__(self, K, R): + """ + Initialization. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); type(f) + + """ + Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) + self._zero = R(0) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: f(K.gen()) + a + O(3^20) + """ + cdef FPElement x = _x + if x.ordp < 0: raise ValueError("negative valuation") + cdef FMElement ans = self._zero._new_c() + cdef bint reduce = False + ans.absprec = x.relprec + x.ordp + if ans.absprec > ans.prime_pow.ram_prec_cap: + ans.absprec = ans.prime_pow.ram_prec_cap + reduce = True + if x.ordp >= ans.absprec: + csetzero(ans.value, ans.prime_pow) + else: + cshift(ans.value, x.unit, x.ordp, ans.absprec, ans.prime_pow, reduce) + return ans + + cpdef Element _call_with_args(self, _x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in + (relative or absolute or both). + + See the documentation for + :meth:`pAdicCappedAbsoluteElement.__init__` for more details. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); a = K(a) + sage: f(a, 3) + a + O(3^3) + sage: b = 9*a + sage: f(b, 3) + a*3^2 + O(3^3) + sage: f(b, 4, 1) + a*3^2 + O(3^3) + sage: f(b, 4, 3) + a*3^2 + O(3^4) + sage: f(b, absprec=4) + a*3^2 + O(3^4) + sage: f(b, relprec=3) + a*3^2 + O(3^5) + sage: f(b, absprec=1) + O(3) + sage: f(K(0)) + O(3^20) + """ + cdef long aprec, rprec + cdef FPElement x = _x + if x.ordp < 0: raise ValueError("negative valuation") + cdef FMElement ans = self._zero._new_c() + cdef bint reduce = False + _process_args_and_kwds(&aprec, &rprec, args, kwds, True, ans.prime_pow) + if x.relprec < rprec: + rprec = x.relprec + reduce = True + ans.absprec = rprec + x.ordp + if aprec < ans.absprec: + ans.absprec = aprec + reduce = True + if x.ordp >= ans.absprec: + csetzero(ans.value, ans.prime_pow) + else: + sig_on() + cshift(ans.value, x.unit, x.ordp, ans.absprec, ans.prime_pow, reduce) + sig_off() + return ans + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: a = K(a) + sage: g = copy(f) # indirect doctest + sage: g + Generic morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + sage: g == f + True + sage: g is f + False + sage: g(a) + a + O(3^20) + sage: g(a) == f(a) + True + + """ + _slots['_zero'] = self._zero + return Morphism._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: a = f(a) + sage: g = copy(f) # indirect doctest + sage: g + Generic morphism: + From: Unramified Extension in a defined by x^2 + 2*x + 2 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^2 + 2*x + 2 of fixed modulus 3^20 over 3-adic Ring + sage: g == f + True + sage: g is f + False + sage: g(a) + a + O(3^20) + sage: g(a) == f(a) + True + + """ + self._zero = _slots['_zero'] + Morphism._update_slots(self, _slots) + def unpickle_fme_v2(cls, parent, value): """ - Unpickles a capped relative element. + Unpickles a fixed-mod element. EXAMPLES:: diff --git a/src/sage/rings/padics/FM_template_header.pxi b/src/sage/rings/padics/FM_template_header.pxi index a2439686a86..c8443c1cd54 100644 --- a/src/sage/rings/padics/FM_template_header.pxi +++ b/src/sage/rings/padics/FM_template_header.pxi @@ -41,3 +41,9 @@ cdef class pAdicConvert_FM_ZZ(RingMap): cdef class pAdicConvert_QQ_FM(Morphism): cdef FMElement _zero cdef RingMap _section +# There should also be a pAdicConvert_CA_QQ for extension rings.... +cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): + cdef FPElement _zero + cdef Morphism _section +cdef class pAdicConvert_FM_frac_field(Morphism): + cdef FPElement _zero diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index 546ecf78a32..b6846dde06f 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -83,6 +83,8 @@ def _coerce_map_from_(self, R): from sage.rings.padics.qadic_flint_CR import pAdicCoercion_CR_frac_field as coerce_map elif R._prec_type() == 'floating-point': from sage.rings.padics.qadic_flint_FP import pAdicCoercion_FP_frac_field as coerce_map + elif R._prec_type() == 'fixed-mod': + from sage.rings.padics.qadic_flint_FM import pAdicCoercion_FM_frac_field as coerce_map return coerce_map(R, self) def __eq__(self, other): diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pxd b/src/sage/rings/padics/padic_fixed_mod_element.pxd index d82f89cd65f..cd619a1bcb2 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pxd +++ b/src/sage/rings/padics/padic_fixed_mod_element.pxd @@ -1,5 +1,6 @@ from sage.libs.gmp.types cimport mpz_t from cypari2.gen cimport Gen as pari_gen +from sage.rings.padics.padic_floating_point_element cimport FPElement ctypedef mpz_t celement include "FM_template_header.pxi" diff --git a/src/sage/rings/padics/qadic_flint_FM.pxd b/src/sage/rings/padics/qadic_flint_FM.pxd index c063afef3fa..7c2facd3aaa 100644 --- a/src/sage/rings/padics/qadic_flint_FM.pxd +++ b/src/sage/rings/padics/qadic_flint_FM.pxd @@ -1,5 +1,6 @@ from cypari2.gen cimport Gen as pari_gen from sage.libs.flint.types cimport fmpz_poly_t +from sage.rings.padics.qadic_flint_FP cimport FPElement from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram cdef class PowComputer_(PowComputer_flint_unram): From 7e62f70fbd338a99ae80921cc585261f406bc3e7 Mon Sep 17 00:00:00 2001 From: David Roe Date: Thu, 3 Aug 2017 21:30:21 +0000 Subject: [PATCH 025/218] Fixing errors in the coercion to the fraction field for fixed-mod p-adics --- src/sage/rings/padics/FM_template.pxi | 67 +++++++++----------- src/sage/rings/padics/FM_template_header.pxi | 2 +- src/sage/rings/padics/local_generic.py | 13 ++-- src/sage/rings/padics/padic_base_leaves.py | 2 +- src/sage/rings/ring.pyx | 1 + src/sage/structure/category_object.pyx | 2 + 6 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index b3bc5d13cf6..f968702abac 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -1271,6 +1271,8 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): a """ cdef FMElement x = _x + if ciszero(x.value, x.prime_pow): + return self._zero cdef FPElement ans = self._zero._new_c() ans.ordp = cremove(ans.unit, x.value, x.prime_pow.ram_prec_cap, x.prime_pow) return ans @@ -1308,17 +1310,17 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): """ cdef long aprec, rprec cdef FMElement x = _x - if ciszero(x.value): + if ciszero(x.value, x.prime_pow): return self._zero cdef FPElement ans = self._zero._new_c() cdef bint reduce = False - _process_args_and_kwds(&aprec, &rprec, args, kwds, False, ans.prime_pow) + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, x.prime_pow) ans.ordp = cremove(ans.unit, x.value, aprec, x.prime_pow) if aprec < ans.ordp + rprec: rprec = aprec - ans.ordp if rprec <= 0: return self._zero - creduce(ans.unit, ans.unit, rprec, ans.prime_pow) + creduce(ans.unit, ans.unit, rprec, x.prime_pow) return ans def section(self): @@ -1331,9 +1333,13 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): sage: R. = ZqFM(27) sage: K = R.fraction_field() sage: f = K.coerce_map_from(R) - sage: f(K.gen()) + sage: f.section()(K.gen()) a + O(3^20) """ + from sage.misc.constant_function import ConstantFunction + if not isinstance(self._section.domain, ConstantFunction): + import copy + self._section = copy.copy(self._section) return self._section cdef dict _extra_slots(self, dict _slots): @@ -1361,7 +1367,7 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): """ _slots['_zero'] = self._zero - _slots['_section'] = self._section + _slots['_section'] = self.section() # use method since it copies coercion-internal sections. return RingHomomorphism._extra_slots(self, _slots) cdef _update_slots(self, dict _slots): @@ -1383,7 +1389,7 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): sage: g is f False sage: g(a) - a + O(3^20) + a sage: g(a) == f(a) True @@ -1464,16 +1470,10 @@ cdef class pAdicConvert_FM_frac_field(Morphism): """ cdef FPElement x = _x if x.ordp < 0: raise ValueError("negative valuation") + if x.ordp >= self._zero.prime_pow.ram_prec_cap: + return self._zero cdef FMElement ans = self._zero._new_c() - cdef bint reduce = False - ans.absprec = x.relprec + x.ordp - if ans.absprec > ans.prime_pow.ram_prec_cap: - ans.absprec = ans.prime_pow.ram_prec_cap - reduce = True - if x.ordp >= ans.absprec: - csetzero(ans.value, ans.prime_pow) - else: - cshift(ans.value, x.unit, x.ordp, ans.absprec, ans.prime_pow, reduce) + cshift(ans.value, x.unit, x.ordp, ans.prime_pow.ram_prec_cap, ans.prime_pow, x.ordp > 0) return ans cpdef Element _call_with_args(self, _x, args=(), kwds={}): @@ -1490,42 +1490,35 @@ cdef class pAdicConvert_FM_frac_field(Morphism): sage: K = R.fraction_field() sage: f = R.convert_map_from(K); a = K(a) sage: f(a, 3) - a + O(3^3) - sage: b = 9*a + a + O(3^20) + sage: b = 117*a sage: f(b, 3) - a*3^2 + O(3^3) + a*3^2 + O(3^20) sage: f(b, 4, 1) - a*3^2 + O(3^3) + a*3^2 + O(3^20) sage: f(b, 4, 3) - a*3^2 + O(3^4) + a*3^2 + a*3^3 + O(3^20) sage: f(b, absprec=4) - a*3^2 + O(3^4) + a*3^2 + a*3^3 + O(3^20) sage: f(b, relprec=3) - a*3^2 + O(3^5) + a*3^2 + a*3^3 + a*3^4 + O(3^20) sage: f(b, absprec=1) - O(3) + O(3^20) sage: f(K(0)) O(3^20) """ cdef long aprec, rprec cdef FPElement x = _x if x.ordp < 0: raise ValueError("negative valuation") + if x.ordp >= self._zero.prime_pow.ram_prec_cap: + return self._zero cdef FMElement ans = self._zero._new_c() - cdef bint reduce = False _process_args_and_kwds(&aprec, &rprec, args, kwds, True, ans.prime_pow) - if x.relprec < rprec: - rprec = x.relprec - reduce = True - ans.absprec = rprec + x.ordp - if aprec < ans.absprec: - ans.absprec = aprec - reduce = True - if x.ordp >= ans.absprec: - csetzero(ans.value, ans.prime_pow) - else: - sig_on() - cshift(ans.value, x.unit, x.ordp, ans.absprec, ans.prime_pow, reduce) - sig_off() + if rprec < aprec - x.ordp: + aprec = x.ordp + rprec + sig_on() + cshift(ans.value, x.unit, x.ordp, aprec, ans.prime_pow, x.ordp > 0) + sig_off() return ans cdef dict _extra_slots(self, dict _slots): diff --git a/src/sage/rings/padics/FM_template_header.pxi b/src/sage/rings/padics/FM_template_header.pxi index c8443c1cd54..bd651167622 100644 --- a/src/sage/rings/padics/FM_template_header.pxi +++ b/src/sage/rings/padics/FM_template_header.pxi @@ -46,4 +46,4 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): cdef FPElement _zero cdef Morphism _section cdef class pAdicConvert_FM_frac_field(Morphism): - cdef FPElement _zero + cdef FMElement _zero diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 9c682bac8bd..caca3942ed6 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -365,6 +365,13 @@ def get_unramified_modulus(q, res_name): (functor_dict['print_mode'].get('mode') == 'digits' and p > getattr(functor, "p", p))): from .padic_printing import _printer_defaults kwds['alphabet'] = _printer_defaults.alphabet()[:p] + # For fraction fields of fixed-mod rings, we need to explicitly set show_prec = False + if 'field' in kwds and 'type' not in kwds: + if self._prec_type() == 'capped-abs': + kwds['type'] = 'capped-rel' + elif self._prec_type() == 'fixed-mod': + kwds['type'] = 'floating-point' + kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. # There are two kinds of functors possible: # CompletionFunctor and AlgebraicExtensionFunctor @@ -378,12 +385,6 @@ def get_unramified_modulus(q, res_name): field = kwds.pop('field') if field: ring = ring.fraction_field() - if 'type' not in kwds: - if self._prec_type() == 'capped-abs': - kwds['type'] = 'capped-rel' - elif self._prec_type() == 'fixed-mod': - kwds['type'] = 'floating-point' - kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. elif ring.is_field(): ring = ring.ring_of_integers() for atr in ('p', 'prec', 'type'): diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 29f42c9dde8..0cfc9252554 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -701,7 +701,7 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(ZpCA(17,40)) False """ - if isinstance(R, (pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): + if isinstance(R, (pAdicRingFixedMod, pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): if R.precision_cap() > self.precision_cap(): return True elif R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index da137a09260..fc9959023dc 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -119,6 +119,7 @@ cdef class Ring(ParentWithGens): running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index cdf4bff1c4a..23bbee9b430 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -803,6 +803,7 @@ cdef class CategoryObject(SageObject): running ._test_enumerated_set_iter_list() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_metric() . . . pass running ._test_new() . . . pass @@ -866,6 +867,7 @@ cdef class CategoryObject(SageObject): _test_enumerated_set_iter_list _test_eq _test_euclidean_degree + _test_fraction_field _test_gcd_vs_xgcd _test_metric _test_new From cb882fda2eb6a055b0176b8df5bf8cffd6c62be6 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 4 Aug 2017 02:37:55 +0000 Subject: [PATCH 026/218] Update add_bigoh to account for fixed-mod having a fraction field --- src/sage/rings/padics/FM_template.pxi | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index 7f6d68e4561..ac24aed663a 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -422,9 +422,7 @@ cdef class FMElement(pAdicTemplateElement): sage: a.add_bigoh(2^1000) 7 + O(7^4) sage: a.add_bigoh(-2^1000) - Traceback (most recent call last): - ... - ValueError: absprec must be at least 0 + 0 """ cdef long aprec @@ -436,14 +434,14 @@ cdef class FMElement(pAdicTemplateElement): if not isinstance(absprec, Integer): absprec = Integer(absprec) if mpz_sgn((absprec).value) == -1: - aprec = -1 + return self.parent().fraction_field()(0) elif mpz_fits_slong_p((absprec).value) == 0: - aprec = self.prime_pow.ram_prec_cap + return self else: aprec = mpz_get_si((absprec).value) if aprec < 0: - raise ValueError("absprec must be at least 0") - if aprec >= self.prime_pow.prec_cap: + return self.parent().fraction_field()(self, absprec) + elif aprec >= self.prime_pow.prec_cap: return self cdef FMElement ans = self._new_c() creduce(ans.value, self.value, aprec, ans.prime_pow) From a82697895556d4acda681ea0ca9f8fac8f0c51d1 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 4 Aug 2017 02:38:53 +0000 Subject: [PATCH 027/218] Fix _tester_add_bigoh --- src/sage/rings/padics/local_generic.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 1d37943db49..44ec0572a98 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -868,14 +868,10 @@ def _test_add_bigoh(self, **options): raise NotImplementedError # if absprec < 0, then the result is in the fraction field (see #13591) - try: - y = x.add_bigoh(-1) - except ValueError: - tester.assertTrue(self.is_fixed_mod()) - else: - tester.assertIs(y.parent(), self.fraction_field()) - if not self.is_floating_point(): - tester.assertLessEqual(y.precision_absolute(), -1) + y = x.add_bigoh(-1) + tester.assertIs(y.parent(), self.fraction_field()) + if not self.is_floating_point() and not self.is_fixed_mod(): + tester.assertLessEqual(y.precision_absolute(), -1) # make sure that we handle very large values correctly absprec = Integer(2)**1000 From 883e6b5fe81e5c2741ef8fb3521039ac6470fd0b Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 4 Aug 2017 03:46:54 +0000 Subject: [PATCH 028/218] Fix doctest in local_generic_element.pyx --- src/sage/rings/padics/local_generic_element.pyx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/padics/local_generic_element.pyx b/src/sage/rings/padics/local_generic_element.pyx index 99915c25685..1a25d0e9d12 100644 --- a/src/sage/rings/padics/local_generic_element.pyx +++ b/src/sage/rings/padics/local_generic_element.pyx @@ -430,13 +430,10 @@ cdef class LocalGenericElement(CommutativeRingElement): sage: R(3).add_bigoh(5) 3 + O(3^4) - However, a negative value for ``absprec`` leads to an error, since - there is no fraction field for fixed-mod elements:: + A negative value for ``absprec`` returns an element in the fraction field:: - sage: R(3).add_bigoh(-1) - Traceback (most recent call last): - ... - ValueError: absprec must be at least 0 + sage: R(3).add_bigoh(-1).parent() + 3-adic Field with floating precision 4 TESTS: From adae40d344f159248bfac6a5be1b7d719c27d542 Mon Sep 17 00:00:00 2001 From: Emile Nadeau Date: Wed, 16 Aug 2017 14:25:46 -0400 Subject: [PATCH 029/218] Trac #23131: Correct formating of code and doctest --- src/sage/combinat/words/finite_word.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 256c704f13e..ea56ca9cfb6 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2205,7 +2205,7 @@ def is_cadence(self, seq): return False return True - def longest_forward_extension(self,x,y): + def longest_forward_extension(self, x, y): r""" Compute the length of le longest factor of ``self`` that starts at ``x`` and that matches a factor that starts at ``y``. Return 0 if ``x`` or ``y`` are not valid @@ -2217,12 +2217,12 @@ def longest_forward_extension(self,x,y): EXAMPLES:: - sage:w = Word('0011001') - sage:w.longest_forward_extension(0, 5) + sage: w = Word('0011001') + sage: w.longest_forward_extension(0, 5) 3 - sage:w.longest_forward_extension(0, 2) + sage: w.longest_forward_extension(0, 2) 0 - sage:w.longest_forward_extension(-3, 2) + sage: w.longest_forward_extension(-3, 2) 0 """ length = self.length() @@ -2235,7 +2235,7 @@ def longest_forward_extension(self,x,y): y += 1 return l - def longest_backward_extension(self,x,y): + def longest_backward_extension(self, x, y): r""" Compute the length of le longest factor of ``self`` that ends at ``x`` and that matches a factor that ends at ``y``. Return 0 if ``x`` or ``y`` are not valid position @@ -2247,12 +2247,12 @@ def longest_backward_extension(self,x,y): EXAMPLES:: - sage:w = Word('0011001') - sage:w.longest_backward_extension(7, 2) + sage: w = Word('0011001') + sage: w.longest_backward_extension(7, 2) 3 - sage:w.longest_backward_extension(1, 5) + sage: w.longest_backward_extension(1, 5) 1 - sage:w.longest_backward_extension(4, 23) + sage: w.longest_backward_extension(4, 23) 0 """ length = self.length() From 8a8c36022a0dd1319f881bd8bc79e2088e99f1b6 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 17 Aug 2017 18:51:48 +0200 Subject: [PATCH 030/218] a first prototype --- ...free_quadratic_module_integer_symmetric.py | 270 ++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/sage/modules/free_quadratic_module_integer_symmetric.py diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py new file mode 100644 index 00000000000..3686877cfa8 --- /dev/null +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -0,0 +1,270 @@ +#***************************************************************************** +# Copyright (C) 2017 Simon Brandhorst +# +# 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/ +#***************************************************************************** +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid +#from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup_fixed_gens + + +############################################################################### +# +# Constructor functions +# +############################################################################### + +def IntegerLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): + + """ + Return the integral lattice spanned by basis in the ambient space. + + A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. + Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis + + INPUT: + + - ``ambient`` - a free quadratic module + + - ``basis`` - a list of elements of ambient or a matrix + + - ``inner_product_matrix`` - a symmetric matrix over the rationals + + + """ + if basis==None: + basis = matrix.identity(QQ,inner_product_matrix.ncols()) + if inner_product_matrix!=inner_product_matrix.transpose(): + raise ValueError("Argument inner_product_matrix (= %s) must be symmetric" % inner_product_matrix) + + return(FreeQuadraticModule_integer_symmetric(ambient=FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix),basis=basis,inner_product_matrix=inner_product_matrix,already_echelonized=False)) + + + +############################################################################### +# +# Base class for Lattices +# +############################################################################### + +class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): + """ + This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules + """ + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): + """ + Create the integral lattice spanned by basis in the ambient space. + + INPUT: + + - ``ambient`` - a free quadratic module + + - ``basis`` - a list of elements of ambient or a matrix + + - ``inner_product_matrix`` - a symmetric matrix over the rationals + + """ + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) + if self.determinant()==0: + raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") + if type(self.gram_matrix())!=sage.matrix.matrix_integer_dense.Matrix_integer_dense: + if self.gram_matrix().denominator()!=1: + raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") + + def _repr_(self): + """ + The printing representation of self. + + Examples:: + sage: A2 = IntegerLattice(matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2 + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [ 2 -1] + [-1 2] + """ + if self.is_sparse(): + s = "Sparse lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + else: + s = "Lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + return s + + + def is_even(self): + """ + Return True if the diagonal entries of the Gram matrix of self are even. + + + Examples:: + sage: L = IntegerLattice(Matrix(ZZ,2,2,[-1,1,1,2])) + sage: L.is_even() + False + sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: L.is_even() + True + """ + for d in self.gram_matrix().diagonal(): + if d % 2 !=0: + return(False) + return(True) + + def dual_lattice(self): + """ + Return the dual lattice of self as a FreeQuadraticModule + + Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. + + Examples:: + sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: Ldual=L.dual_lattice() + sage: Ldual + Free module of degree 2 and rank 2 over Integer Ring + Echelon basis matrix: + [1/3 2/3] + [ 0 1] + + Since our lattices are always integral, a lattice is contained in its dual + + sage: Ldual.is_submodule(L) + True + """ + return(self.span(self.gram_matrix().inverse()*self.basis_matrix())) + + def discriminant_group(self,s=0): + """ + Return the discriminant group $L^\vee / L$ of self. + + + Input: + s - an integer + + Examples:: + sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants (2, 10) + sage: L.discriminant_group(2) + Finitely generated module V/W over Integer Ring with invariants (2, 2) + sage: L.discriminant_group(5) + Finitely generated module V/W over Integer Ring with invariants (5) + + Tests:: + sage: L = IntegerLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants () + """ + D=self.dual_lattice()/self + #This is a workaround + if D.cardinality()==1: + d = 1 + else: + d = D.annihilator().gen() + a = prime_to_m_part(d,s) + Dp_gens = [a*g for g in D.gens()] + return(D.submodule(Dp_gens)) + + def signature(self): + """ + Returns the signature of self defined as + + number of positive eigenvalues - number of negative eigenvalues + + of the Gram matrix of self. + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return(QuadraticForm(QQ,self.gram_matrix()).signature()) + + def signature_pair(self): + """ + Returns the signature tuple $(n_+,n_-)$ of self. + + Here $n_+$ (resp. $n_-$) is the number of positive (resp. negative) eigenvalues of the gram_matrix of self + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()) + + + def direct_sum(self,M): + """ + Return the direct sum lattice of self with M + """ + + ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) + basis = self.basis_matrix().augment(matrix.zero(self.rank(),M.degree())).stack(matrix.zero(M.rank(),self.degree()).augment(M.basis_matrix())) + return(FreeQuadraticModule_integer_symmetric(ambient=ambient,basis=basis,inner_product_matrix=ambient.inner_product_matrix(),already_echelonized=False)) + + def is_primitive(self,M): + """ + Return True if M is a primitive submodule of self + + A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. + + """ + return(0==gcd((self/M).invariants())) + + def orthogonal_complement(self,M): + """ + Return the orthogonal complement of M in self. + """ + K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() + K.base_extend(QQ) + return(self.sublattice(self.intersection(K))) + + def sublattice(self,basis): + """ + Return the sublattice of self spanned by basis + + Input: + gens - a list of elements of self or a rational matrix + """ + M = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) + + if not M.is_submodule(self): + raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) + return(M) + + def overlattice(self,gens): + """ + Return the lattice spanned by self and gens + + Input: + gens - a list of elements of self or a rational matrix + """ + basis = (self+self.span(gens)).basis() + L = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) + + return(L) + + def genus(self): + """ + Return the genus of self + + Tests: + sage: L=IntegerLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.genus() + Genus of [0 1] + [1 0] + """ + from sage.quadratic_forms.genera.genus import Genus + return(Genus(self.gram_matrix())) + + def orthogonal_group(): + """ + Return the isometry group of this lattice embedded in the ambient module. + """ + raise NotImplementedError + + From 8b7671388303bb52dc30f3c94b80f4474560f424 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 18 Aug 2017 08:58:43 +0200 Subject: [PATCH 031/218] Doctests added, some bugs fixed --- ...free_quadratic_module_integer_symmetric.py | 138 ++++++++++++++++-- 1 file changed, 124 insertions(+), 14 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 3686877cfa8..d7967a6c407 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -9,7 +9,9 @@ #***************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid +from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule +from sage.matrix.constructor import matrix +from sage.arith.misc import prime_to_m_part,gcd #from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup_fixed_gens @@ -19,7 +21,7 @@ # ############################################################################### -def IntegerLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): +def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): """ Return the integral lattice spanned by basis in the ambient space. @@ -35,6 +37,27 @@ def IntegerLattice(inner_product_matrix,basis=None,already_echelonized=False,che - ``inner_product_matrix`` - a symmetric matrix over the rationals + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [0 1] + [1 0] + + We can specify a basis as well + + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + """ if basis==None: @@ -72,7 +95,7 @@ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_ech FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) if self.determinant()==0: raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") - if type(self.gram_matrix())!=sage.matrix.matrix_integer_dense.Matrix_integer_dense: + if self.gram_matrix().base_ring()!=ZZ: if self.gram_matrix().denominator()!=1: raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") @@ -81,7 +104,8 @@ def _repr_(self): The printing representation of self. Examples:: - sage: A2 = IntegerLattice(matrix(ZZ,2,2,[2,-1,-1,2])) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) sage: A2 Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: @@ -110,10 +134,11 @@ def is_even(self): Examples:: - sage: L = IntegerLattice(Matrix(ZZ,2,2,[-1,1,1,2])) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) sage: L.is_even() False - sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) sage: L.is_even() True """ @@ -129,7 +154,8 @@ def dual_lattice(self): Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. Examples:: - sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) sage: Ldual=L.dual_lattice() sage: Ldual Free module of degree 2 and rank 2 over Integer Ring @@ -153,7 +179,8 @@ def discriminant_group(self,s=0): s - an integer Examples:: - sage: L = IntegerLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) sage: L.discriminant_group() Finitely generated module V/W over Integer Ring with invariants (2, 10) sage: L.discriminant_group(2) @@ -162,10 +189,12 @@ def discriminant_group(self,s=0): Finitely generated module V/W over Integer Ring with invariants (5) Tests:: - sage: L = IntegerLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: L.discriminant_group() Finitely generated module V/W over Integer Ring with invariants () """ + D=self.dual_lattice()/self #This is a workaround if D.cardinality()==1: @@ -181,8 +210,14 @@ def signature(self): Returns the signature of self defined as number of positive eigenvalues - number of negative eigenvalues - of the Gram matrix of self. + + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: U.signature() + 0 + """ from sage.quadratic_forms.quadratic_form import QuadraticForm return(QuadraticForm(QQ,self.gram_matrix()).signature()) @@ -192,14 +227,33 @@ def signature_pair(self): Returns the signature tuple $(n_+,n_-)$ of self. Here $n_+$ (resp. $n_-$) is the number of positive (resp. negative) eigenvalues of the gram_matrix of self + + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2.signature_pair() + (2, 0) """ from sage.quadratic_forms.quadratic_form import QuadraticForm - return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()) + return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()[:2]) def direct_sum(self,M): """ Return the direct sum lattice of self with M + + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A = IntegralLattice(matrix([1])) + sage: A.direct_sum(A) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [1|0] + [-+-] + [0|1] """ ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) @@ -212,16 +266,44 @@ def is_primitive(self,M): A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L1 = U.span([vector([1,1])]) + sage: L2 = U.span([vector([1,-1])]) + sage: U.is_primitive(L1) + True + sage: U.is_primitive(L2) + True + sage: U.is_primitive(L1+L2) + False + + We can also compute the index + sage: (L1+L2).index_in(U) + 2 + """ return(0==gcd((self/M).invariants())) def orthogonal_complement(self,M): """ Return the orthogonal complement of M in self. + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) + sage: S = L.span([vector([1,1])]) + sage: L.orthogonal_complement(S) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 3] + Inner product matrix: + [ 2 1] + [ 1 -2] + """ K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() K.base_extend(QQ) - return(self.sublattice(self.intersection(K))) + return(self.sublattice(self.intersection(K).basis())) def sublattice(self,basis): """ @@ -229,9 +311,28 @@ def sublattice(self,basis): Input: gens - a list of elements of self or a rational matrix + + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: S = U.sublattice([vector([1,1])]) + sage: S + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + sage: U.sublattice([vector([1,-1])/2]) + Traceback (most recent call last): + ... + ValueError: Lattices must be integral. Use FreeQuadraticModule instead + sage: S.sublattice([vector([1,-1])]) + Traceback (most recent call last): + ... + ValueError: Argument basis (= [(1, -1)]) does not span a submodule of self """ M = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) - if not M.is_submodule(self): raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) return(M) @@ -242,6 +343,14 @@ def overlattice(self,gens): Input: gens - a list of elements of self or a rational matrix + + Examples:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) + sage: M = L.overlattice([vector([1,1])/2]) + sage: M.gram_matrix() + [1 1] + [1 2] """ basis = (self+self.span(gens)).basis() L = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) @@ -253,7 +362,8 @@ def genus(self): Return the genus of self Tests: - sage: L=IntegerLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: L.genus() Genus of [0 1] [1 0] From c992563eeea8df8950fcd1680b842e38a0d760a4 Mon Sep 17 00:00:00 2001 From: Emile Nadeau Date: Sun, 20 Aug 2017 21:11:11 -0400 Subject: [PATCH 032/218] Trac #23131: Minor correction and add a valueError for invalid parameter --- src/sage/combinat/words/finite_word.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index ea56ca9cfb6..153f36149c0 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2207,7 +2207,7 @@ def is_cadence(self, seq): def longest_forward_extension(self, x, y): r""" - Compute the length of le longest factor of ``self`` that starts at ``x`` and that + Compute the length of the longest factor of ``self`` that starts at ``x`` and that matches a factor that starts at ``y``. Return 0 if ``x`` or ``y`` are not valid position in self. @@ -2226,8 +2226,8 @@ def longest_forward_extension(self, x, y): 0 """ length = self.length() - if not (0 <= x and 0 <= y): - return 0 + if not (0 <= x and 0 <= y and x < length and y < length): + raise ValueError("x and y must be valid positions in self") l = 0 while x < length and y < length and self[x] == self[y]: l += 1 @@ -2237,13 +2237,13 @@ def longest_forward_extension(self, x, y): def longest_backward_extension(self, x, y): r""" - Compute the length of le longest factor of ``self`` that ends at ``x`` and that + Compute the length of the longest factor of ``self`` that ends at ``x`` and that matches a factor that ends at ``y``. Return 0 if ``x`` or ``y`` are not valid position in ``self``. INPUT: - - ``x``, ``y`` - positions in ``self`` + - ``x``, ``y`` -- positions in ``self`` EXAMPLES:: @@ -2256,8 +2256,8 @@ def longest_backward_extension(self, x, y): 0 """ length = self.length() - if not (x < length and y < length): - return 0 + if not (0 <= x and 0 <= y and x < length and y < length): + raise ValueError("x and y must be valid positions in self") l = 0 while x >= 0 and y >= 0 and self[x] == self[y]: l += 1 From 82338dceb541fafac98c357eefea04999c5e4002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Mon, 21 Aug 2017 12:46:24 +0800 Subject: [PATCH 033/218] Fix factorization over fraction fields that are isomorphic to function fields --- src/sage/rings/fraction_field.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index b8c49d230f0..007525a3d9b 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -839,6 +839,25 @@ def class_number(self): """ return 1 + def _factor_univariate_polynomial(self, f): + r""" + Return the factorization of ``f`` over this field. + + EXAMPLES:: + + sage: k. = GF(9) + sage: K = k['t'].fraction_field() + sage: R. = K[] + sage: f = x^3 + a + sage: f.factor() + (t + 2*a + 1)^3 + + """ + # The default implementation would try to convert this element to singular and factor there. + # This fails silently over some base fields, see #23642, so we convert + # to the function field and factor there. + return f.change_ring(self.function_field()).factor().base_change(self) + class FractionFieldEmbedding(DefaultConvertMap_unique): r""" From 8d3d3fa1a57ef9a7bb69799f0b961c05ffe81b84 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 21 Aug 2017 14:08:28 -0500 Subject: [PATCH 034/218] Some last little doc fixes. --- src/sage/combinat/words/finite_word.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 153f36149c0..76d27736185 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2207,9 +2207,8 @@ def is_cadence(self, seq): def longest_forward_extension(self, x, y): r""" - Compute the length of the longest factor of ``self`` that starts at ``x`` and that - matches a factor that starts at ``y``. Return 0 if ``x`` or ``y`` are not valid - position in self. + Compute the length of the longest factor of ``self`` that + starts at ``x`` and that matches a factor that starts at ``y``. INPUT: @@ -2218,12 +2217,14 @@ def longest_forward_extension(self, x, y): EXAMPLES:: sage: w = Word('0011001') - sage: w.longest_forward_extension(0, 5) + sage: w.longest_forward_extension(0, 4) 3 sage: w.longest_forward_extension(0, 2) 0 sage: w.longest_forward_extension(-3, 2) - 0 + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self """ length = self.length() if not (0 <= x and 0 <= y and x < length and y < length): @@ -2237,9 +2238,8 @@ def longest_forward_extension(self, x, y): def longest_backward_extension(self, x, y): r""" - Compute the length of the longest factor of ``self`` that ends at ``x`` and that - matches a factor that ends at ``y``. Return 0 if ``x`` or ``y`` are not valid position - in ``self``. + Compute the length of the longest factor of ``self`` that + ends at ``x`` and that matches a factor that ends at ``y``. INPUT: @@ -2248,12 +2248,16 @@ def longest_backward_extension(self, x, y): EXAMPLES:: sage: w = Word('0011001') - sage: w.longest_backward_extension(7, 2) + sage: w.longest_backward_extension(6, 2) 3 - sage: w.longest_backward_extension(1, 5) + sage: w.longest_backward_extension(1, 4) 1 - sage: w.longest_backward_extension(4, 23) + sage: w.longest_backward_extension(1, 3) 0 + sage: w.longest_backward_extension(4, 23) + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self """ length = self.length() if not (0 <= x and 0 <= y and x < length and y < length): From 7ee56991602e1a944baa73a6fc9c86d22b67dbd4 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Fri, 25 Aug 2017 20:32:13 +0000 Subject: [PATCH 035/218] trac 23131: allow negative positions --- src/sage/combinat/words/finite_word.py | 47 ++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 76d27736185..96d746bd191 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2221,14 +2221,33 @@ def longest_forward_extension(self, x, y): 3 sage: w.longest_forward_extension(0, 2) 0 - sage: w.longest_forward_extension(-3, 2) + + The method also accepts negative positions indicating the distance from + the end of the word (in order to be consist with how negative indices + work with lists). For instance, for a word of length `7`, using + positions `-3` and `2` is the same as using positions `4` and `2`:: + + sage: w.longest_forward_extension(1, -2) + 2 + sage: w.longest_forward_extension(4, -3) + 3 + + TESTS:: + + sage: w = Word('0011001') + sage: w.longest_forward_extension(-10, 2) Traceback (most recent call last): ... ValueError: x and y must be valid positions in self + """ length = self.length() - if not (0 <= x and 0 <= y and x < length and y < length): + if not (-length <= x < length and -length <= y < length): raise ValueError("x and y must be valid positions in self") + if x < 0: + x = x + length + if y < 0: + y = y + length l = 0 while x < length and y < length and self[x] == self[y]: l += 1 @@ -2254,14 +2273,36 @@ def longest_backward_extension(self, x, y): 1 sage: w.longest_backward_extension(1, 3) 0 + + The method also accepts negative positions indicating the distance from + the end of the word (in order to be consist with how negative indices + work with lists). For instance, for a word of length `7`, using + positions `6` and `-5` is the same as using positions `6` and `2`:: + + sage: w.longest_backward_extension(6, -5) + 3 + sage: w.longest_backward_extension(-6, 4) + 1 + + TESTS:: + + sage: w = Word('0011001') sage: w.longest_backward_extension(4, 23) Traceback (most recent call last): ... ValueError: x and y must be valid positions in self + sage: w.longest_backward_extension(-9, 4) + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self """ length = self.length() - if not (0 <= x and 0 <= y and x < length and y < length): + if not (-length <= x < length and -length <= y < length): raise ValueError("x and y must be valid positions in self") + if x < 0: + x = x + length + if y < 0: + y = y + length l = 0 while x >= 0 and y >= 0 and self[x] == self[y]: l += 1 From c728c1ae23e783ffd7a7932b37ad6a825c95a532 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 24 Aug 2017 19:02:53 -0500 Subject: [PATCH 036/218] Cythonized the iterator for Permutations. --- src/sage/combinat/permutation.py | 44 ++----------- src/sage/combinat/permutation_cython.pxd | 1 + src/sage/combinat/permutation_cython.pyx | 83 ++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 38 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 53978a4bc7f..7e0e69cf74f 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -260,7 +260,8 @@ from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.rsk import RSK, RSK_inverse from sage.combinat.permutation_cython import (left_action_product, - right_action_product, left_action_same_n, right_action_same_n) + right_action_product, left_action_same_n, right_action_same_n, + next_perm) class Permutation(CombinatorialElement): r""" @@ -5421,8 +5422,7 @@ def _repr_(self): def __iter__(self): r""" - Algorithm based on: - http://marknelson.us/2002/03/01/next-permutation/ + Iterate over ``self``. EXAMPLES:: @@ -5439,48 +5439,16 @@ def __iter__(self): mset = self.mset n = len(self.mset) lmset = list(mset) - mset_list = sorted((lmset.index(x) for x in lmset)) + mset_list = sorted(lmset.index(x) for x in lmset) yield self.element_class(self, [lmset[x] for x in mset_list]) if n <= 1: return - while True: - one = n - 2 - two = n - 1 - j = n - 1 - - #starting from the end, find the first o such that - #mset_list[o] < mset_list[o+1] - while two > 0 and mset_list[one] >= mset_list[two]: - one -= 1 - two -= 1 - - if two == 0: - return - - #starting from the end, find the first j such that - #mset_list[j] > mset_list[one] - while mset_list[j] <= mset_list[one]: - j -= 1 - - #Swap positions one and j - t = mset_list[one] - mset_list[one] = mset_list[j] - mset_list[j] = t - - #Reverse the list between two and last - i = int((n - two)/2)-1 - #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] - while i >= 0: - t = mset_list[ i + two ] - mset_list[ i + two ] = mset_list[n-1 - i] - mset_list[n-1 - i] = t - i -= 1 - + while next_perm(mset_list): #Yield the permutation - yield self.element_class(self, [lmset[x] for x in mset_list]) + yield self.element_class(self, [lmset[x] for x in mset_list]) def cardinality(self): """ diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index acf5b074c4b..7edd8397cbb 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -1,5 +1,6 @@ cdef void reset_swap(int n, int *c, int *o) cdef int next_swap(int n, int *c, int *o) +cpdef next_perm(list l) cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index d784ec937c8..910e9f92c9c 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -29,6 +29,8 @@ speed, we provide a class that wraps our struct. # Copyright 2010, Tom Boothby from __future__ import print_function +cimport cython + from cpython.list cimport * from cysignals.memory cimport sig_malloc, sig_free @@ -182,6 +184,87 @@ def permutation_iterator_transposition_list(int n): return T +##################################################################### +## iterator-type method for getting the next permutation + +@cython.wraparound(False) +@cython.boundscheck(False) +cpdef next_perm(list l): + """ + Obtain the next permutation under lex order of ``l`` + by mutating ``l``. + + Algorithm based on: + http://marknelson.us/2002/03/01/next-permutation/ + + INPUT: + + - ``l`` -- a list + + .. WARNING:: + + This method mutates the list ``l``. + + OUTPUT: + + boolean; whether another permutation was obtained + + EXAMPLES:: + + sage: from sage.combinat.permutation_cython import next_perm + sage: L = [1, 1, 2, 3] + sage: while next_perm(L): + ....: print(L) + [1, 1, 3, 2] + [1, 2, 1, 3] + [1, 2, 3, 1] + [1, 3, 1, 2] + [1, 3, 2, 1] + [2, 1, 1, 3] + [2, 1, 3, 1] + [2, 3, 1, 1] + [3, 1, 1, 2] + [3, 1, 2, 1] + [3, 2, 1, 1] + """ + cdef int n = len(l) + + if n <= 1: + return False + + cdef int one = n - 2 + cdef int two = n - 1 + cdef int j = n - 1 + + # Starting from the end, find the first o such that + # l[o] < l[o+1] + while two > 0 and l[one] >= l[two]: + one -= 1 + two -= 1 + + if two == 0: + return False + + #starting from the end, find the first j such that + #l[j] > l[one] + while l[j] <= l[one]: + j -= 1 + + #Swap positions one and j + t = l[one] + PyList_SET_ITEM(l, one, l[j]) + PyList_SET_ITEM(l, j, t) + + #Reverse the list between two and last + #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] + n -= 1 # In the loop, we only need n-1, so just do it once here + cdef int i + for i in xrange((n+1 - two) // 2 - 1, -1, -1): + t = l[i + two] + PyList_SET_ITEM(l, i + two, l[n - i]) + PyList_SET_ITEM(l, n - i, t) + + return True ##################################################################### From 5ba97be8282a8a1ae0cc7c6ff39d2af3a3ad4499 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 28 Aug 2017 11:18:47 -0500 Subject: [PATCH 037/218] Use Py_ssize_t instead of int. --- src/sage/combinat/permutation_cython.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 910e9f92c9c..1546902777c 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -227,14 +227,14 @@ cpdef next_perm(list l): [3, 1, 2, 1] [3, 2, 1, 1] """ - cdef int n = len(l) + cdef Py_ssize_t n = len(l) if n <= 1: return False - cdef int one = n - 2 - cdef int two = n - 1 - cdef int j = n - 1 + cdef Py_ssize_t one = n - 2 + cdef Py_ssize_t two = n - 1 + cdef Py_ssize_t j = n - 1 # Starting from the end, find the first o such that # l[o] < l[o+1] @@ -258,7 +258,7 @@ cpdef next_perm(list l): #Reverse the list between two and last #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] n -= 1 # In the loop, we only need n-1, so just do it once here - cdef int i + cdef Py_ssize_t i for i in xrange((n+1 - two) // 2 - 1, -1, -1): t = l[i + two] PyList_SET_ITEM(l, i + two, l[n - i]) From 4856761ac805418cc7620ba688361f8e6e4cb206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 22 Aug 2017 10:14:10 +0200 Subject: [PATCH 038/218] first sketch of implementation of hypergeometric motives --- src/doc/en/reference/modmisc/index.rst | 1 + src/sage/modular/hypergeometric_motive.py | 1181 +++++++++++++++++++++ src/sage/rings/padics/misc.py | 7 +- 3 files changed, 1186 insertions(+), 3 deletions(-) create mode 100644 src/sage/modular/hypergeometric_motive.py diff --git a/src/doc/en/reference/modmisc/index.rst b/src/doc/en/reference/modmisc/index.rst index 574e5796bcb..5158bd3248f 100644 --- a/src/doc/en/reference/modmisc/index.rst +++ b/src/doc/en/reference/modmisc/index.rst @@ -23,5 +23,6 @@ Miscellaneous Modular-Form-Related Modules sage/modular/cusps_nf + sage/modular/hypergeometric_motive .. include:: ../footer.txt diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py new file mode 100644 index 00000000000..a1d33e15cf4 --- /dev/null +++ b/src/sage/modular/hypergeometric_motive.py @@ -0,0 +1,1181 @@ +""" +Hypergeometric motives + +EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([30], [1,2,3,5])) + sage: H.alpha_beta() + ([1/30, 7/30, 11/30, 13/30, 17/30, 19/30, 23/30, 29/30], + [0, 1/5, 1/3, 2/5, 1/2, 3/5, 2/3, 4/5]) + sage: H.M_value() == 30**30 / (15**15 * 10**10 * 6**6) + True +""" +from collections import defaultdict + +from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime +from sage.arith.misc import gauss_sum +from sage.combinat.integer_vector_weighted import WeightedIntegerVectors +from sage.functions.generalized import sgn +from sage.functions.other import floor +from sage.misc.functional import cyclotomic_polynomial +from sage.misc.misc_c import prod +from sage.rings.fraction_field import FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.padics.factory import Zp +from sage.rings.padics.misc import gauss_sum as padic_gauss_sum +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.schemes.generic.spec import Spec +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + + +def convert_to_Z(x): + r""" + Convert from a specific extension of `p`-adic numbers to `\ZZ`. + + INPUT: + + - ``x`` -- element of the extension used for the `p`-adic + Gauss sums + + This is an extension of `\QQ_p` with one generator `\pi` + that satisfies `\pi ^ {p - 1} = -p`. + + OUTPUT: + + an integer in `\ZZ` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import convert_to_Z + sage: p = 5 + sage: R = Zp(p) + sage: X = PolynomialRing(R, name='X').gen() + sage: pi = R.ext(X**(p - 1) + p, names='pi').gen() + sage: convert_to_Z(1 + pi^4 + O(pi^80)) + -4 + sage: convert_to_Z(1 + pi^8 + 3*pi^12 + pi^16 + O(pi^80)) + 276 + + TESTS:: + + sage: g = pi^4 + O(pi^80) + sage: convert_to_Z(g) + -5 + sage: convert_to_Z(~~g) + -5 + """ + p = x.parent().base_ring().prime() + y = x.parent().integer_ring()(x) + L = y.list() + return ZZ.sum(L[(p - 1) * i] * (-p) ** i + for i in range(1 + len(L) // (p - 1))) + + +def characteristic_polynomial_from_traces(traces, d, q, i): + r""" + Given a sequence of traces `t_1, \dots, t_k`, return the + corresponding characteristic polynomial with Weil numbers as roots. + + The characteristic polynomial is defined by the generating series + + .. MATH:: + + P(T) = \exp\left(- \sum_{k\geq 1} t_k \frac{T^k}{k}\right) + + and should have the property that reciprocals of all roots have + absolute value `q^{i/2}`. + + There can be two possible signs for the leading coefficient. If + the degree ``d`` is even, one need at least ``floor(d/2)`` traces + and at least one more for odd ``d``. In case the correct sign for + the leading coefficient cannot be guessed from the given traces, + the output is a pair (f, dictionary). The number `f` is such that the + trace for `p^f` allows to fix the ambiguity. The dictionary maps + the two possible traces for `p^f` to the corresponding Euler + factors. + + INPUT: + + - ``traces`` -- a list of integers `t_1, \dots, t_k` + + - ``d`` -- the degree of the characteristic polynomial + + - ``q`` -- power of a prime number + + - ``i`` -- integer, the weight in the motivic sense + + OUTPUT: + + a polynomial or a pair (integer, dictionary) + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import characteristic_polynomial_from_traces + sage: characteristic_polynomial_from_traces([1, 1], 1, 3, 0) + -T + 1 + sage: characteristic_polynomial_from_traces([1], 1, 3, 0) + -T + 1 + + sage: characteristic_polynomial_from_traces([25,625], 1, 5, 4) + -25*T + 1 + sage: characteristic_polynomial_from_traces([25], 1, 5, 4) + -25*T + 1 + + sage: characteristic_polynomial_from_traces([3,-1,-18,-49], 2, 5, 1) + 5*T^2 - 3*T + 1 + sage: characteristic_polynomial_from_traces([3], 2, 5, 1) + 5*T^2 - 3*T + 1 + + sage: characteristic_polynomial_from_traces([-4,276], 4, 5, 3) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + sage: characteristic_polynomial_from_traces([4,-276], 4, 5, 3) + 15625*T^4 - 500*T^3 + 146*T^2 - 4*T + 1 + + sage: characteristic_polynomial_from_traces([1,-13,-20,71], 2, 7, 1) + 7*T^2 - T + 1 + sage: characteristic_polynomial_from_traces([1], 2, 7, 1) + 7*T^2 - T + 1 + + sage: characteristic_polynomial_from_traces([36,7620], 4, 17, 3) + 24137569*T^4 - 176868*T^3 - 3162*T^2 - 36*T + 1 + + TESTS:: + + sage: characteristic_polynomial_from_traces([0],2,17,1) + (2, {-34: 17*T^2 + 1, 34: -17*T^2 + 1}) + + sage: characteristic_polynomial_from_traces([-36], 4, 17, 3) + Traceback (most recent call last): + ... + ValueError: not enough traces were given + """ + if len(traces) < d // 2 + d % 2: + raise ValueError('not enough traces were given') + t = PowerSeriesRing(QQ, 't').gen() + ring = PolynomialRing(ZZ, 'T') + + series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) + N = min(len(traces), d) # never need more than d traces + series = series.O(N + 1).exp() + coeffs = list(series) + + rev_coeffs = {d - k: coeffs[k] * q**(-k * i + d * i // 2) + for k in range(len(coeffs)) if k <= d} + intersection = [k for k in range(len(coeffs)) + if k in rev_coeffs and coeffs[k]] + + def poly(sign): + data = [0 for _ in range(d + 1)] + for k in range(len(coeffs)): + data[k] = coeffs[k] + for k in rev_coeffs: + data[k] = sign * rev_coeffs[k] + return ring(data) + + if intersection: + idx = intersection[0] + sign = 1 if coeffs[idx] == rev_coeffs[idx] else -1 + return poly(sign) + else: + p1 = poly(1) + p2 = poly(-1) + s1 = (p1(t).O(t ** (d + 1))).log() + s2 = (p2(t).O(t ** (d + 1))).log() + index = (s1 - s2).valuation() + return (index, {-s1[index] * index: p1, -s2[index] * index: p2}) + # IDEA: also return the first index of trace + # that would allow sign recognition + # this means finding the first coefficient that differs in s1 and s2 + + +def possible_hypergeometric_data(d, weight=None): + """ + Return the list of possible parameters of hypergeometric motives. + + INPUT: + + - ``d`` -- the degree + + - ``weight`` -- optional integer, to specify the motivic weight + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import possible_hypergeometric_data + sage: P = possible_hypergeometric_data + sage: [len(P(i,weight=2)) for i in range(1, 7)] + [0, 0, 10, 30, 93, 234] + """ + bound = 2 * d * d # to make sure that phi(n) <= d + possible = [(i, euler_phi(i)) for i in range(1, bound + 1) + if euler_phi(i) <= d] + poids = [z[1] for z in possible] + N = len(poids) + vectors = list(WeightedIntegerVectors(d, poids)) + + def iterator(): + for i, u in enumerate(vectors): + supp_u = [j for j in range(N) if u[j]] + for v in vectors[i + 1:]: + if not any(v[j] for j in supp_u): + yield (u, v) + + def formule(u): + return [possible[j][0] for j in range(N) for _ in range(u[j])] + + data = [HypergeometricMotive(cyclotomic=(formule(a), formule(b))) + for a, b in iterator()] + if weight is None: + return data + else: + return [H for H in data if H.weight() == weight] + + +def cyclotomic_to_alpha(cyclo): + """ + Convert a list of indices of cyclotomic polynomials + to a list of rational numbers. + + The input represents a product of cyclotomic polynomials. + + The output is the list of arguments of the roots of the + given product of cyclotomic polynomials. + + This is the inverse of :func:`alpha_to_cyclotomic`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_alpha + sage: cyclotomic_to_alpha([1]) + [0] + sage: cyclotomic_to_alpha([2]) + [1/2] + sage: cyclotomic_to_alpha([5]) + [1/5, 2/5, 3/5, 4/5] + sage: cyclotomic_to_alpha([1,2,3,6]) + [0, 1/6, 1/3, 1/2, 2/3, 5/6] + sage: cyclotomic_to_alpha([2,3]) + [1/3, 1/2, 2/3] + """ + alpha = [] + for d in cyclo: + if d == 1: + alpha.append(QQ.zero()) + else: + for k in range(1, d): + if gcd(k, d) == 1: + alpha.append(QQ((k, d))) + return sorted(alpha) + + +def alpha_to_cyclotomic(alpha): + """ + Convert from a list of rationals arguments to a list of integers. + + The input represents arguments of some roots of unity. + + The output represent a product of cyclotomic polynomials with exactly + the given roots. + + This is the inverse of :func:`cyclotomic_to_alpha`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic + sage: alpha_to_cyclotomic([0]) + [1] + sage: alpha_to_cyclotomic([1/2]) + [2] + sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5]) + [5] + sage: alpha_to_cyclotomic([1/6, 1/3, 1/2, 2/3, 5/6, 1]) + [1, 2, 3, 6] + sage: alpha_to_cyclotomic([1/3,2/3,1/2]) + [2, 3] + """ + cyclo = [] + Alpha = list(alpha) + while Alpha: + q = QQ(Alpha.pop()) + d = q.denominator() + for k in range(1, d): + if gcd(k, d) == 1 and QQ((k, d)) != q: + Alpha.remove(QQ((k, d))) + cyclo.append(d) + return sorted(cyclo) + + +def capital_M(n): + """ + Auxiliary function, used to describe the canonical scheme. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + a rational + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import capital_M + sage: [capital_M(i) for i in range(1,8)] + [1, 4, 27, 64, 3125, 432, 823543] + """ + n = ZZ(n) + return QQ.prod(d ** (d * moebius(n / d)) for d in divisors(n)) + + +def cyclotomic_to_gamma(cyclo_up, cyclo_down): + """ + Convert a quotient of products of cyclotomic polynomials + to a quotient of products of polynomials `x^n - 1`. + + INPUT: + + - ``cyclo_up`` -- list of indices of cyclotomic polynomials + - ``cyclo_down`` -- list of indices of cyclotomic polynomials + + OUTPUT: + + a dictionary mapping an integer `n` to the power of `x^n - 1` that + appears in the given product + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_gamma + sage: cyclotomic_to_gamma([6], [1]) + {2: -1, 3: -1, 6: 1} + """ + dico = defaultdict(lambda: 0) + for d in cyclo_up: + dico[d] += 1 + for d in cyclo_down: + dico[d] -= 1 + + resu = defaultdict(lambda: 0) + for n in dico: + for d in divisors(n): + resu[d] += moebius(n / d) * dico[n] + + return {d: resu[d] for d in resu if resu[d]} + + +def gamma_list_to_cyclotomic(galist): + r""" + Convert a quotient of products of polynomials `x^n - 1` + to a quotient of products of cyclotomic polynomials. + + INPUT: + + - ``galist`` -- a list of integers, where an integer `n` represents + the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}` + + OUTPUT: + + a pair of list of integers, where `k` represents the cyclotomic + polynomial `\Phi_k` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic + sage: gamma_list_to_cyclotomic([-1, -1, 2]) + ([2], [1]) + + sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6]) + ([2, 6], [1, 1, 1]) + + sage: gamma_list_to_cyclotomic([-1, 2, 3, -4]) + ([3], [4]) + + sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1]) + ([2, 2, 8], [3, 3, 6]) + """ + resu = defaultdict(lambda: 0) + for n in galist: + eps = sgn(n) + for d in divisors(abs(n)): + resu[d] += eps + + return (sorted(d for d in resu for k in range(resu[d])), + sorted(d for d in resu for k in range(-resu[d]))) + + +class HypergeometricMotive(object): + def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): + """ + Creation of hypergeometric motives. + + INPUT: + + three possibilities are offered: + + - ``cyclotomic`` -- a pair of lists of nonnegative integers, + each integer `k` represents a cyclotomic polynomial `\Phi_k` + + - ``alpha_beta`` -- a pair of lists of rationals, + each rational represents a root of unity + + - ``gamma_list`` -- a pair of list of nonnegative integers, + each integer `n` represents a polynomial `x^n - 1` + + In the last case, it is also allowed to send just one list of signed + integers where signs indicate to which part the integer belongs to. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([2],[1])) + Hypergeometric motive for [1/2] and [0] + + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric motive for [1/2] and [0] + sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) + Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + + sage: Hyp(gamma_list=([5],[1,1,1,1,1])) + Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + """ + if gamma_list is not None: + if isinstance(gamma_list[0], (list, tuple)): + pos, neg = gamma_list + gamma_list = pos + [-u for u in neg] + cyclotomic = gamma_list_to_cyclotomic(gamma_list) + if cyclotomic is not None: + cyclo_up, cyclo_down = cyclotomic + if any(x in cyclo_up for x in cyclo_down): + raise ValueError('must be prime') + deg = sum(euler_phi(x) for x in cyclo_down) + up_deg = sum(euler_phi(x) for x in cyclo_up) + if up_deg != deg: + msg = 'not the same degree: {} != {}'.format(up_deg, deg) + raise ValueError(msg) + cyclo_up.sort() + cyclo_down.sort() + alpha = cyclotomic_to_alpha(cyclo_up) + beta = cyclotomic_to_alpha(cyclo_down) + elif alpha_beta is not None: + alpha, beta = alpha_beta + if len(alpha) != len(beta): + raise ValueError('alpha and beta not of the same length') + alpha = sorted(u - floor(u) for u in alpha) + beta = sorted(u - floor(u) for u in beta) + cyclo_up = alpha_to_cyclotomic(alpha) + cyclo_down = alpha_to_cyclotomic(beta) + deg = sum(euler_phi(x) for x in cyclo_down) + + self._cyclo_up = cyclo_up + self._cyclo_down = cyclo_down + self._alpha = alpha + self._beta = beta + self._deg = deg + + def __repr__(self): + """ + Return the string representation. + + This displays the rational arguments of the roots of unity. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric motive for [1/2] and [0] + """ + txt = "Hypergeometric motive for {} and {}" + return txt.format(self._alpha, self._beta) + + def twist(self): + r""" + Return the twist of ``self``. + + This is defined by adding `1/2` to each rational in `\alpha` + and `\beta`. + + This is an involution. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.twist() + Hypergeometric motive for [0] and [1/2] + + sage: Hyp(cyclotomic=([6],[1,2])).twist().cyclotomic_data() + ([3], [1, 2]) + """ + alpha = [x + QQ((1, 2)) for x in self._alpha] + beta = [x + QQ((1, 2)) for x in self._beta] + return HypergeometricMotive(alpha_beta=(alpha, beta)) + + def swap_alpha_beta(self): + """ + Return the hypergeometric motive with ``alpha`` and ``beta`` exchanged. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.swap_alpha_beta() + Hypergeometric motive for [0] and [1/2] + """ + alpha, beta = self.alpha_beta() + return HypergeometricMotive(alpha_beta=(beta, alpha)) + + def primitive_data(self): + """ + Return a primitive version. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_index`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H2 = Hyp(gamma_list=[-2, 4, 6, -8]) + sage: H2.primitive_data() == H + True + """ + g = self.gamma_list() + d = gcd(g) + return HypergeometricMotive(gamma_list=[x / d for x in g]) + + def weight(self): + """ + Return the motivic weight of ``self``. + + EXAMPLES: + + With rational inputs:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).weight() + 0 + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).weight() + 1 + sage: Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[0,0,1/4,3/4])).weight() + 1 + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.weight() + 1 + + With cyclotomic inputs:: + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).weight() + 2 + sage: Hyp(cyclotomic=([6],[1,2])).weight() + 0 + sage: Hyp(cyclotomic=([8],[1,2,3])).weight() + 0 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).weight() + 3 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).weight() + 1 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).weight() + 2 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).weight() + 1 + + With gamma list input:: + + sage: Hyp(gamma_list=([8,2,2,2],[6,4,3,1])).weight() + 3 + """ + alpha = self._alpha + beta = self._beta + D = [sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x) + for x in alpha + beta] + return ZZ(max(D) - min(D) - 1) + + def degree(self): + """ + Return the degree. + + This is the sum of the Hodge numbers. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).degree() + 1 + sage: Hyp(gamma_list=([2,2,4],[8])).degree() + 4 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).degree() + 6 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).degree() + 6 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).degree() + 4 + """ + return self._deg + + def defining_polynomials(self): + """ + Return the pair of products of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).defining_polynomials() + (x^2 + 1, x^2 - 2*x + 1) + """ + up = prod(cyclotomic_polynomial(d) for d in self._cyclo_up) + down = prod(cyclotomic_polynomial(d) for d in self._cyclo_down) + return (up, down) + + def cyclotomic_data(self): + """ + Return the pair of lists of indices of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).cyclotomic_data() + ([2], [1]) + """ + return (self._cyclo_up, self._cyclo_down) + + def alpha_beta(self): + """ + Return the pair of lists of rational arguments. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).alpha_beta() + ([1/2], [0]) + """ + return (self._alpha, self._beta) + + def M_value(self): + """ + Return the `M` coefficient that appears in the equations. + + OUTPUT: + + a rational + + .. SEEALSO:: :meth:`canonical_scheme` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.M_value() + 729/4096 + sage: Hyp(alpha_beta=(([1/2,1/2,1/2,1/2],[0,0,0,0]))).M_value() + 256 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).M_value() + 3125 + """ + up = QQ.prod(capital_M(d) for d in self._cyclo_up) + down = QQ.prod(capital_M(d) for d in self._cyclo_down) + return up / down + + def gamma_array(self): + r""" + Return the dictionary `\{v: \gamma_v\}` for the expression + + .. MATH:: + + \prod_v (T^v - 1)^{\gamma_v} + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_array() + {1: -2, 2: 1} + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_array() + {1: -3, 3: -1, 6: 1} + """ + return cyclotomic_to_gamma(self._cyclo_up, self._cyclo_down) + + def gamma_list(self): + r""" + Return a list of integers describing the `x^n - 1` factors. + + Each integer `n` stands for `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_list() + [-1, -1, 2] + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_list() + [-1, -1, -1, -3, 6] + + sage: Hyp(cyclotomic=([3],[4])).gamma_list() + [-1, 2, 3, -4] + """ + gamma = self.gamma_array() + resu = [] + for v in gamma: + resu += [sgn(gamma[v]) * v] * abs(gamma[v]) + return resu + + def __eq__(self, other): + """ + Return whether ``self`` is equal to ``other``. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 == H1 + True + sage: H1 == H2 + False + """ + return (self._alpha == other._alpha and + self._beta == other._beta) + + def __ne__(self, other): + """ + Return whether ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 != H1 + False + sage: H1 != H2 + True + """ + return not (self == other) + + def is_primitive(self): + """ + Return whether ``self`` is primitive. + + .. SEEALSO:: + + :meth:`primitive_index`, :meth:`primitive_data`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([3],[4])).is_primitive() + True + sage: Hyp(gamma_list=[-2, 4, 6, -8]).is_primitive() + False + sage: Hyp(gamma_list=[-3, 6, 9, -12]).is_primitive() + False + """ + return self.primitive_index() == 1 # ? + + def primitive_index(self): + """ + Return the primitive index. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_data`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([3],[4])).primitive_index() + 1 + sage: Hyp(gamma_list=[-2, 4, 6, -8]).primitive_index() + 2 + sage: Hyp(gamma_list=[-3, 6, 9, -12]).primitive_index() + 3 + """ + return gcd(self.gamma_list()) + + def has_symmetry_at_one(self): + """ + If ``True``, the motive H(t=1) is a direct sum of two motives. + + Note that simultaneous exchange of (t,1/t) and (alpha,beta) + always gives the same motive. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=[[1/2]*16,[0]*16]).has_symmetry_at_one() + True + + REFERENCE: + + - https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + """ + _, beta_twist = self.twist().alpha_beta() + return self.degree() % 2 == 0 and self._alpha == beta_twist + + def hodge_numbers(self): + """ + Return the Hodge numbers. + + .. SEEALSO:: + + :meth:`degree`, :meth:`hodge_polynomial` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[6])) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(cyclotomic=([4],[1,2])) + sage: H.hodge_numbers() + [2] + + sage: H = Hyp(gamma_list=([8,2,2,2],[6,4,3,1])) + sage: H.hodge_numbers() + [1, 2, 2, 1] + + sage: H = Hyp(gamma_list=([5],[1,1,1,1,1])) + sage: H.hodge_numbers() + [1, 1, 1, 1] + + sage: H = Hyp(gamma_list=[6,1,-4,-3]) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(gamma_list=[-3]*4 + [1]*12) + sage: H.hodge_numbers() + [1, 1, 1, 1, 1, 1, 1, 1] + """ + alpha = [(x, 'a') for x in self._alpha] + beta = [(x, 'b') for x in self._beta] + height = 0 + hodge = defaultdict(lambda: 0) + for x, letter in sorted(alpha + beta): + if letter == 'a': + hodge[height] += 1 + height += 1 + else: + height -= 1 + return [hodge[i] for i in sorted(hodge)] + + def hodge_polynomial(self): + """ + Return the Hodge polynomial. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([6,10],[3,12])) + sage: H.hodge_polynomial() + (T^3 + 2*T^2 + 2*T + 1)/T^2 + sage: H = Hyp(cyclotomic=([2,2,2,2,3,3,3,6,6],[1,1,4,5,9])) + sage: H.hodge_polynomial() + (T^5 + 3*T^4 + 3*T^3 + 3*T^2 + 3*T + 1)/T^2 + """ + alpha = self._alpha + beta = self._beta + + def D(x): + return (sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if 1 - b <= x)) + + def z(x): + return alpha.count(x) + + T = polygen(ZZ, 'T') + return sum(T ** (D(a) - z(a)) * (T**z(a) - 1) // (T - 1) + for a in set(alpha)) + + def padic_H_value(self, p, f, t, prec=20): + """ + Return the `p`-adic trace of the Frobenius. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``prec`` -- precision (optional, default 20) + + OUTPUT: + + an integer + + .. WARNING:: + + This is not yet working correctly. + + This is denoted by `U_q(t)` in the reference below. + + EXAMPLES: + + From Benasque report, page 8:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] + [0, -476] + sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] + [0, -4972] + + From slides:: + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: t = 189/125 + sage: H.padic_H_value(13,1,t) + 0 + + REFERENCE: + + - http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + """ + beta = self._beta + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + M = self.M_value() + D = (self.weight() + 1 - m[0]) // 2 + + gauss_table = [padic_gauss_sum(r, p, f, prec) for r in range(q - 1)] + + p_ring = Zp(p, prec=prec) + teich = p_ring.teichmuller(t * M) + sigma = sum(q**(D + m[0] - m[r]) * + prod(gauss_table[(v * r) % (q - 1)] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + return convert_to_Z(resu) + + def H_value(self, p, f, t, ring=None): + """ + Return the trace of the Frobenius. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``ring`` -- optional (default ``UniversalCyclotomicfield``) + + The ring could be also ``ComplexField(n)`` or ``QQbar``. + + OUTPUT: + + an integer + + .. WARNING:: + + This is apparently working correctly as can be tested + using ComplexField(70) as value ring. + + Using instead UniversalCyclotomicfield, this is much + slower than the `p`-adic version :meth:`padic_H_value`. + + EXAMPLES: + + With values in the UniversalCyclotomicField (slow):: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.H_value(7,i,-1) for i in range(1,3)] # not tested + [0, -476] + sage: [H.H_value(11,i,-1) for i in range(1,3)] # not tested + [0, -4972] + sage: [H.H_value(13,i,-1) for i in range(1,3)] # not tested + [-84, -1420] + + With values in ComplexField:: + + sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)] + [-4, 276] + + REFERENCES: + + - https://arxiv.org/pdf/1505.02900.pdf, Theorem 1.3 + + - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + """ + if ring is None: + ring = UniversalCyclotomicField() + beta = self._beta + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + D = (self.weight() + 1 - m[0]) // 2 + M = self.M_value() + + Fq = GF(q) + gen = Fq.multiplicative_generator() + zeta_q = ring.zeta(q - 1) + + tM = Fq(t * M) + for k in range(q - 1): + if gen ** k == tM: + teich = zeta_q ** k + break + + gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] + + sigma = sum(q**(D + m[0] - m[r]) * + prod(gauss_table[(-v * r) % (q - 1)] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + if not ring.is_exact(): + resu = resu.real_part().round() + return resu + + def euler_factor(self, t, p, degree=0): + """ + Return the Euler factor of the motive `H_t` at prime `p`. + + INPUT: + + - `t` -- rational number, not 0 or 1 + + - `p` -- prime number + + - ``degree`` -- optional integer (default 0) + + OUTPUT: + + a polynomial + + See http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + for explicit examples of Euler factors. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: H.euler_factor(-1, 5) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + + sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(4,p) + ....: for p in [5,7,11,13,17,19]] + [125*T^3 + 20*T^2 + 4*T + 1, + 343*T^3 - 42*T^2 - 6*T + 1, + -1331*T^3 - 22*T^2 + 2*T + 1, + -2197*T^3 - 156*T^2 + 12*T + 1, + 4913*T^3 + 323*T^2 + 19*T + 1, + 6859*T^3 - 57*T^2 - 3*T + 1] + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: t = 189/125 + sage: H.euler_factor(t,11) + 11*T^2 + 4*T + 1 + sage: H.euler_factor(t,13) + 13*T^2 + 1 + sage: H.euler_factor(t,17) + 17*T^2 + 1 + sage: H.euler_factor(t,19) + 19*T^2 + 1 + sage: H.euler_factor(t,23) # not tested + 23*T^2 + 8*T + 1 + sage: H.euler_factor(t,29) # not tested + 29*T^2 + 2*T + 1 + + REFERENCE: + + - https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + """ + if t not in QQ or t in [0, 1]: + raise ValueError('wrong t') + if not is_prime(p): + raise ValueError('p not prime') + if not all(x.denominator() % p for x in self._alpha + self._beta): + raise ValueError('p is wild') + if (t.valuation(p) or (t - 1).valuation(p) > 0): + raise ValueError('p is tame') + # now p is good + if degree == 0: + d = self.degree() + bound = d // 2 + d % 2 + traces = [self.padic_H_value(p, i + 1, t) for i in range(bound)] + + w = self.weight() + + # One has to handle the cases of sign ambiguity + resu = characteristic_polynomial_from_traces(traces, d, p, w) + if isinstance(resu, tuple): + f, dico = resu + return dico[self.padic_H_value(p, f, t)] + else: + return resu + + def canonical_scheme(self, t=None): + """ + Return the canonical scheme. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H.gamma_list() + [-1, 2, 3, -4] + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, -X0^2*X1^3 + 27/64*t*Y0*Y1^4) + + sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, -X0^3*X1^4 + 1728/3125*t*Y0^2*Y1^5) + """ + if t is None: + t = FractionField(QQ['t']).gen() + basering = t.parent() + gamma_pos = [u for u in self.gamma_list() if u > 0] + gamma_neg = [u for u in self.gamma_list() if u < 0] + N_pos = len(gamma_pos) + N_neg = len(gamma_neg) + varX = ['X{}'.format(i) for i in range(N_pos)] + varY = ['Y{}'.format(i) for i in range(N_neg)] + ring = PolynomialRing(basering, varX + varY) + gens = ring.gens() + X = gens[:N_pos] + Y = gens[N_pos:] + eq0 = ring.sum(X) - 1 + eq1 = ring.sum(Y) - 1 + eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) + eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) + + ideal = ring.ideal([eq0, eq1, self.M_value() * t * eq2_neg - eq2_pos]) + return Spec(ring.quotient(ideal)) diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index bdd5b5a14b4..7158b7ea9bf 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -47,13 +47,14 @@ def gauss_sum(a, p, f, prec=20): Rend. Sem. Mat. Univ. Padova 105 (2001), 157--170. Let `p` be a prime, `f` a positive integer, `q=p^f`, and `\pi` be - a root of `f(x) = x^{p-1}+p`. Let `0\leq a < q-1`. Then the + the unique root of `f(x) = x^{p-1}+p` congruent to `\zeta_p - 1` modulo + `(\zeta_p - 1)^2`. Let `0\leq a < q-1`. Then the Gross-Koblitz formula gives us the value of the Gauss sum `g_q(a)` - as a product of p-adic Gamma functions as follows: + as a product of `p`-adic Gamma functions as follows: .. MATH:: - g_q(a) = \pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)), + g_q(a) = -\pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)), where `s` is the sum of the digits of `a` in base `p` and the `a^{(i)}` have `p`-adic expansions obtained from cyclic From d5aae64066afbcb4edbc35d867b1122da8413c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 30 Aug 2017 16:57:31 +0200 Subject: [PATCH 039/218] trac 23671 adding tests --- src/sage/modular/hypergeometric_motive.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index a1d33e15cf4..a119dbdea35 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1103,9 +1103,9 @@ def euler_factor(self, t, p, degree=0): 17*T^2 + 1 sage: H.euler_factor(t,19) 19*T^2 + 1 - sage: H.euler_factor(t,23) # not tested + sage: H.euler_factor(t,23) 23*T^2 + 8*T + 1 - sage: H.euler_factor(t,29) # not tested + sage: H.euler_factor(t,29) 29*T^2 + 2*T + 1 REFERENCE: From 15c88927a333e50cebeab1b07c364ecaf2862418 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 28 Aug 2017 17:43:45 -0500 Subject: [PATCH 040/218] Using array and skipping the check. --- src/sage/combinat/permutation.py | 12 ++-- src/sage/combinat/permutation_cython.pxd | 6 +- src/sage/combinat/permutation_cython.pyx | 76 +++++++++++++++++------- 3 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 7e0e69cf74f..0bec90c153b 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -261,7 +261,7 @@ from sage.combinat.rsk import RSK, RSK_inverse from sage.combinat.permutation_cython import (left_action_product, right_action_product, left_action_same_n, right_action_same_n, - next_perm) + map_to_list, next_perm) class Permutation(CombinatorialElement): r""" @@ -5437,18 +5437,18 @@ def __iter__(self): [[]] """ mset = self.mset - n = len(self.mset) - lmset = list(mset) - mset_list = sorted(lmset.index(x) for x in lmset) + n = len(mset) + from array import array + mset_list = array('I', sorted(mset.index(x) for x in mset)) - yield self.element_class(self, [lmset[x] for x in mset_list]) + yield self.element_class(self, map_to_list(mset_list, mset, n), check=False) if n <= 1: return while next_perm(mset_list): #Yield the permutation - yield self.element_class(self, [lmset[x] for x in mset_list]) + yield self.element_class(self, map_to_list(mset_list, mset, n), check=False) def cardinality(self): """ diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index 7edd8397cbb..0ff39b13c4f 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -1,6 +1,10 @@ +from cpython cimport array +import array + cdef void reset_swap(int n, int *c, int *o) cdef int next_swap(int n, int *c, int *o) -cpdef next_perm(list l) +cpdef next_perm(array.array l) +cpdef list map_to_list(array.array l, tuple values, int n) cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 1546902777c..3088399d8d0 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -189,7 +189,7 @@ def permutation_iterator_transposition_list(int n): @cython.wraparound(False) @cython.boundscheck(False) -cpdef next_perm(list l): +cpdef next_perm(array.array l): """ Obtain the next permutation under lex order of ``l`` by mutating ``l``. @@ -199,11 +199,11 @@ cpdef next_perm(list l): INPUT: - - ``l`` -- a list + - ``l`` -- array of unsigned int (i.e., type ``'I'``) .. WARNING:: - This method mutates the list ``l``. + This method mutates the array ``l``. OUTPUT: @@ -212,20 +212,21 @@ cpdef next_perm(list l): EXAMPLES:: sage: from sage.combinat.permutation_cython import next_perm - sage: L = [1, 1, 2, 3] + sage: from array import array + sage: L = array('I', [1, 1, 2, 3]) sage: while next_perm(L): ....: print(L) - [1, 1, 3, 2] - [1, 2, 1, 3] - [1, 2, 3, 1] - [1, 3, 1, 2] - [1, 3, 2, 1] - [2, 1, 1, 3] - [2, 1, 3, 1] - [2, 3, 1, 1] - [3, 1, 1, 2] - [3, 1, 2, 1] - [3, 2, 1, 1] + array('I', [1L, 1L, 3L, 2L]) + array('I', [1L, 2L, 1L, 3L]) + array('I', [1L, 2L, 3L, 1L]) + array('I', [1L, 3L, 1L, 2L]) + array('I', [1L, 3L, 2L, 1L]) + array('I', [2L, 1L, 1L, 3L]) + array('I', [2L, 1L, 3L, 1L]) + array('I', [2L, 3L, 1L, 1L]) + array('I', [3L, 1L, 1L, 2L]) + array('I', [3L, 1L, 2L, 1L]) + array('I', [3L, 2L, 1L, 1L]) """ cdef Py_ssize_t n = len(l) @@ -235,10 +236,11 @@ cpdef next_perm(list l): cdef Py_ssize_t one = n - 2 cdef Py_ssize_t two = n - 1 cdef Py_ssize_t j = n - 1 + cdef unsigned int t # Starting from the end, find the first o such that # l[o] < l[o+1] - while two > 0 and l[one] >= l[two]: + while two > 0 and l.data.as_uints[one] >= l.data.as_uints[two]: one -= 1 two -= 1 @@ -247,25 +249,53 @@ cpdef next_perm(list l): #starting from the end, find the first j such that #l[j] > l[one] - while l[j] <= l[one]: + while l.data.as_uints[j] <= l.data.as_uints[one]: j -= 1 #Swap positions one and j - t = l[one] - PyList_SET_ITEM(l, one, l[j]) - PyList_SET_ITEM(l, j, t) + t = l.data.as_uints[one] + l.data.as_uints[one] = l.data.as_uints[j] + l.data.as_uints[j] = t #Reverse the list between two and last #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] n -= 1 # In the loop, we only need n-1, so just do it once here cdef Py_ssize_t i for i in xrange((n+1 - two) // 2 - 1, -1, -1): - t = l[i + two] - PyList_SET_ITEM(l, i + two, l[n - i]) - PyList_SET_ITEM(l, n - i, t) + t = l.data.as_uints[i + two] + l.data.as_uints[i + two] = l.data.as_uints[n - i] + l.data.as_uints[n - i] = t return True +cpdef list map_to_list(array.array l, tuple values, int n): + """ + Build a list by mapping the array ``l`` using ``values``. + + INPUT: + + - ``l`` -- array of unsigned int (i.e., type ``'I'``) + - ``values`` -- tuple; the values of the permutation + - ``n`` -- int; the length of the array ``l`` + + OUTPUT: + + A list representing the permutation. + + EXAMPLES:: + + sage: from array import array + sage: from sage.combinat.permutation_cython import map_to_list + sage: l = array('I', [0, 1, 0, 3, 3, 0, 1]) + sage: map_to_list(l, ('a', 'b', 'c', 'd'), 7) + ['a', 'b', 'a', 'd', 'd', 'a', 'b'] + """ + cdef int i + cdef list ret = [] + for i in xrange(n): + ret.append(values[l.data.as_uints[i]]) + return ret + ##################################################################### ## Multiplication functions for permutations From 08b5dae48cd9242dbaa758d03ac88b0232d93ddd Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 5 Sep 2017 09:42:46 +0200 Subject: [PATCH 041/218] Slight improvement in MultivectorModule._element_constructor_ --- src/sage/manifolds/differentiable/multivector_module.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index 17fb0abd96b..699d2c48be7 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -36,6 +36,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent +from sage.rings.integer import Integer from sage.categories.modules import Modules from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule from sage.manifolds.differentiable.multivectorfield import ( @@ -297,7 +298,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, True """ - if comp == 0: + if isinstance(comp, (int, Integer)) and comp == 0: return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction @@ -715,7 +716,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, True """ - if comp == 0: + if isinstance(comp, (int, Integer)) and comp == 0: return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction From db3363b4a150d7345e6ac1a8b5b72a426ccbf297 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Tue, 5 Sep 2017 15:40:02 +0000 Subject: [PATCH 042/218] Eliminate use of ramified extension --- src/sage/modular/hypergeometric_motive.py | 53 +++-------------------- src/sage/rings/padics/misc.py | 2 +- 2 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index a119dbdea35..0daa0400372 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -21,6 +21,7 @@ from sage.misc.functional import cyclotomic_polynomial from sage.misc.misc_c import prod from sage.rings.fraction_field import FractionField +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Zp from sage.rings.padics.misc import gauss_sum as padic_gauss_sum @@ -32,50 +33,6 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField - -def convert_to_Z(x): - r""" - Convert from a specific extension of `p`-adic numbers to `\ZZ`. - - INPUT: - - - ``x`` -- element of the extension used for the `p`-adic - Gauss sums - - This is an extension of `\QQ_p` with one generator `\pi` - that satisfies `\pi ^ {p - 1} = -p`. - - OUTPUT: - - an integer in `\ZZ` - - EXAMPLES:: - - sage: from sage.modular.hypergeometric_motive import convert_to_Z - sage: p = 5 - sage: R = Zp(p) - sage: X = PolynomialRing(R, name='X').gen() - sage: pi = R.ext(X**(p - 1) + p, names='pi').gen() - sage: convert_to_Z(1 + pi^4 + O(pi^80)) - -4 - sage: convert_to_Z(1 + pi^8 + 3*pi^12 + pi^16 + O(pi^80)) - 276 - - TESTS:: - - sage: g = pi^4 + O(pi^80) - sage: convert_to_Z(g) - -5 - sage: convert_to_Z(~~g) - -5 - """ - p = x.parent().base_ring().prime() - y = x.parent().integer_ring()(x) - L = y.list() - return ZZ.sum(L[(p - 1) * i] * (-p) ** i - for i in range(1 + len(L) // (p - 1))) - - def characteristic_polynomial_from_traces(traces, d, q, i): r""" Given a sequence of traces `t_1, \dots, t_k`, return the @@ -957,17 +914,19 @@ def padic_H_value(self, p, f, t, prec=20): M = self.M_value() D = (self.weight() + 1 - m[0]) // 2 - gauss_table = [padic_gauss_sum(r, p, f, prec) for r in range(q - 1)] + gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] p_ring = Zp(p, prec=prec) teich = p_ring.teichmuller(t * M) sigma = sum(q**(D + m[0] - m[r]) * - prod(gauss_table[(v * r) % (q - 1)] ** gv + (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv + for v, gv in gamma.items())//(p-1)) * + prod(gauss_table[(v * r) % (q - 1)][1] ** gv for v, gv in gamma.items()) * teich ** r for r in range(q - 1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma - return convert_to_Z(resu) + return IntegerModRing(p**prec)(resu).lift_centered() def H_value(self, p, f, t, ring=None): """ diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 0f59575f38c..9bd3254b76f 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -128,7 +128,7 @@ def gauss_sum(a, p, f, prec=20, factored=False): n = len(digits) digits = digits + [0] * (f - n) s = sum(digits) - out = -1 + out = R(-1) for i in range(f): a_i = R.sum(digits[k] * p**((i + k) % f) for k in range(f)) if a_i: From 8271a6b4d9610ade46bc9fc9942c56ee9b177a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 22 Aug 2017 10:14:10 +0200 Subject: [PATCH 043/218] first sketch of implementation of hypergeometric motives --- src/doc/en/reference/modmisc/index.rst | 1 + src/sage/modular/hypergeometric_motive.py | 1181 +++++++++++++++++++++ src/sage/rings/padics/misc.py | 7 +- 3 files changed, 1186 insertions(+), 3 deletions(-) create mode 100644 src/sage/modular/hypergeometric_motive.py diff --git a/src/doc/en/reference/modmisc/index.rst b/src/doc/en/reference/modmisc/index.rst index 574e5796bcb..5158bd3248f 100644 --- a/src/doc/en/reference/modmisc/index.rst +++ b/src/doc/en/reference/modmisc/index.rst @@ -23,5 +23,6 @@ Miscellaneous Modular-Form-Related Modules sage/modular/cusps_nf + sage/modular/hypergeometric_motive .. include:: ../footer.txt diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py new file mode 100644 index 00000000000..a1d33e15cf4 --- /dev/null +++ b/src/sage/modular/hypergeometric_motive.py @@ -0,0 +1,1181 @@ +""" +Hypergeometric motives + +EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([30], [1,2,3,5])) + sage: H.alpha_beta() + ([1/30, 7/30, 11/30, 13/30, 17/30, 19/30, 23/30, 29/30], + [0, 1/5, 1/3, 2/5, 1/2, 3/5, 2/3, 4/5]) + sage: H.M_value() == 30**30 / (15**15 * 10**10 * 6**6) + True +""" +from collections import defaultdict + +from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime +from sage.arith.misc import gauss_sum +from sage.combinat.integer_vector_weighted import WeightedIntegerVectors +from sage.functions.generalized import sgn +from sage.functions.other import floor +from sage.misc.functional import cyclotomic_polynomial +from sage.misc.misc_c import prod +from sage.rings.fraction_field import FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.padics.factory import Zp +from sage.rings.padics.misc import gauss_sum as padic_gauss_sum +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.schemes.generic.spec import Spec +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + + +def convert_to_Z(x): + r""" + Convert from a specific extension of `p`-adic numbers to `\ZZ`. + + INPUT: + + - ``x`` -- element of the extension used for the `p`-adic + Gauss sums + + This is an extension of `\QQ_p` with one generator `\pi` + that satisfies `\pi ^ {p - 1} = -p`. + + OUTPUT: + + an integer in `\ZZ` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import convert_to_Z + sage: p = 5 + sage: R = Zp(p) + sage: X = PolynomialRing(R, name='X').gen() + sage: pi = R.ext(X**(p - 1) + p, names='pi').gen() + sage: convert_to_Z(1 + pi^4 + O(pi^80)) + -4 + sage: convert_to_Z(1 + pi^8 + 3*pi^12 + pi^16 + O(pi^80)) + 276 + + TESTS:: + + sage: g = pi^4 + O(pi^80) + sage: convert_to_Z(g) + -5 + sage: convert_to_Z(~~g) + -5 + """ + p = x.parent().base_ring().prime() + y = x.parent().integer_ring()(x) + L = y.list() + return ZZ.sum(L[(p - 1) * i] * (-p) ** i + for i in range(1 + len(L) // (p - 1))) + + +def characteristic_polynomial_from_traces(traces, d, q, i): + r""" + Given a sequence of traces `t_1, \dots, t_k`, return the + corresponding characteristic polynomial with Weil numbers as roots. + + The characteristic polynomial is defined by the generating series + + .. MATH:: + + P(T) = \exp\left(- \sum_{k\geq 1} t_k \frac{T^k}{k}\right) + + and should have the property that reciprocals of all roots have + absolute value `q^{i/2}`. + + There can be two possible signs for the leading coefficient. If + the degree ``d`` is even, one need at least ``floor(d/2)`` traces + and at least one more for odd ``d``. In case the correct sign for + the leading coefficient cannot be guessed from the given traces, + the output is a pair (f, dictionary). The number `f` is such that the + trace for `p^f` allows to fix the ambiguity. The dictionary maps + the two possible traces for `p^f` to the corresponding Euler + factors. + + INPUT: + + - ``traces`` -- a list of integers `t_1, \dots, t_k` + + - ``d`` -- the degree of the characteristic polynomial + + - ``q`` -- power of a prime number + + - ``i`` -- integer, the weight in the motivic sense + + OUTPUT: + + a polynomial or a pair (integer, dictionary) + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import characteristic_polynomial_from_traces + sage: characteristic_polynomial_from_traces([1, 1], 1, 3, 0) + -T + 1 + sage: characteristic_polynomial_from_traces([1], 1, 3, 0) + -T + 1 + + sage: characteristic_polynomial_from_traces([25,625], 1, 5, 4) + -25*T + 1 + sage: characteristic_polynomial_from_traces([25], 1, 5, 4) + -25*T + 1 + + sage: characteristic_polynomial_from_traces([3,-1,-18,-49], 2, 5, 1) + 5*T^2 - 3*T + 1 + sage: characteristic_polynomial_from_traces([3], 2, 5, 1) + 5*T^2 - 3*T + 1 + + sage: characteristic_polynomial_from_traces([-4,276], 4, 5, 3) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + sage: characteristic_polynomial_from_traces([4,-276], 4, 5, 3) + 15625*T^4 - 500*T^3 + 146*T^2 - 4*T + 1 + + sage: characteristic_polynomial_from_traces([1,-13,-20,71], 2, 7, 1) + 7*T^2 - T + 1 + sage: characteristic_polynomial_from_traces([1], 2, 7, 1) + 7*T^2 - T + 1 + + sage: characteristic_polynomial_from_traces([36,7620], 4, 17, 3) + 24137569*T^4 - 176868*T^3 - 3162*T^2 - 36*T + 1 + + TESTS:: + + sage: characteristic_polynomial_from_traces([0],2,17,1) + (2, {-34: 17*T^2 + 1, 34: -17*T^2 + 1}) + + sage: characteristic_polynomial_from_traces([-36], 4, 17, 3) + Traceback (most recent call last): + ... + ValueError: not enough traces were given + """ + if len(traces) < d // 2 + d % 2: + raise ValueError('not enough traces were given') + t = PowerSeriesRing(QQ, 't').gen() + ring = PolynomialRing(ZZ, 'T') + + series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) + N = min(len(traces), d) # never need more than d traces + series = series.O(N + 1).exp() + coeffs = list(series) + + rev_coeffs = {d - k: coeffs[k] * q**(-k * i + d * i // 2) + for k in range(len(coeffs)) if k <= d} + intersection = [k for k in range(len(coeffs)) + if k in rev_coeffs and coeffs[k]] + + def poly(sign): + data = [0 for _ in range(d + 1)] + for k in range(len(coeffs)): + data[k] = coeffs[k] + for k in rev_coeffs: + data[k] = sign * rev_coeffs[k] + return ring(data) + + if intersection: + idx = intersection[0] + sign = 1 if coeffs[idx] == rev_coeffs[idx] else -1 + return poly(sign) + else: + p1 = poly(1) + p2 = poly(-1) + s1 = (p1(t).O(t ** (d + 1))).log() + s2 = (p2(t).O(t ** (d + 1))).log() + index = (s1 - s2).valuation() + return (index, {-s1[index] * index: p1, -s2[index] * index: p2}) + # IDEA: also return the first index of trace + # that would allow sign recognition + # this means finding the first coefficient that differs in s1 and s2 + + +def possible_hypergeometric_data(d, weight=None): + """ + Return the list of possible parameters of hypergeometric motives. + + INPUT: + + - ``d`` -- the degree + + - ``weight`` -- optional integer, to specify the motivic weight + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import possible_hypergeometric_data + sage: P = possible_hypergeometric_data + sage: [len(P(i,weight=2)) for i in range(1, 7)] + [0, 0, 10, 30, 93, 234] + """ + bound = 2 * d * d # to make sure that phi(n) <= d + possible = [(i, euler_phi(i)) for i in range(1, bound + 1) + if euler_phi(i) <= d] + poids = [z[1] for z in possible] + N = len(poids) + vectors = list(WeightedIntegerVectors(d, poids)) + + def iterator(): + for i, u in enumerate(vectors): + supp_u = [j for j in range(N) if u[j]] + for v in vectors[i + 1:]: + if not any(v[j] for j in supp_u): + yield (u, v) + + def formule(u): + return [possible[j][0] for j in range(N) for _ in range(u[j])] + + data = [HypergeometricMotive(cyclotomic=(formule(a), formule(b))) + for a, b in iterator()] + if weight is None: + return data + else: + return [H for H in data if H.weight() == weight] + + +def cyclotomic_to_alpha(cyclo): + """ + Convert a list of indices of cyclotomic polynomials + to a list of rational numbers. + + The input represents a product of cyclotomic polynomials. + + The output is the list of arguments of the roots of the + given product of cyclotomic polynomials. + + This is the inverse of :func:`alpha_to_cyclotomic`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_alpha + sage: cyclotomic_to_alpha([1]) + [0] + sage: cyclotomic_to_alpha([2]) + [1/2] + sage: cyclotomic_to_alpha([5]) + [1/5, 2/5, 3/5, 4/5] + sage: cyclotomic_to_alpha([1,2,3,6]) + [0, 1/6, 1/3, 1/2, 2/3, 5/6] + sage: cyclotomic_to_alpha([2,3]) + [1/3, 1/2, 2/3] + """ + alpha = [] + for d in cyclo: + if d == 1: + alpha.append(QQ.zero()) + else: + for k in range(1, d): + if gcd(k, d) == 1: + alpha.append(QQ((k, d))) + return sorted(alpha) + + +def alpha_to_cyclotomic(alpha): + """ + Convert from a list of rationals arguments to a list of integers. + + The input represents arguments of some roots of unity. + + The output represent a product of cyclotomic polynomials with exactly + the given roots. + + This is the inverse of :func:`cyclotomic_to_alpha`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic + sage: alpha_to_cyclotomic([0]) + [1] + sage: alpha_to_cyclotomic([1/2]) + [2] + sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5]) + [5] + sage: alpha_to_cyclotomic([1/6, 1/3, 1/2, 2/3, 5/6, 1]) + [1, 2, 3, 6] + sage: alpha_to_cyclotomic([1/3,2/3,1/2]) + [2, 3] + """ + cyclo = [] + Alpha = list(alpha) + while Alpha: + q = QQ(Alpha.pop()) + d = q.denominator() + for k in range(1, d): + if gcd(k, d) == 1 and QQ((k, d)) != q: + Alpha.remove(QQ((k, d))) + cyclo.append(d) + return sorted(cyclo) + + +def capital_M(n): + """ + Auxiliary function, used to describe the canonical scheme. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + a rational + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import capital_M + sage: [capital_M(i) for i in range(1,8)] + [1, 4, 27, 64, 3125, 432, 823543] + """ + n = ZZ(n) + return QQ.prod(d ** (d * moebius(n / d)) for d in divisors(n)) + + +def cyclotomic_to_gamma(cyclo_up, cyclo_down): + """ + Convert a quotient of products of cyclotomic polynomials + to a quotient of products of polynomials `x^n - 1`. + + INPUT: + + - ``cyclo_up`` -- list of indices of cyclotomic polynomials + - ``cyclo_down`` -- list of indices of cyclotomic polynomials + + OUTPUT: + + a dictionary mapping an integer `n` to the power of `x^n - 1` that + appears in the given product + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_gamma + sage: cyclotomic_to_gamma([6], [1]) + {2: -1, 3: -1, 6: 1} + """ + dico = defaultdict(lambda: 0) + for d in cyclo_up: + dico[d] += 1 + for d in cyclo_down: + dico[d] -= 1 + + resu = defaultdict(lambda: 0) + for n in dico: + for d in divisors(n): + resu[d] += moebius(n / d) * dico[n] + + return {d: resu[d] for d in resu if resu[d]} + + +def gamma_list_to_cyclotomic(galist): + r""" + Convert a quotient of products of polynomials `x^n - 1` + to a quotient of products of cyclotomic polynomials. + + INPUT: + + - ``galist`` -- a list of integers, where an integer `n` represents + the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}` + + OUTPUT: + + a pair of list of integers, where `k` represents the cyclotomic + polynomial `\Phi_k` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic + sage: gamma_list_to_cyclotomic([-1, -1, 2]) + ([2], [1]) + + sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6]) + ([2, 6], [1, 1, 1]) + + sage: gamma_list_to_cyclotomic([-1, 2, 3, -4]) + ([3], [4]) + + sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1]) + ([2, 2, 8], [3, 3, 6]) + """ + resu = defaultdict(lambda: 0) + for n in galist: + eps = sgn(n) + for d in divisors(abs(n)): + resu[d] += eps + + return (sorted(d for d in resu for k in range(resu[d])), + sorted(d for d in resu for k in range(-resu[d]))) + + +class HypergeometricMotive(object): + def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): + """ + Creation of hypergeometric motives. + + INPUT: + + three possibilities are offered: + + - ``cyclotomic`` -- a pair of lists of nonnegative integers, + each integer `k` represents a cyclotomic polynomial `\Phi_k` + + - ``alpha_beta`` -- a pair of lists of rationals, + each rational represents a root of unity + + - ``gamma_list`` -- a pair of list of nonnegative integers, + each integer `n` represents a polynomial `x^n - 1` + + In the last case, it is also allowed to send just one list of signed + integers where signs indicate to which part the integer belongs to. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([2],[1])) + Hypergeometric motive for [1/2] and [0] + + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric motive for [1/2] and [0] + sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) + Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + + sage: Hyp(gamma_list=([5],[1,1,1,1,1])) + Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + """ + if gamma_list is not None: + if isinstance(gamma_list[0], (list, tuple)): + pos, neg = gamma_list + gamma_list = pos + [-u for u in neg] + cyclotomic = gamma_list_to_cyclotomic(gamma_list) + if cyclotomic is not None: + cyclo_up, cyclo_down = cyclotomic + if any(x in cyclo_up for x in cyclo_down): + raise ValueError('must be prime') + deg = sum(euler_phi(x) for x in cyclo_down) + up_deg = sum(euler_phi(x) for x in cyclo_up) + if up_deg != deg: + msg = 'not the same degree: {} != {}'.format(up_deg, deg) + raise ValueError(msg) + cyclo_up.sort() + cyclo_down.sort() + alpha = cyclotomic_to_alpha(cyclo_up) + beta = cyclotomic_to_alpha(cyclo_down) + elif alpha_beta is not None: + alpha, beta = alpha_beta + if len(alpha) != len(beta): + raise ValueError('alpha and beta not of the same length') + alpha = sorted(u - floor(u) for u in alpha) + beta = sorted(u - floor(u) for u in beta) + cyclo_up = alpha_to_cyclotomic(alpha) + cyclo_down = alpha_to_cyclotomic(beta) + deg = sum(euler_phi(x) for x in cyclo_down) + + self._cyclo_up = cyclo_up + self._cyclo_down = cyclo_down + self._alpha = alpha + self._beta = beta + self._deg = deg + + def __repr__(self): + """ + Return the string representation. + + This displays the rational arguments of the roots of unity. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric motive for [1/2] and [0] + """ + txt = "Hypergeometric motive for {} and {}" + return txt.format(self._alpha, self._beta) + + def twist(self): + r""" + Return the twist of ``self``. + + This is defined by adding `1/2` to each rational in `\alpha` + and `\beta`. + + This is an involution. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.twist() + Hypergeometric motive for [0] and [1/2] + + sage: Hyp(cyclotomic=([6],[1,2])).twist().cyclotomic_data() + ([3], [1, 2]) + """ + alpha = [x + QQ((1, 2)) for x in self._alpha] + beta = [x + QQ((1, 2)) for x in self._beta] + return HypergeometricMotive(alpha_beta=(alpha, beta)) + + def swap_alpha_beta(self): + """ + Return the hypergeometric motive with ``alpha`` and ``beta`` exchanged. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.swap_alpha_beta() + Hypergeometric motive for [0] and [1/2] + """ + alpha, beta = self.alpha_beta() + return HypergeometricMotive(alpha_beta=(beta, alpha)) + + def primitive_data(self): + """ + Return a primitive version. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_index`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H2 = Hyp(gamma_list=[-2, 4, 6, -8]) + sage: H2.primitive_data() == H + True + """ + g = self.gamma_list() + d = gcd(g) + return HypergeometricMotive(gamma_list=[x / d for x in g]) + + def weight(self): + """ + Return the motivic weight of ``self``. + + EXAMPLES: + + With rational inputs:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).weight() + 0 + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).weight() + 1 + sage: Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[0,0,1/4,3/4])).weight() + 1 + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.weight() + 1 + + With cyclotomic inputs:: + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).weight() + 2 + sage: Hyp(cyclotomic=([6],[1,2])).weight() + 0 + sage: Hyp(cyclotomic=([8],[1,2,3])).weight() + 0 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).weight() + 3 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).weight() + 1 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).weight() + 2 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).weight() + 1 + + With gamma list input:: + + sage: Hyp(gamma_list=([8,2,2,2],[6,4,3,1])).weight() + 3 + """ + alpha = self._alpha + beta = self._beta + D = [sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x) + for x in alpha + beta] + return ZZ(max(D) - min(D) - 1) + + def degree(self): + """ + Return the degree. + + This is the sum of the Hodge numbers. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).degree() + 1 + sage: Hyp(gamma_list=([2,2,4],[8])).degree() + 4 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).degree() + 6 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).degree() + 6 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).degree() + 4 + """ + return self._deg + + def defining_polynomials(self): + """ + Return the pair of products of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).defining_polynomials() + (x^2 + 1, x^2 - 2*x + 1) + """ + up = prod(cyclotomic_polynomial(d) for d in self._cyclo_up) + down = prod(cyclotomic_polynomial(d) for d in self._cyclo_down) + return (up, down) + + def cyclotomic_data(self): + """ + Return the pair of lists of indices of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).cyclotomic_data() + ([2], [1]) + """ + return (self._cyclo_up, self._cyclo_down) + + def alpha_beta(self): + """ + Return the pair of lists of rational arguments. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).alpha_beta() + ([1/2], [0]) + """ + return (self._alpha, self._beta) + + def M_value(self): + """ + Return the `M` coefficient that appears in the equations. + + OUTPUT: + + a rational + + .. SEEALSO:: :meth:`canonical_scheme` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.M_value() + 729/4096 + sage: Hyp(alpha_beta=(([1/2,1/2,1/2,1/2],[0,0,0,0]))).M_value() + 256 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).M_value() + 3125 + """ + up = QQ.prod(capital_M(d) for d in self._cyclo_up) + down = QQ.prod(capital_M(d) for d in self._cyclo_down) + return up / down + + def gamma_array(self): + r""" + Return the dictionary `\{v: \gamma_v\}` for the expression + + .. MATH:: + + \prod_v (T^v - 1)^{\gamma_v} + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_array() + {1: -2, 2: 1} + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_array() + {1: -3, 3: -1, 6: 1} + """ + return cyclotomic_to_gamma(self._cyclo_up, self._cyclo_down) + + def gamma_list(self): + r""" + Return a list of integers describing the `x^n - 1` factors. + + Each integer `n` stands for `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_list() + [-1, -1, 2] + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_list() + [-1, -1, -1, -3, 6] + + sage: Hyp(cyclotomic=([3],[4])).gamma_list() + [-1, 2, 3, -4] + """ + gamma = self.gamma_array() + resu = [] + for v in gamma: + resu += [sgn(gamma[v]) * v] * abs(gamma[v]) + return resu + + def __eq__(self, other): + """ + Return whether ``self`` is equal to ``other``. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 == H1 + True + sage: H1 == H2 + False + """ + return (self._alpha == other._alpha and + self._beta == other._beta) + + def __ne__(self, other): + """ + Return whether ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 != H1 + False + sage: H1 != H2 + True + """ + return not (self == other) + + def is_primitive(self): + """ + Return whether ``self`` is primitive. + + .. SEEALSO:: + + :meth:`primitive_index`, :meth:`primitive_data`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([3],[4])).is_primitive() + True + sage: Hyp(gamma_list=[-2, 4, 6, -8]).is_primitive() + False + sage: Hyp(gamma_list=[-3, 6, 9, -12]).is_primitive() + False + """ + return self.primitive_index() == 1 # ? + + def primitive_index(self): + """ + Return the primitive index. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_data`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(cyclotomic=([3],[4])).primitive_index() + 1 + sage: Hyp(gamma_list=[-2, 4, 6, -8]).primitive_index() + 2 + sage: Hyp(gamma_list=[-3, 6, 9, -12]).primitive_index() + 3 + """ + return gcd(self.gamma_list()) + + def has_symmetry_at_one(self): + """ + If ``True``, the motive H(t=1) is a direct sum of two motives. + + Note that simultaneous exchange of (t,1/t) and (alpha,beta) + always gives the same motive. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: Hyp(alpha_beta=[[1/2]*16,[0]*16]).has_symmetry_at_one() + True + + REFERENCE: + + - https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + """ + _, beta_twist = self.twist().alpha_beta() + return self.degree() % 2 == 0 and self._alpha == beta_twist + + def hodge_numbers(self): + """ + Return the Hodge numbers. + + .. SEEALSO:: + + :meth:`degree`, :meth:`hodge_polynomial` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[6])) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(cyclotomic=([4],[1,2])) + sage: H.hodge_numbers() + [2] + + sage: H = Hyp(gamma_list=([8,2,2,2],[6,4,3,1])) + sage: H.hodge_numbers() + [1, 2, 2, 1] + + sage: H = Hyp(gamma_list=([5],[1,1,1,1,1])) + sage: H.hodge_numbers() + [1, 1, 1, 1] + + sage: H = Hyp(gamma_list=[6,1,-4,-3]) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(gamma_list=[-3]*4 + [1]*12) + sage: H.hodge_numbers() + [1, 1, 1, 1, 1, 1, 1, 1] + """ + alpha = [(x, 'a') for x in self._alpha] + beta = [(x, 'b') for x in self._beta] + height = 0 + hodge = defaultdict(lambda: 0) + for x, letter in sorted(alpha + beta): + if letter == 'a': + hodge[height] += 1 + height += 1 + else: + height -= 1 + return [hodge[i] for i in sorted(hodge)] + + def hodge_polynomial(self): + """ + Return the Hodge polynomial. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([6,10],[3,12])) + sage: H.hodge_polynomial() + (T^3 + 2*T^2 + 2*T + 1)/T^2 + sage: H = Hyp(cyclotomic=([2,2,2,2,3,3,3,6,6],[1,1,4,5,9])) + sage: H.hodge_polynomial() + (T^5 + 3*T^4 + 3*T^3 + 3*T^2 + 3*T + 1)/T^2 + """ + alpha = self._alpha + beta = self._beta + + def D(x): + return (sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if 1 - b <= x)) + + def z(x): + return alpha.count(x) + + T = polygen(ZZ, 'T') + return sum(T ** (D(a) - z(a)) * (T**z(a) - 1) // (T - 1) + for a in set(alpha)) + + def padic_H_value(self, p, f, t, prec=20): + """ + Return the `p`-adic trace of the Frobenius. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``prec`` -- precision (optional, default 20) + + OUTPUT: + + an integer + + .. WARNING:: + + This is not yet working correctly. + + This is denoted by `U_q(t)` in the reference below. + + EXAMPLES: + + From Benasque report, page 8:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] + [0, -476] + sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] + [0, -4972] + + From slides:: + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: t = 189/125 + sage: H.padic_H_value(13,1,t) + 0 + + REFERENCE: + + - http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + """ + beta = self._beta + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + M = self.M_value() + D = (self.weight() + 1 - m[0]) // 2 + + gauss_table = [padic_gauss_sum(r, p, f, prec) for r in range(q - 1)] + + p_ring = Zp(p, prec=prec) + teich = p_ring.teichmuller(t * M) + sigma = sum(q**(D + m[0] - m[r]) * + prod(gauss_table[(v * r) % (q - 1)] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + return convert_to_Z(resu) + + def H_value(self, p, f, t, ring=None): + """ + Return the trace of the Frobenius. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``ring`` -- optional (default ``UniversalCyclotomicfield``) + + The ring could be also ``ComplexField(n)`` or ``QQbar``. + + OUTPUT: + + an integer + + .. WARNING:: + + This is apparently working correctly as can be tested + using ComplexField(70) as value ring. + + Using instead UniversalCyclotomicfield, this is much + slower than the `p`-adic version :meth:`padic_H_value`. + + EXAMPLES: + + With values in the UniversalCyclotomicField (slow):: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.H_value(7,i,-1) for i in range(1,3)] # not tested + [0, -476] + sage: [H.H_value(11,i,-1) for i in range(1,3)] # not tested + [0, -4972] + sage: [H.H_value(13,i,-1) for i in range(1,3)] # not tested + [-84, -1420] + + With values in ComplexField:: + + sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)] + [-4, 276] + + REFERENCES: + + - https://arxiv.org/pdf/1505.02900.pdf, Theorem 1.3 + + - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + """ + if ring is None: + ring = UniversalCyclotomicField() + beta = self._beta + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + D = (self.weight() + 1 - m[0]) // 2 + M = self.M_value() + + Fq = GF(q) + gen = Fq.multiplicative_generator() + zeta_q = ring.zeta(q - 1) + + tM = Fq(t * M) + for k in range(q - 1): + if gen ** k == tM: + teich = zeta_q ** k + break + + gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] + + sigma = sum(q**(D + m[0] - m[r]) * + prod(gauss_table[(-v * r) % (q - 1)] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + if not ring.is_exact(): + resu = resu.real_part().round() + return resu + + def euler_factor(self, t, p, degree=0): + """ + Return the Euler factor of the motive `H_t` at prime `p`. + + INPUT: + + - `t` -- rational number, not 0 or 1 + + - `p` -- prime number + + - ``degree`` -- optional integer (default 0) + + OUTPUT: + + a polynomial + + See http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + for explicit examples of Euler factors. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: H.euler_factor(-1, 5) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + + sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(4,p) + ....: for p in [5,7,11,13,17,19]] + [125*T^3 + 20*T^2 + 4*T + 1, + 343*T^3 - 42*T^2 - 6*T + 1, + -1331*T^3 - 22*T^2 + 2*T + 1, + -2197*T^3 - 156*T^2 + 12*T + 1, + 4913*T^3 + 323*T^2 + 19*T + 1, + 6859*T^3 - 57*T^2 - 3*T + 1] + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: t = 189/125 + sage: H.euler_factor(t,11) + 11*T^2 + 4*T + 1 + sage: H.euler_factor(t,13) + 13*T^2 + 1 + sage: H.euler_factor(t,17) + 17*T^2 + 1 + sage: H.euler_factor(t,19) + 19*T^2 + 1 + sage: H.euler_factor(t,23) # not tested + 23*T^2 + 8*T + 1 + sage: H.euler_factor(t,29) # not tested + 29*T^2 + 2*T + 1 + + REFERENCE: + + - https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + """ + if t not in QQ or t in [0, 1]: + raise ValueError('wrong t') + if not is_prime(p): + raise ValueError('p not prime') + if not all(x.denominator() % p for x in self._alpha + self._beta): + raise ValueError('p is wild') + if (t.valuation(p) or (t - 1).valuation(p) > 0): + raise ValueError('p is tame') + # now p is good + if degree == 0: + d = self.degree() + bound = d // 2 + d % 2 + traces = [self.padic_H_value(p, i + 1, t) for i in range(bound)] + + w = self.weight() + + # One has to handle the cases of sign ambiguity + resu = characteristic_polynomial_from_traces(traces, d, p, w) + if isinstance(resu, tuple): + f, dico = resu + return dico[self.padic_H_value(p, f, t)] + else: + return resu + + def canonical_scheme(self, t=None): + """ + Return the canonical scheme. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H.gamma_list() + [-1, 2, 3, -4] + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, -X0^2*X1^3 + 27/64*t*Y0*Y1^4) + + sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, -X0^3*X1^4 + 1728/3125*t*Y0^2*Y1^5) + """ + if t is None: + t = FractionField(QQ['t']).gen() + basering = t.parent() + gamma_pos = [u for u in self.gamma_list() if u > 0] + gamma_neg = [u for u in self.gamma_list() if u < 0] + N_pos = len(gamma_pos) + N_neg = len(gamma_neg) + varX = ['X{}'.format(i) for i in range(N_pos)] + varY = ['Y{}'.format(i) for i in range(N_neg)] + ring = PolynomialRing(basering, varX + varY) + gens = ring.gens() + X = gens[:N_pos] + Y = gens[N_pos:] + eq0 = ring.sum(X) - 1 + eq1 = ring.sum(Y) - 1 + eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) + eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) + + ideal = ring.ideal([eq0, eq1, self.M_value() * t * eq2_neg - eq2_pos]) + return Spec(ring.quotient(ideal)) diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 1c65f6708b8..2327aad65d9 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -47,13 +47,14 @@ def gauss_sum(a, p, f, prec=20): Rend. Sem. Mat. Univ. Padova 105 (2001), 157--170. Let `p` be a prime, `f` a positive integer, `q=p^f`, and `\pi` be - a root of `f(x) = x^{p-1}+p`. Let `0\leq a < q-1`. Then the + the unique root of `f(x) = x^{p-1}+p` congruent to `\zeta_p - 1` modulo + `(\zeta_p - 1)^2`. Let `0\leq a < q-1`. Then the Gross-Koblitz formula gives us the value of the Gauss sum `g_q(a)` - as a product of p-adic Gamma functions as follows: + as a product of `p`-adic Gamma functions as follows: .. MATH:: - g_q(a) = \pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)), + g_q(a) = -\pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)), where `s` is the sum of the digits of `a` in base `p` and the `a^{(i)}` have `p`-adic expansions obtained from cyclic From a302f4dfc0d306244beb355b313fa51bdac543cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 30 Aug 2017 16:57:31 +0200 Subject: [PATCH 044/218] trac 23671 adding tests --- src/sage/modular/hypergeometric_motive.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index a1d33e15cf4..a119dbdea35 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1103,9 +1103,9 @@ def euler_factor(self, t, p, degree=0): 17*T^2 + 1 sage: H.euler_factor(t,19) 19*T^2 + 1 - sage: H.euler_factor(t,23) # not tested + sage: H.euler_factor(t,23) 23*T^2 + 8*T + 1 - sage: H.euler_factor(t,29) # not tested + sage: H.euler_factor(t,29) 29*T^2 + 2*T + 1 REFERENCE: From 83aecd9fae1429d6fbae1b4f95c0852ab867af94 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Mon, 4 Sep 2017 15:46:18 +0000 Subject: [PATCH 045/218] Modify p-adic Gauss sum to provide a factored option --- src/sage/rings/padics/misc.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 2327aad65d9..1e979dbb657 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -13,6 +13,7 @@ - David Roe - Adriana Salerno - Ander Steele +- Kiran Kedlaya (modified gauss_sum 2017/09) """ #***************************************************************************** # Copyright (C) 2007-2013 David Roe @@ -30,7 +31,7 @@ from six.moves.builtins import max as python_max from sage.rings.infinity import infinity -def gauss_sum(a, p, f, prec=20): +def gauss_sum(a, p, f, prec=20, factored=False): r""" Return the Gauss sum `g_q(a)` as a `p`-adic number. @@ -70,9 +71,15 @@ def gauss_sum(a, p, f, prec=20): - ``prec`` -- positive integer (optional, 20 by default) + - ``factored`` - boolean (optional, False by default) + OUTPUT: - a `p`-adic number in an Eisenstein extension of `\QQ_p` + If `factored` is False, returns a `p`-adic number in an Eisenstein extension of `\QQ_p`. + This number has the form `pi^e * z` where `pi` is as above, `e` is some nonnegative + integer, and `z` is an element of `\ZZ_p`; if `factored` is True, the pair `(e,z)` + is returned instead, and the Eisenstein extension is not formed. + .. NOTE:: @@ -101,6 +108,7 @@ def gauss_sum(a, p, f, prec=20): 6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 + pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 + pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242) +<<<<<<< HEAD .. SEEALSO:: @@ -109,22 +117,30 @@ def gauss_sum(a, p, f, prec=20): for prime finite fields - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum_numerical` for prime finite fields +======= + sage: gauss_sum(2,13,2,factored=True) + (2, 6 + 6*13 + 10*13^2 + O(13^5)) + +>>>>>>> Modify p-adic Gauss sum to provide a factored option """ from sage.rings.padics.factory import Zp from sage.rings.all import PolynomialRing a = a % (p**f - 1) R = Zp(p, prec) - X = PolynomialRing(R, name='X').gen() - pi = R.ext(X**(p - 1) + p, names='pi').gen() digits = Zp(p)(a).list(start_val=0) n = len(digits) digits = digits + [0] * (f - n) s = sum(digits) - out = -pi**s + out = -1 for i in range(f): a_i = R.sum(digits[k] * p**((i + k) % f) for k in range(f)) if a_i: out *= R((a_i / (p**f - 1)).gamma()) + if factored: + return(s, out) + X = PolynomialRing(R, name='X').gen() + pi = R.ext(X**(p - 1) + p, names='pi').gen() + out *= pi**s return out From 700a0b7aafbf88c1d3ad23888104a6d638bcef91 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Mon, 4 Sep 2017 15:50:34 +0000 Subject: [PATCH 046/218] Fixed typo in doctest --- src/sage/rings/padics/misc.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 1e979dbb657..ddcbe002cce 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -108,7 +108,6 @@ def gauss_sum(a, p, f, prec=20, factored=False): 6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 + pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 + pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242) -<<<<<<< HEAD .. SEEALSO:: @@ -117,11 +116,9 @@ def gauss_sum(a, p, f, prec=20, factored=False): for prime finite fields - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum_numerical` for prime finite fields -======= - sage: gauss_sum(2,13,2,factored=True) + sage: gauss_sum(2,13,2,prec=5,factored=True) (2, 6 + 6*13 + 10*13^2 + O(13^5)) - ->>>>>>> Modify p-adic Gauss sum to provide a factored option + """ from sage.rings.padics.factory import Zp from sage.rings.all import PolynomialRing From d57a3ebf7d6d0f2bad6f86ad4087fda8a00c7afe Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Tue, 5 Sep 2017 15:40:02 +0000 Subject: [PATCH 047/218] Eliminate use of ramified extension --- src/sage/modular/hypergeometric_motive.py | 53 +++-------------------- src/sage/rings/padics/misc.py | 2 +- 2 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index a119dbdea35..0daa0400372 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -21,6 +21,7 @@ from sage.misc.functional import cyclotomic_polynomial from sage.misc.misc_c import prod from sage.rings.fraction_field import FractionField +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Zp from sage.rings.padics.misc import gauss_sum as padic_gauss_sum @@ -32,50 +33,6 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField - -def convert_to_Z(x): - r""" - Convert from a specific extension of `p`-adic numbers to `\ZZ`. - - INPUT: - - - ``x`` -- element of the extension used for the `p`-adic - Gauss sums - - This is an extension of `\QQ_p` with one generator `\pi` - that satisfies `\pi ^ {p - 1} = -p`. - - OUTPUT: - - an integer in `\ZZ` - - EXAMPLES:: - - sage: from sage.modular.hypergeometric_motive import convert_to_Z - sage: p = 5 - sage: R = Zp(p) - sage: X = PolynomialRing(R, name='X').gen() - sage: pi = R.ext(X**(p - 1) + p, names='pi').gen() - sage: convert_to_Z(1 + pi^4 + O(pi^80)) - -4 - sage: convert_to_Z(1 + pi^8 + 3*pi^12 + pi^16 + O(pi^80)) - 276 - - TESTS:: - - sage: g = pi^4 + O(pi^80) - sage: convert_to_Z(g) - -5 - sage: convert_to_Z(~~g) - -5 - """ - p = x.parent().base_ring().prime() - y = x.parent().integer_ring()(x) - L = y.list() - return ZZ.sum(L[(p - 1) * i] * (-p) ** i - for i in range(1 + len(L) // (p - 1))) - - def characteristic_polynomial_from_traces(traces, d, q, i): r""" Given a sequence of traces `t_1, \dots, t_k`, return the @@ -957,17 +914,19 @@ def padic_H_value(self, p, f, t, prec=20): M = self.M_value() D = (self.weight() + 1 - m[0]) // 2 - gauss_table = [padic_gauss_sum(r, p, f, prec) for r in range(q - 1)] + gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] p_ring = Zp(p, prec=prec) teich = p_ring.teichmuller(t * M) sigma = sum(q**(D + m[0] - m[r]) * - prod(gauss_table[(v * r) % (q - 1)] ** gv + (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv + for v, gv in gamma.items())//(p-1)) * + prod(gauss_table[(v * r) % (q - 1)][1] ** gv for v, gv in gamma.items()) * teich ** r for r in range(q - 1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma - return convert_to_Z(resu) + return IntegerModRing(p**prec)(resu).lift_centered() def H_value(self, p, f, t, ring=None): """ diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index ddcbe002cce..151ad0a1c85 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -128,7 +128,7 @@ def gauss_sum(a, p, f, prec=20, factored=False): n = len(digits) digits = digits + [0] * (f - n) s = sum(digits) - out = -1 + out = R(-1) for i in range(f): a_i = R.sum(digits[k] * p**((i + k) % f) for k in range(f)) if a_i: From 10377d01754372eb22a4e656b92f6c70a288623f Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 6 Sep 2017 14:37:33 +0000 Subject: [PATCH 048/218] Interchange t for 1/t --- src/sage/modular/hypergeometric_motive.py | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 0daa0400372..8a2027948a4 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -898,7 +898,7 @@ def padic_H_value(self, p, f, t, prec=20): sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 - sage: H.padic_H_value(13,1,t) + sage: H.padic_H_value(13,1,1/t) 0 REFERENCE: @@ -917,7 +917,7 @@ def padic_H_value(self, p, f, t, prec=20): gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] p_ring = Zp(p, prec=prec) - teich = p_ring.teichmuller(t * M) + teich = p_ring.teichmuller(M / t) sigma = sum(q**(D + m[0] - m[r]) * (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv for v, gv in gamma.items())//(p-1)) * @@ -999,7 +999,7 @@ def H_value(self, p, f, t, ring=None): gen = Fq.multiplicative_generator() zeta_q = ring.zeta(q - 1) - tM = Fq(t * M) + tM = Fq(M / t) for k in range(q - 1): if gen ** k == tM: teich = zeta_q ** k @@ -1043,7 +1043,7 @@ def euler_factor(self, t, p, degree=0): sage: H.euler_factor(-1, 5) 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 - sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(4,p) + sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(1/4,p) ....: for p in [5,7,11,13,17,19]] [125*T^3 + 20*T^2 + 4*T + 1, 343*T^3 - 42*T^2 - 6*T + 1, @@ -1054,17 +1054,17 @@ def euler_factor(self, t, p, degree=0): sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 - sage: H.euler_factor(t,11) + sage: H.euler_factor(1/t,11) 11*T^2 + 4*T + 1 - sage: H.euler_factor(t,13) + sage: H.euler_factor(1/t,13) 13*T^2 + 1 - sage: H.euler_factor(t,17) + sage: H.euler_factor(1/t,17) 17*T^2 + 1 - sage: H.euler_factor(t,19) + sage: H.euler_factor(1/t,19) 19*T^2 + 1 - sage: H.euler_factor(t,23) + sage: H.euler_factor(1/t,23) 23*T^2 + 8*T + 1 - sage: H.euler_factor(t,29) + sage: H.euler_factor(1/t,29) 29*T^2 + 2*T + 1 REFERENCE: @@ -1109,14 +1109,14 @@ def canonical_scheme(self, t=None): Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal - (X0 + X1 - 1, Y0 + Y1 - 1, -X0^2*X1^3 + 27/64*t*Y0*Y1^4) + (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^2*X1^3 + 27/64*Y0*Y1^4) sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) sage: H.canonical_scheme() Spectrum of Quotient of Multivariate Polynomial Ring in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal - (X0 + X1 - 1, Y0 + Y1 - 1, -X0^3*X1^4 + 1728/3125*t*Y0^2*Y1^5) + (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^3*X1^4 + 1728/3125*Y0^2*Y1^5) """ if t is None: t = FractionField(QQ['t']).gen() @@ -1136,5 +1136,5 @@ def canonical_scheme(self, t=None): eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) - ideal = ring.ideal([eq0, eq1, self.M_value() * t * eq2_neg - eq2_pos]) + ideal = ring.ideal([eq0, eq1, self.M_value() * eq2_neg - t * eq2_pos]) return Spec(ring.quotient(ideal)) From cc19212f92fb3e1b005618e11016bf5683785a15 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 6 Sep 2017 17:19:18 +0000 Subject: [PATCH 049/218] General cleanup --- src/sage/modular/hypergeometric_motive.py | 69 +++++++++++------------ 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 95fa1462019..368aad1d575 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1,6 +1,16 @@ """ Hypergeometric motives +This is largely a port of the corresponding package in Magma. One +important conventional difference: the motivic parameter `t` has been replaced +with `1/t` to match the classical literature on hypergeometric series. +(E.g., see Beukers-Heckman, Monodromy for the hypergeometric function nF_{n-1}.) + +AUTHORS: + +- Frédéric Chapoton +- Kiran S. Kedlaya + EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp @@ -10,7 +20,20 @@ [0, 1/5, 1/3, 2/5, 1/2, 3/5, 2/3, 4/5]) sage: H.M_value() == 30**30 / (15**15 * 10**10 * 6**6) True + sage: H.euler_factor(2, 7) + T^8 + T^5 + T^3 + 1 """ +#***************************************************************************** +# Copyright (C) 2017 Frédéric Chapoton +# Kiran S. Kedlaya +# +# 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/ +#***************************************************************************** + from collections import defaultdict from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime @@ -857,7 +880,8 @@ def z(x): def padic_H_value(self, p, f, t, prec=20): """ - Return the `p`-adic trace of the Frobenius. + Return the `p`-adic trace of Frobenius, computed using the + Gross-Koblitz formula. INPUT: @@ -873,12 +897,6 @@ def padic_H_value(self, p, f, t, prec=20): an integer - .. WARNING:: - - This is not yet working correctly. - - This is denoted by `U_q(t)` in the reference below. - EXAMPLES: From Benasque report, page 8:: @@ -894,15 +912,11 @@ def padic_H_value(self, p, f, t, prec=20): sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] - From slides:: + From slides (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 -<<<<<<< HEAD sage: H.padic_H_value(13,1,1/t) -======= - sage: H.padic_H_value(13,1,t) ->>>>>>> db3363b4a150d7345e6ac1a8b5b72a426ccbf297 0 REFERENCE: @@ -921,11 +935,7 @@ def padic_H_value(self, p, f, t, prec=20): gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] p_ring = Zp(p, prec=prec) -<<<<<<< HEAD teich = p_ring.teichmuller(M / t) -======= - teich = p_ring.teichmuller(t * M) ->>>>>>> db3363b4a150d7345e6ac1a8b5b72a426ccbf297 sigma = sum(q**(D + m[0] - m[r]) * (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv for v, gv in gamma.items())//(p-1)) * @@ -1007,11 +1017,7 @@ def H_value(self, p, f, t, ring=None): gen = Fq.multiplicative_generator() zeta_q = ring.zeta(q - 1) -<<<<<<< HEAD tM = Fq(M / t) -======= - tM = Fq(t * M) ->>>>>>> db3363b4a150d7345e6ac1a8b5b72a426ccbf297 for k in range(q - 1): if gen ** k == tM: teich = zeta_q ** k @@ -1055,11 +1061,7 @@ def euler_factor(self, t, p, degree=0): sage: H.euler_factor(-1, 5) 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 -<<<<<<< HEAD sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(1/4,p) -======= - sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(4,p) ->>>>>>> db3363b4a150d7345e6ac1a8b5b72a426ccbf297 ....: for p in [5,7,11,13,17,19]] [125*T^3 + 20*T^2 + 4*T + 1, 343*T^3 - 42*T^2 - 6*T + 1, @@ -1070,18 +1072,13 @@ def euler_factor(self, t, p, degree=0): sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 - sage: H.euler_factor(1/t,11) - 11*T^2 + 4*T + 1 - sage: H.euler_factor(1/t,13) - 13*T^2 + 1 - sage: H.euler_factor(1/t,17) - 17*T^2 + 1 - sage: H.euler_factor(1/t,19) - 19*T^2 + 1 - sage: H.euler_factor(1/t,23) - 23*T^2 + 8*T + 1 - sage: H.euler_factor(1/t,29) - 29*T^2 + 2*T + 1 + sage: [H.euler_factor(1/t,p) for p in [11,13,17,19,23,29]] + [11*T^2 + 4*T + 1, + 13*T^2 + 1, + 17*T^2 + 1, + 19*T^2 + 1, + 23*T^2 + 8*T + 1, + 29*T^2 + 2*T + 1] REFERENCE: From 9f5dd9dfa9ba042532b65125cd56c520530ef25e Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 7 Sep 2017 13:23:43 +0000 Subject: [PATCH 050/218] Add zigzag function, change class name to HypergeometricData --- src/sage/modular/hypergeometric_motive.py | 94 ++++++++++++++--------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 368aad1d575..e6afe8ad7d1 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -13,7 +13,7 @@ EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([30], [1,2,3,5])) sage: H.alpha_beta() ([1/30, 7/30, 11/30, 13/30, 17/30, 19/30, 23/30, 29/30], @@ -207,7 +207,7 @@ def iterator(): def formule(u): return [possible[j][0] for j in range(N) for _ in range(u[j])] - data = [HypergeometricMotive(cyclotomic=(formule(a), formule(b))) + data = [HypergeometricData(cyclotomic=(formule(a), formule(b))) for a, b in iterator()] if weight is None: return data @@ -386,7 +386,7 @@ def gamma_list_to_cyclotomic(galist): sorted(d for d in resu for k in range(-resu[d]))) -class HypergeometricMotive(object): +class HypergeometricData(object): def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): """ Creation of hypergeometric motives. @@ -409,7 +409,7 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([2],[1])) Hypergeometric motive for [1/2] and [0] @@ -463,7 +463,7 @@ def __repr__(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])) Hypergeometric motive for [1/2] and [0] """ @@ -481,7 +481,7 @@ def twist(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2],[0])) sage: H.twist() Hypergeometric motive for [0] and [1/2] @@ -491,7 +491,7 @@ def twist(self): """ alpha = [x + QQ((1, 2)) for x in self._alpha] beta = [x + QQ((1, 2)) for x in self._beta] - return HypergeometricMotive(alpha_beta=(alpha, beta)) + return HypergeometricData(alpha_beta=(alpha, beta)) def swap_alpha_beta(self): """ @@ -499,13 +499,13 @@ def swap_alpha_beta(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2],[0])) sage: H.swap_alpha_beta() Hypergeometric motive for [0] and [1/2] """ alpha, beta = self.alpha_beta() - return HypergeometricMotive(alpha_beta=(beta, alpha)) + return HypergeometricData(alpha_beta=(beta, alpha)) def primitive_data(self): """ @@ -517,7 +517,7 @@ def primitive_data(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([3],[4])) sage: H2 = Hyp(gamma_list=[-2, 4, 6, -8]) sage: H2.primitive_data() == H @@ -525,7 +525,33 @@ def primitive_data(self): """ g = self.gamma_list() d = gcd(g) - return HypergeometricMotive(gamma_list=[x / d for x in g]) + return HypergeometricData(gamma_list=[x / d for x in g]) + + def zigzag(self, x): + """ + Count ``alpha``'s up to ``x`` minus ``beta``'s up to ``x``. + + This function is used to compute the weight and the Hodge numbers. + + .. SEEALSO:: + + :meth:`weight`, :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: [H.zigzag(x) for x in [0, 1/3, 1/2]] + [0, 1, 0] + sage: H = Hyp(cyclotomic=([5],[1,1,1,1])) + sage: [H.zigzag(x) for x in [0,1/6,1/4,1/2,3/4,5/6]] + [-4, -4, -3, -2, -1, 0] + + """ + alpha = self._alpha + beta = self._beta + return(sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x)) def weight(self): """ @@ -535,7 +561,7 @@ def weight(self): With rational inputs:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).weight() 0 sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).weight() @@ -570,9 +596,7 @@ def weight(self): """ alpha = self._alpha beta = self._beta - D = [sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if b <= x) - for x in alpha + beta] + D = [self.zigzag(x) for x in alpha + beta] return ZZ(max(D) - min(D) - 1) def degree(self): @@ -587,7 +611,7 @@ def degree(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).degree() 1 sage: Hyp(gamma_list=([2,2,4],[8])).degree() @@ -607,7 +631,7 @@ def defining_polynomials(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).defining_polynomials() (x^2 + 1, x^2 - 2*x + 1) """ @@ -621,7 +645,7 @@ def cyclotomic_data(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).cyclotomic_data() ([2], [1]) """ @@ -633,7 +657,7 @@ def alpha_beta(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).alpha_beta() ([1/2], [0]) """ @@ -651,7 +675,7 @@ def M_value(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) sage: H.M_value() 729/4096 @@ -674,7 +698,7 @@ def gamma_array(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).gamma_array() {1: -2, 2: 1} sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_array() @@ -690,7 +714,7 @@ def gamma_list(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])).gamma_list() [-1, -1, 2] @@ -712,7 +736,7 @@ def __eq__(self, other): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H1 = Hyp(alpha_beta=([1/2],[0])) sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) sage: H1 == H1 @@ -729,7 +753,7 @@ def __ne__(self, other): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H1 = Hyp(alpha_beta=([1/2],[0])) sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) sage: H1 != H1 @@ -745,11 +769,11 @@ def is_primitive(self): .. SEEALSO:: - :meth:`primitive_index`, :meth:`primitive_data`, + :meth:`primitive_index`, :meth:`primitive_data` EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([3],[4])).is_primitive() True sage: Hyp(gamma_list=[-2, 4, 6, -8]).is_primitive() @@ -765,11 +789,11 @@ def primitive_index(self): .. SEEALSO:: - :meth:`is_primitive`, :meth:`primitive_data`, + :meth:`is_primitive`, :meth:`primitive_data` EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([3],[4])).primitive_index() 1 sage: Hyp(gamma_list=[-2, 4, 6, -8]).primitive_index() @@ -788,7 +812,7 @@ def has_symmetry_at_one(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=[[1/2]*16,[0]*16]).has_symmetry_at_one() True @@ -809,7 +833,7 @@ def hodge_numbers(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([3],[6])) sage: H.hodge_numbers() [1, 1] @@ -856,7 +880,7 @@ def hodge_polynomial(self): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([6,10],[3,12])) sage: H.hodge_polynomial() (T^3 + 2*T^2 + 2*T + 1)/T^2 @@ -901,7 +925,7 @@ def padic_H_value(self, p, f, t, prec=20): From Benasque report, page 8:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] @@ -978,7 +1002,7 @@ def H_value(self, p, f, t, ring=None): With values in the UniversalCyclotomicField (slow):: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.H_value(3,i,-1) for i in range(1,3)] [0, -12] @@ -1056,7 +1080,7 @@ def euler_factor(self, t, p, degree=0): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: H.euler_factor(-1, 5) 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 @@ -1114,7 +1138,7 @@ def canonical_scheme(self, t=None): EXAMPLES:: - sage: from sage.modular.hypergeometric_motive import HypergeometricMotive as Hyp + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(cyclotomic=([3],[4])) sage: H.gamma_list() [-1, 2, 3, -4] From 4766e9bceb6bbd4f867f1225e16d5fa81f8334e9 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 7 Sep 2017 15:59:46 +0200 Subject: [PATCH 051/218] Implement cython() using cythonize() --- src/sage/misc/cython.py | 241 +++++++++++++++---------------------- src/sage/misc/cython_c.pyx | 2 +- 2 files changed, 101 insertions(+), 142 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 3cdfcfcfe4d..0790edf20f1 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -20,13 +20,14 @@ import os import sys -import platform - +import re +import shutil +import pkgconfig -from sage.env import SAGE_LOCAL, SAGE_SRC -from .misc import SPYX_TMP +from sage.env import (SAGE_LOCAL, SAGE_SRC, cython_aliases, + sage_include_directories) +from sage.misc.misc import SPYX_TMP, sage_makedirs from .temporary_file import tmp_filename -import pkgconfig # CBLAS can be one of multiple implementations @@ -254,8 +255,6 @@ def pyx_preparse(s): sage: module.evaluate_at_power_of_gen(x^3 + x - 7, 5) # long time x^15 + x^5 - 7 """ - from sage.env import sage_include_directories - lang, s = parse_keywords('clang', s) if lang: lang = lang[0].lower() # this allows both C++ and c++ @@ -296,7 +295,7 @@ def pyx_preparse(s): sequence_number = {} -def cython(filename, verbose=False, compile_message=False, +def cython(filename, verbose=0, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, create_local_so_file=False): r""" @@ -306,32 +305,31 @@ def cython(filename, verbose=False, compile_message=False, INPUT: - - ``filename`` - the name of the file to be compiled. Should end with + - ``filename`` -- the name of the file to be compiled. Should end with 'pyx'. - - ``verbose`` (bool, default False) - if True, print debugging - information. + - ``verbose`` (integer, default 0) -- level of verbosity. - - ``compile_message`` (bool, default False) - if True, print + - ``compile_message`` (bool, default False) -- if True, print ``'Compiling ...'`` to the standard error. - - ``use_cache`` (bool, default False) - if True, check the + - ``use_cache`` (bool, default False) -- if True, check the temporary build directory to see if there is already a corresponding .so file. If so, and if the .so file is newer than the Cython file, don't recompile, just reuse the .so file. - - ``create_local_c_file`` (bool, default False) - if True, save a + - ``create_local_c_file`` (bool, default False) -- if True, save a copy of the ``.c`` or ``.cpp`` file in the current directory. - - ``annotate`` (bool, default True) - if True, create an html file which + - ``annotate`` (bool, default True) -- if True, create an html file which annotates the conversion from .pyx to .c. By default this is only created in the temporary directory, but if ``create_local_c_file`` is also True, then save a copy of the .html file in the current directory. - - ``sage_namespace`` (bool, default True) - if True, import + - ``sage_namespace`` (bool, default True) -- if True, import ``sage.all``. - - ``create_local_so_file`` (bool, default False) - if True, save a + - ``create_local_so_file`` (bool, default False) -- if True, save a copy of the compiled .so file in the current directory. TESTS: @@ -342,12 +340,8 @@ def cython(filename, verbose=False, compile_message=False, work around while waiting for :trac:`22461` which will offer a better solution:: - sage: import pkgconfig - sage: singular_pc = pkgconfig.parse('Singular') sage: code = [ ....: "#clang C++", - ....: "#clib " + " ".join(singular_pc['libraries']), - ....: "#cargs " + pkgconfig.cflags('Singular'), ....: "from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular", ....: "from sage.libs.singular.polynomial cimport singular_polynomial_pow", ....: "def test(MPolynomial_libsingular p):", @@ -389,8 +383,7 @@ def cython(filename, verbose=False, compile_message=False, sage: cython("sig_malloc(0)") Traceback (most recent call last): ... - RuntimeError: Error converting ... to C: - ... + RuntimeError: Error converting ... to C NOTE: Sage no longer automatically includes the deprecated files "cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files. You can fix your code by adding "from cysignals.memory cimport sig_malloc". @@ -411,57 +404,37 @@ def cython(filename, verbose=False, compile_message=False, else: base = sanitize(os.path.abspath(filename)) - # This is the *temporary* directory where we build the pyx file. - # This is deleted when sage exits, which means pyx files must be + # This is the *temporary* directory where we store the pyx file. + # This is deleted when Sage exits, which means pyx files must be # rebuilt every time Sage is restarted at present. - build_dir = os.path.join(SPYX_TMP, base) + target_dir = os.path.join(SPYX_TMP, base) - if os.path.exists(build_dir): + # Build directory for Cython/distutils + build_dir = os.path.join(target_dir, "build") + + if os.path.exists(target_dir): # There is already a module here. Maybe we do not have to rebuild? # Find the name. if use_cache: from sage.misc.sageinspect import loadable_module_extension - prev_so = [F for F in os.listdir(build_dir) if F.endswith(loadable_module_extension())] + prev_so = [F for F in os.listdir(target_dir) if F.endswith(loadable_module_extension())] if len(prev_so) > 0: prev_so = prev_so[0] # should have length 1 because of deletes below - if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(build_dir, prev_so)): + if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(target_dir, prev_so)): # We do not have to rebuild. - return prev_so[:-len(loadable_module_extension())], build_dir - else: - os.makedirs(build_dir) - for F in os.listdir(build_dir): - G = '%s/%s'%(build_dir,F) - try: - if not os.path.isdir(G): + return prev_so[:-len(loadable_module_extension())], target_dir + + # Delete all ordinary files in target_dir + for F in os.listdir(target_dir): + G = os.path.join(target_dir, F) + if os.path.isdir(G): + continue + try: os.unlink(G) - except OSError: - pass - - # Get the absolute path to the directory that contains the pyx file. - # We will use this only to make some convenient symbolic links. - abs_base = os.path.split(os.path.abspath(filename))[0] - - # bad things happen if the current directory is SAGE_SRC - if not os.path.exists("%s/sage" % abs_base): - cmd = 'cd "%s"; ln -sf "%s"/* .'%(build_dir, abs_base) - os.system(cmd) - if os.path.exists("%s/setup.py" % build_dir): - os.unlink("%s/setup.py" % build_dir) - - if compile_message: - print("Compiling {}...".format(filename), file=sys.stderr) - - F = open(filename).read() - - F, libs, includes, language, additional_source_files, extra_args, libdirs = pyx_preparse(F) - - # add the working directory to the includes so custom headers etc. work - includes.append(os.path.split(os.path.splitext(filename)[0])[0]) - - if language == 'c++': - extension = "cpp" + except OSError: + pass else: - extension = "c" + sage_makedirs(target_dir) if create_local_so_file: name = base @@ -474,97 +447,83 @@ def cython(filename, verbose=False, compile_message=False, # increment the sequence number so will use a different one next time. sequence_number[base] += 1 - file_list = [] + if compile_message: + print("Compiling {}...".format(filename), file=sys.stderr) + + with open(filename) as f: + (preparsed, libs, includes, language, additional_source_files, + extra_args, libdirs) = pyx_preparse(f.read()) + + # New filename with preparsed code. + # NOTE: if we ever stop preparsing, we should still copy the + # original file to the target directory. + pyxfile = os.path.join(target_dir, name + ".pyx") + with open(pyxfile, 'w') as f: + f.write(preparsed) + + extra_sources = [] for fname in additional_source_files: fname = fname.replace("$SAGE_SRC", SAGE_SRC) fname = fname.replace("$SAGE_LOCAL", SAGE_LOCAL) - if fname.startswith(os.path.sep): - file_list.append("'"+fname+"'") - else: - file_list.append("'"+os.path.abspath(os.curdir)+"/"+fname+"'") - additional_source_files = ",".join(file_list) - - pyx = '%s/%s.pyx'%(build_dir, name) - open(pyx,'w').write(F) - setup=""" -# Build using 'python setup.py' -import distutils.sysconfig, os, sys -from distutils.core import setup, Extension - -from sage.env import SAGE_LOCAL - -extra_compile_args = %s - -ext_modules = [Extension('%s', sources=['%s.%s', %s], - libraries=%s, - library_dirs=[SAGE_LOCAL + '/lib/'] + %s, - extra_compile_args = extra_compile_args, - language = '%s' )] - -setup(ext_modules = ext_modules, - include_dirs = %s) - """%(extra_args, name, name, extension, additional_source_files, libs, libdirs, language, includes) - open('%s/setup.py'%build_dir,'w').write(setup) - cython_include = ' '.join(["-I '%s'"%x for x in includes if len(x.strip()) > 0 ]) - - options = ['-p'] - if annotate: - options.append('-a') - if sage_namespace: - options.append('--pre-import sage.all') - - cmd = "cd '{DIR}' && cython {OPT} {INC} {LANG} '{NAME}.pyx' 1>log 2>err ".format( - DIR=build_dir, - OPT=' '.join(options), - INC=cython_include, - LANG='--cplus' if language=='c++' else '', - NAME=name) - - if create_local_c_file: - target_c = '%s/_%s.%s'%(os.path.abspath(os.curdir), base, extension) - cmd += " && cp '%s.%s' '%s'"%(name, extension, target_c) - if annotate: - target_html = '%s/_%s.html'%(os.path.abspath(os.curdir), base) - cmd += " && cp '%s.html' '%s'"%(name, target_html) - - if verbose: - print(cmd) - if os.system(cmd): - log = open('%s/log'%build_dir).read() - err = open('%s/err'%build_dir).read() + extra_sources.append(fname) + + # Now do the actual build, directly calling Cython and distutils + from Cython.Build import cythonize + from Cython.Compiler.Errors import CompileError + import Cython.Compiler.Options + from distutils.dist import Distribution + from distutils.core import Extension + from distutils.log import set_verbosity + set_verbosity(verbose) + + Cython.Compiler.Options.annotate = annotate + Cython.Compiler.Options.embed_pos_in_docstring = True + Cython.Compiler.Options.pre_import = "sage.all" if sage_namespace else None + + ext = Extension(name, + sources=[pyxfile] + extra_sources, + libraries=libs, + library_dirs=[os.path.join(SAGE_LOCAL, "lib")] + libdirs, + extra_compile_args=extra_args, + language=language) + + try: + ext, = cythonize([ext], aliases=cython_aliases(), quiet=not verbose) + except CompileError: + msg = "Error converting {} to C".format(filename) + # Check for names in old_pxi_names for pxd, names in old_pxi_names.items(): for name in names: - if ("undeclared name not builtin: " + name) in err: - err += '\nNOTE: Sage no longer automatically includes the deprecated files\n' \ + if re.search(r"\b{}\b".format(name), preparsed): + msg += '\nNOTE: Sage no longer automatically includes the deprecated files\n' \ '"cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files.\n' \ 'You can fix your code by adding "from %s cimport %s".' % \ (pxd, name) - raise RuntimeError("Error converting {} to C:\n{}\n{}".format(filename, log, err)) + raise RuntimeError(msg) - cmd = 'cd %s && python setup.py build 1>log 2>err'%build_dir - if verbose: - print(cmd) - if os.system(cmd): - log = open('%s/log'%build_dir).read() - err = open('%s/err'%build_dir).read() - raise RuntimeError("Error compiling {}:\n{}\n{}".format(filename, log, err)) - - # Move from lib directory. - cmd = 'mv %s/build/lib.*/* %s'%(build_dir, build_dir) - if verbose: - print(cmd) - if os.system(cmd): - raise RuntimeError("Error copying extension module for {}".format(filename)) + if create_local_c_file: + shutil.copy(os.path.join(target_dir, ext.sources[0]), + os.curdir) + if annotate: + shutil.copy(os.path.join(target_dir, name + ".html"), + os.curdir) + + # This emulates running "setup.py build" with the correct options + dist = Distribution() + dist.ext_modules = [ext] + dist.include_dirs = includes + buildcmd = dist.get_command_obj("build") + buildcmd.build_base = build_dir + buildcmd.build_lib = target_dir + dist.run_command("build") if create_local_so_file: - # Copy from lib directory into local directory + # Copy module to current directory from sage.misc.sageinspect import loadable_module_extension - cmd = 'cp %s/%s%s %s'%(build_dir, name, loadable_module_extension(), os.path.abspath(os.curdir)) - if os.system(cmd): - raise RuntimeError("Error making local copy of shared object library for {}".format(filename)) - - return name, build_dir + shutil.copy(os.path.join(target_dir, name + loadable_module_extension()), + os.curdir) + return name, target_dir def subtract_from_line_numbers(s, n): diff --git a/src/sage/misc/cython_c.pyx b/src/sage/misc/cython_c.pyx index c2a9c4167bd..177a659a1a2 100644 --- a/src/sage/misc/cython_c.pyx +++ b/src/sage/misc/cython_c.pyx @@ -60,7 +60,7 @@ def cython_compile(code, Need to create a clever caching system so code only gets compiled once. """ - tmpfile = tmp_filename(ext=".spyx") + tmpfile = tmp_filename(ext=".pyx") open(tmpfile,'w').write(code) cython_import_all(tmpfile, get_globals(), verbose=verbose, compile_message=compile_message, From 60c038b4ae556a0bd9b426f29dd1156f0d8b3507 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 7 Sep 2017 19:03:47 +0000 Subject: [PATCH 052/218] Implement formula for sign of the functional equation --- src/sage/modular/hypergeometric_motive.py | 166 +++++++++++----------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index e6afe8ad7d1..6ffa18d9cc0 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -8,7 +8,7 @@ AUTHORS: -- Frédéric Chapoton +- Frederic Chapoton - Kiran S. Kedlaya EXAMPLES:: @@ -24,7 +24,7 @@ T^8 + T^5 + T^3 + 1 """ #***************************************************************************** -# Copyright (C) 2017 Frédéric Chapoton +# Copyright (C) 2017 Frederic Chapoton # Kiran S. Kedlaya # # Distributed under the terms of the GNU General Public License (GPL) @@ -37,7 +37,7 @@ from collections import defaultdict from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime -from sage.arith.misc import gauss_sum +from sage.arith.misc import gauss_sum, kronecker_symbol from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.functions.generalized import sgn from sage.functions.other import floor @@ -56,7 +56,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField -def characteristic_polynomial_from_traces(traces, d, q, i): +def characteristic_polynomial_from_traces(traces, d, q, i, sign): r""" Given a sequence of traces `t_1, \dots, t_k`, return the corresponding characteristic polynomial with Weil numbers as roots. @@ -70,14 +70,7 @@ def characteristic_polynomial_from_traces(traces, d, q, i): and should have the property that reciprocals of all roots have absolute value `q^{i/2}`. - There can be two possible signs for the leading coefficient. If - the degree ``d`` is even, one need at least ``floor(d/2)`` traces - and at least one more for odd ``d``. In case the correct sign for - the leading coefficient cannot be guessed from the given traces, - the output is a pair (f, dictionary). The number `f` is such that the - trace for `p^f` allows to fix the ambiguity. The dictionary maps - the two possible traces for `p^f` to the corresponding Euler - factors. + The sign specified here is the local root number times `(-1)^d`. INPUT: @@ -89,88 +82,62 @@ def characteristic_polynomial_from_traces(traces, d, q, i): - ``i`` -- integer, the weight in the motivic sense + - ``sign`` -- integer, the sign + OUTPUT: - a polynomial or a pair (integer, dictionary) + a polynomial EXAMPLES:: sage: from sage.modular.hypergeometric_motive import characteristic_polynomial_from_traces - sage: characteristic_polynomial_from_traces([1, 1], 1, 3, 0) - -T + 1 - sage: characteristic_polynomial_from_traces([1], 1, 3, 0) + sage: characteristic_polynomial_from_traces([1, 1], 1, 3, 0, -1) -T + 1 - - sage: characteristic_polynomial_from_traces([25,625], 1, 5, 4) - -25*T + 1 - sage: characteristic_polynomial_from_traces([25], 1, 5, 4) + sage: characteristic_polynomial_from_traces([25], 1, 5, 4, -1) -25*T + 1 - sage: characteristic_polynomial_from_traces([3,-1,-18,-49], 2, 5, 1) - 5*T^2 - 3*T + 1 - sage: characteristic_polynomial_from_traces([3], 2, 5, 1) + sage: characteristic_polynomial_from_traces([3], 2, 5, 1, 1) 5*T^2 - 3*T + 1 - - sage: characteristic_polynomial_from_traces([-4,276], 4, 5, 3) - 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 - sage: characteristic_polynomial_from_traces([4,-276], 4, 5, 3) - 15625*T^4 - 500*T^3 + 146*T^2 - 4*T + 1 - - sage: characteristic_polynomial_from_traces([1,-13,-20,71], 2, 7, 1) - 7*T^2 - T + 1 - sage: characteristic_polynomial_from_traces([1], 2, 7, 1) + sage: characteristic_polynomial_from_traces([1], 2, 7, 1, 1) 7*T^2 - T + 1 - sage: characteristic_polynomial_from_traces([36,7620], 4, 17, 3) + sage: characteristic_polynomial_from_traces([20], 3, 29, 2, 1) + 24389*T^3 - 580*T^2 - 20*T + 1 + sage: characteristic_polynomial_from_traces([12], 3, 13, 2, -1) + -2197*T^3 + 156*T^2 - 12*T + 1 + + sage: characteristic_polynomial_from_traces([36,7620], 4, 17, 3, 1) 24137569*T^4 - 176868*T^3 - 3162*T^2 - 36*T + 1 + sage: characteristic_polynomial_from_traces([-4,276], 4, 5, 3, 1) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + sage: characteristic_polynomial_from_traces([4,-276], 4, 5, 3, 1) + 15625*T^4 - 500*T^3 + 146*T^2 - 4*T + 1 + sage: characteristic_polynomial_from_traces([22, 484], 4, 31, 2, -1) + -923521*T^4 + 21142*T^3 - 22*T + 1 TESTS:: - sage: characteristic_polynomial_from_traces([0],2,17,1) - (2, {-34: 17*T^2 + 1, 34: -17*T^2 + 1}) - - sage: characteristic_polynomial_from_traces([-36], 4, 17, 3) + sage: characteristic_polynomial_from_traces([-36], 4, 17, 3, 1) Traceback (most recent call last): ... ValueError: not enough traces were given """ - if len(traces) < d // 2 + d % 2: + if len(traces) < d // 2: raise ValueError('not enough traces were given') t = PowerSeriesRing(QQ, 't').gen() ring = PolynomialRing(ZZ, 'T') series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) - N = min(len(traces), d) # never need more than d traces - series = series.O(N + 1).exp() + series = series.O(d//2 + 1).exp() coeffs = list(series) + coeffs += [0,] * max(0,d//2+1-len(coeffs)) - rev_coeffs = {d - k: coeffs[k] * q**(-k * i + d * i // 2) - for k in range(len(coeffs)) if k <= d} - intersection = [k for k in range(len(coeffs)) - if k in rev_coeffs and coeffs[k]] - - def poly(sign): - data = [0 for _ in range(d + 1)] - for k in range(len(coeffs)): - data[k] = coeffs[k] - for k in rev_coeffs: - data[k] = sign * rev_coeffs[k] - return ring(data) - - if intersection: - idx = intersection[0] - sign = 1 if coeffs[idx] == rev_coeffs[idx] else -1 - return poly(sign) - else: - p1 = poly(1) - p2 = poly(-1) - s1 = (p1(t).O(t ** (d + 1))).log() - s2 = (p2(t).O(t ** (d + 1))).log() - index = (s1 - s2).valuation() - return (index, {-s1[index] * index: p1, -s2[index] * index: p2}) - # IDEA: also return the first index of trace - # that would allow sign recognition - # this means finding the first coefficient that differs in s1 and s2 + data = [0 for _ in range(d + 1)] + for k in range(d//2+1): + data[k] = coeffs[k] + for k in range(d//2+1, d+1): + data[k] = sign*coeffs[d-k]*q**(i*(k-d/2)) + return ring(data) def possible_hypergeometric_data(d, weight=None): @@ -454,6 +421,17 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): self._alpha = alpha self._beta = beta self._deg = deg + if self.weight()%2 == 1: + self._sign_param = 1 + else: + gamma = self.gamma_array() + + if deg%2 == 1: + self._sign_param = prod(cyclotomic_polynomial(v).disc() + for v in cyclo_down) + else: + self._sign_param = prod(cyclotomic_polynomial(v).disc() + for v in cyclo_up) def __repr__(self): """ @@ -1025,6 +1003,7 @@ def H_value(self, p, f, t, ring=None): - https://arxiv.org/pdf/1505.02900.pdf, Theorem 1.3 - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + """ if ring is None: ring = UniversalCyclotomicField() @@ -1078,6 +1057,9 @@ def euler_factor(self, t, p, degree=0): See http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf for explicit examples of Euler factors. + For odd weight, the sign of the functional equation is +1. For even + weight, the sign is computed by a recipe found in 11.1 of Watkins. + EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp @@ -1085,16 +1067,9 @@ def euler_factor(self, t, p, degree=0): sage: H.euler_factor(-1, 5) 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 - sage: [Hyp(cyclotomic=([6,2],[1,1,1])).euler_factor(1/4,p) - ....: for p in [5,7,11,13,17,19]] - [125*T^3 + 20*T^2 + 4*T + 1, - 343*T^3 - 42*T^2 - 6*T + 1, - -1331*T^3 - 22*T^2 + 2*T + 1, - -2197*T^3 - 156*T^2 + 12*T + 1, - 4913*T^3 + 323*T^2 + 19*T + 1, - 6859*T^3 - 57*T^2 - 3*T + 1] - sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: H.weight(), H.degree() + (1, 2) sage: t = 189/125 sage: [H.euler_factor(1/t,p) for p in [11,13,17,19,23,29]] [11*T^2 + 4*T + 1, @@ -1104,9 +1079,35 @@ def euler_factor(self, t, p, degree=0): 23*T^2 + 8*T + 1, 29*T^2 + 2*T + 1] + sage: H = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H.weight(), H.degree() + (2, 3) + sage: [H.euler_factor(1/4,p) for p in [5,7,11,13,17,19]] + [125*T^3 + 20*T^2 + 4*T + 1, + 343*T^3 - 42*T^2 - 6*T + 1, + -1331*T^3 - 22*T^2 + 2*T + 1, + -2197*T^3 - 156*T^2 + 12*T + 1, + 4913*T^3 + 323*T^2 + 19*T + 1, + 6859*T^3 - 57*T^2 - 3*T + 1] + + sage: H = Hyp(alpha_beta=([1/12,5/12,7/12,11/12],[0,1/2,1/2,1/2])) + sage: H.weight(), H.degree() + (2, 4) + sage: t = -5 + sage: [H.euler_factor(1/t,p) for p in [11,13,17,19,23,29]] + [-14641*T^4 - 1210*T^3 + 10*T + 1, + -28561*T^4 - 2704*T^3 + 16*T + 1, + -83521*T^4 - 4046*T^3 + 14*T + 1, + 130321*T^4 + 14440*T^3 + 969*T^2 + 40*T + 1, + 279841*T^4 - 25392*T^3 + 1242*T^2 - 48*T + 1, + 707281*T^4 - 7569*T^3 + 696*T^2 - 9*T + 1] + + REFERENCE: - https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + - http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf + """ if t not in QQ or t in [0, 1]: raise ValueError('wrong t') @@ -1124,13 +1125,14 @@ def euler_factor(self, t, p, degree=0): w = self.weight() - # One has to handle the cases of sign ambiguity - resu = characteristic_polynomial_from_traces(traces, d, p, w) - if isinstance(resu, tuple): - f, dico = resu - return dico[self.padic_H_value(p, f, t)] + if w%2 == 1: # sign is always +1 for odd weight + sign = 1 + elif d%2 == 1: + sign = -kronecker_symbol((1-t)*self._sign_param, p) else: - return resu + sign = kronecker_symbol(t*(t-1)*self._sign_param, p) + + return characteristic_polynomial_from_traces(traces, d, p, w, sign) def canonical_scheme(self, t=None): """ From e18e633f49506a264e427025775423891d85fcbd Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Fri, 8 Sep 2017 14:29:36 +0000 Subject: [PATCH 053/218] Correct answers when 0 is in alpha --- src/sage/modular/hypergeometric_motive.py | 54 +++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 6ffa18d9cc0..b2e694e7b50 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -191,7 +191,7 @@ def cyclotomic_to_alpha(cyclo): The output is the list of arguments of the roots of the given product of cyclotomic polynomials. - + This is the inverse of :func:`alpha_to_cyclotomic`. EXAMPLES:: @@ -505,11 +505,12 @@ def primitive_data(self): d = gcd(g) return HypergeometricData(gamma_list=[x / d for x in g]) - def zigzag(self, x): + def zigzag(self, x, flip_beta=False): """ Count ``alpha``'s up to ``x`` minus ``beta``'s up to ``x``. This function is used to compute the weight and the Hodge numbers. + With `flip_beta` set to True, replace each `b` in `\beta` with `1-b`. .. SEEALSO:: @@ -528,8 +529,12 @@ def zigzag(self, x): """ alpha = self._alpha beta = self._beta - return(sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if b <= x)) + if flip_beta: + return(sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if 1-b <= x)) + else: + return(sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x)) def weight(self): """ @@ -869,15 +874,11 @@ def hodge_polynomial(self): alpha = self._alpha beta = self._beta - def D(x): - return (sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if 1 - b <= x)) - def z(x): return alpha.count(x) T = polygen(ZZ, 'T') - return sum(T ** (D(a) - z(a)) * (T**z(a) - 1) // (T - 1) + return sum(T ** (self.zigzag(a,flip_beta=True) - z(a)) * (T**z(a) - 1) // (T - 1) for a in set(alpha)) def padic_H_value(self, p, f, t, prec=20): @@ -925,14 +926,19 @@ def padic_H_value(self, p, f, t, prec=20): - http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf """ + alpha = self._alpha beta = self._beta + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.padic_H_value(p,f,1/t,prec)) t = QQ(t) gamma = self.gamma_array() q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} M = self.M_value() - D = (self.weight() + 1 - m[0]) // 2 + D = -min(self.zigzag(x,flip_beta=True) for x in alpha+beta) +# D = (self.weight() + 1 - m[0]) // 2 gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] @@ -1005,15 +1011,20 @@ def H_value(self, p, f, t, ring=None): - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf """ + alpha = self._alpha + beta = self._beta + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.H_value(p,f,1/t,ring)) if ring is None: ring = UniversalCyclotomicField() - beta = self._beta t = QQ(t) gamma = self.gamma_array() q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} - D = (self.weight() + 1 - m[0]) // 2 + D = -min(self.zigzag(x,flip_beta=True) for x in alpha+beta) +# D = (self.weight() + 1 - m[0]) // 2 M = self.M_value() Fq = GF(q) @@ -1102,6 +1113,17 @@ def euler_factor(self, t, p, degree=0): 279841*T^4 - 25392*T^3 + 1242*T^2 - 48*T + 1, 707281*T^4 - 7569*T^3 + 696*T^2 - 9*T + 1] + TESTS:: + + sage: H1 = Hyp(alpha_beta=([1,1,1],[1/2,1/2,1/2])) + sage: H2 = H1.swap_alpha_beta() + sage: H1.euler_factor(-1, 3) + 27*T^3 + 3*T^2 + T + 1 + sage: H2.euler_factor(-1, 3) + 27*T^3 + 3*T^2 + T + 1 + sage: H = Hyp(alpha_beta=([0,0,0,1/3,2/3],[1/2,1/5,2/5,3/5,4/5])) + sage: H.euler_factor(-1,7) + -16807*T^5 + 1372*T^4 + 511*T^3 - 73*T^2 - 4*T + 1 REFERENCE: @@ -1109,6 +1131,12 @@ def euler_factor(self, t, p, degree=0): - http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf """ + alpha = self._alpha + beta = self._beta + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.euler_factor(1/t,p,degree)) + if t not in QQ or t in [0, 1]: raise ValueError('wrong t') if not is_prime(p): @@ -1120,7 +1148,7 @@ def euler_factor(self, t, p, degree=0): # now p is good if degree == 0: d = self.degree() - bound = d // 2 + d % 2 + bound = d // 2 traces = [self.padic_H_value(p, i + 1, t) for i in range(bound)] w = self.weight() From baf8ae905722d35a513a971e757b28c75e2b26da Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Fri, 8 Sep 2017 14:34:20 +0000 Subject: [PATCH 054/218] Modify one doctest to distinguish t from 1/t --- src/sage/modular/hypergeometric_motive.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index b2e694e7b50..e7892aa73c1 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1122,8 +1122,8 @@ def euler_factor(self, t, p, degree=0): sage: H2.euler_factor(-1, 3) 27*T^3 + 3*T^2 + T + 1 sage: H = Hyp(alpha_beta=([0,0,0,1/3,2/3],[1/2,1/5,2/5,3/5,4/5])) - sage: H.euler_factor(-1,7) - -16807*T^5 + 1372*T^4 + 511*T^3 - 73*T^2 - 4*T + 1 + sage: H.euler_factor(5,7) + 16807*T^5 - 686*T^4 - 105*T^3 - 15*T^2 - 2*T + 1 REFERENCE: From 9dde54a6b42f859c35cbd9945c1da426cef5146a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Sep 2017 17:11:10 +0200 Subject: [PATCH 055/218] trac 23671 pep8 cleanup --- src/sage/modular/hypergeometric_motive.py | 48 +++++++++++------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index e7892aa73c1..186f85c1d59 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -56,6 +56,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + def characteristic_polynomial_from_traces(traces, d, q, i, sign): r""" Given a sequence of traces `t_1, \dots, t_k`, return the @@ -128,15 +129,15 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign): ring = PolynomialRing(ZZ, 'T') series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) - series = series.O(d//2 + 1).exp() + series = series.O(d // 2 + 1).exp() coeffs = list(series) - coeffs += [0,] * max(0,d//2+1-len(coeffs)) + coeffs += [0] * max(0, d // 2 + 1 - len(coeffs)) data = [0 for _ in range(d + 1)] - for k in range(d//2+1): + for k in range(d // 2 + 1): data[k] = coeffs[k] - for k in range(d//2+1, d+1): - data[k] = sign*coeffs[d-k]*q**(i*(k-d/2)) + for k in range(d // 2 + 1, d + 1): + data[k] = sign * coeffs[d - k] * q**(i * (k - d / 2)) return ring(data) @@ -191,7 +192,7 @@ def cyclotomic_to_alpha(cyclo): The output is the list of arguments of the roots of the given product of cyclotomic polynomials. - + This is the inverse of :func:`alpha_to_cyclotomic`. EXAMPLES:: @@ -421,12 +422,10 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): self._alpha = alpha self._beta = beta self._deg = deg - if self.weight()%2 == 1: + if self.weight() % 2: self._sign_param = 1 else: - gamma = self.gamma_array() - - if deg%2 == 1: + if deg % 2: self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_down) else: @@ -531,10 +530,10 @@ def zigzag(self, x, flip_beta=False): beta = self._beta if flip_beta: return(sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if 1-b <= x)) + sum(1 for b in beta if 1 - b <= x)) else: return(sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if b <= x)) + sum(1 for b in beta if b <= x)) def weight(self): """ @@ -872,13 +871,13 @@ def hodge_polynomial(self): (T^5 + 3*T^4 + 3*T^3 + 3*T^2 + 3*T + 1)/T^2 """ alpha = self._alpha - beta = self._beta def z(x): return alpha.count(x) T = polygen(ZZ, 'T') - return sum(T ** (self.zigzag(a,flip_beta=True) - z(a)) * (T**z(a) - 1) // (T - 1) + return sum(T ** (self.zigzag(a, flip_beta=True) - z(a)) * + (T**z(a) - 1) // (T - 1) for a in set(alpha)) def padic_H_value(self, p, f, t, prec=20): @@ -930,14 +929,14 @@ def padic_H_value(self, p, f, t, prec=20): beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() - return(H.padic_H_value(p,f,1/t,prec)) + return(H.padic_H_value(p, f, ~t, prec)) t = QQ(t) gamma = self.gamma_array() q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} M = self.M_value() - D = -min(self.zigzag(x,flip_beta=True) for x in alpha+beta) + D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # D = (self.weight() + 1 - m[0]) // 2 gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] @@ -946,7 +945,7 @@ def padic_H_value(self, p, f, t, prec=20): teich = p_ring.teichmuller(M / t) sigma = sum(q**(D + m[0] - m[r]) * (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv - for v, gv in gamma.items())//(p-1)) * + for v, gv in gamma.items()) // (p - 1)) * prod(gauss_table[(v * r) % (q - 1)][1] ** gv for v, gv in gamma.items()) * teich ** r @@ -1015,7 +1014,7 @@ def H_value(self, p, f, t, ring=None): beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() - return(H.H_value(p,f,1/t,ring)) + return(H.H_value(p, f, ~t, ring)) if ring is None: ring = UniversalCyclotomicField() t = QQ(t) @@ -1023,7 +1022,7 @@ def H_value(self, p, f, t, ring=None): q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} - D = -min(self.zigzag(x,flip_beta=True) for x in alpha+beta) + D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # D = (self.weight() + 1 - m[0]) // 2 M = self.M_value() @@ -1132,10 +1131,9 @@ def euler_factor(self, t, p, degree=0): """ alpha = self._alpha - beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() - return(H.euler_factor(1/t,p,degree)) + return(H.euler_factor(~t, p, degree)) if t not in QQ or t in [0, 1]: raise ValueError('wrong t') @@ -1153,12 +1151,12 @@ def euler_factor(self, t, p, degree=0): w = self.weight() - if w%2 == 1: # sign is always +1 for odd weight + if w % 2: # sign is always +1 for odd weight sign = 1 - elif d%2 == 1: - sign = -kronecker_symbol((1-t)*self._sign_param, p) + elif d % 2: + sign = -kronecker_symbol((1 - t) * self._sign_param, p) else: - sign = kronecker_symbol(t*(t-1)*self._sign_param, p) + sign = kronecker_symbol(t * (t - 1) * self._sign_param, p) return characteristic_polynomial_from_traces(traces, d, p, w, sign) From fd29350ccad453ef3ecbdb374add86ddd67de5dd Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Tue, 12 Sep 2017 19:32:36 +0000 Subject: [PATCH 056/218] Some minor edits --- src/sage/modular/hypergeometric_motive.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 186f85c1d59..8d726a11743 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -6,6 +6,9 @@ with `1/t` to match the classical literature on hypergeometric series. (E.g., see Beukers-Heckman, Monodromy for the hypergeometric function nF_{n-1}.) +The computation of Euler factors is currently only supported for primes `p` +of good reduction. That is, it is required that `v_p(t) = v_p(t-1) = 0`. + AUTHORS: - Frederic Chapoton @@ -227,7 +230,8 @@ def alpha_to_cyclotomic(alpha): The input represents arguments of some roots of unity. The output represent a product of cyclotomic polynomials with exactly - the given roots. + the given roots. Note that the multiplicity of `r/s` in the list + must be independent of `r`; otherwise, a ValueError will be raised. This is the inverse of :func:`cyclotomic_to_alpha`. @@ -252,7 +256,10 @@ def alpha_to_cyclotomic(alpha): d = q.denominator() for k in range(1, d): if gcd(k, d) == 1 and QQ((k, d)) != q: - Alpha.remove(QQ((k, d))) + try: + Alpha.remove(QQ((k, d))) + except ValueError: + raise ValueError, "multiplicities not balanced" cyclo.append(d) return sorted(cyclo) @@ -352,7 +359,7 @@ def gamma_list_to_cyclotomic(galist): return (sorted(d for d in resu for k in range(resu[d])), sorted(d for d in resu for k in range(-resu[d]))) - +J class HypergeometricData(object): def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): @@ -388,6 +395,8 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): sage: Hyp(gamma_list=([5],[1,1,1,1,1])) Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) + Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] """ if gamma_list is not None: if isinstance(gamma_list[0], (list, tuple)): @@ -397,7 +406,7 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): if cyclotomic is not None: cyclo_up, cyclo_down = cyclotomic if any(x in cyclo_up for x in cyclo_down): - raise ValueError('must be prime') + raise ValueError('overlapping parameters not allowed') deg = sum(euler_phi(x) for x in cyclo_down) up_deg = sum(euler_phi(x) for x in cyclo_up) if up_deg != deg: @@ -647,7 +656,7 @@ def alpha_beta(self): def M_value(self): """ - Return the `M` coefficient that appears in the equations. + Return the `M` coefficient that appears in the trace formula. OUTPUT: @@ -955,7 +964,8 @@ def padic_H_value(self, p, f, t, prec=20): def H_value(self, p, f, t, ring=None): """ - Return the trace of the Frobenius. + Return the trace of the Frobenius, computed in terms of Gauss sums + using the hypergeometric trace formula. INPUT: From 28e95f4586177ff08cc06e58dd69c4d5ce17c4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Sep 2017 14:30:32 +0200 Subject: [PATCH 057/218] trac 23671 clean-up of references --- src/sage/modular/hypergeometric_motive.py | 55 ++++++++++++++++------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 186f85c1d59..df91a5373e1 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1,14 +1,15 @@ +# -*- coding: utf-8 -*- """ Hypergeometric motives This is largely a port of the corresponding package in Magma. One important conventional difference: the motivic parameter `t` has been replaced with `1/t` to match the classical literature on hypergeometric series. -(E.g., see Beukers-Heckman, Monodromy for the hypergeometric function nF_{n-1}.) +(E.g., see [BeukersHeckman]_) AUTHORS: -- Frederic Chapoton +- Frédéric Chapoton - Kiran S. Kedlaya EXAMPLES:: @@ -22,6 +23,33 @@ True sage: H.euler_factor(2, 7) T^8 + T^5 + T^3 + 1 + +REFERENCES: + +.. [BeukersHeckman] \F. Beukers and \G. Heckman, + *Monodromy for the hypergeometric function `{}_n F_{n-1}`*, + Invent. Math. 95 (1989) + +.. [Benasque2009] Fernando Rodriguez Villegas, *The L-function of the quintic*, + http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + +.. [MagmaHGM] *Hypergeometric motives* in Magma, + http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + +.. [Roberts2017] David P. Roberts, *Hypergeometric motives and an unusual + application of the Guinand-Weil-Mestre explicit formula*, + https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + +.. [Roberts2015] David P. Roberts, *Hypergeometric Motives I*, https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + +.. [BeCoMe] Frits Beukers, Henri Cohen, Anton Mellit, + *Finite hypergeometric functions*, + https://arxiv.org/pdf/1505.02900.pdf + +.. [Watkins] Mark Watkins, + *Hypergeometric motives over Q and their L-functions*, + http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf + """ #***************************************************************************** # Copyright (C) 2017 Frederic Chapoton @@ -798,9 +826,9 @@ def has_symmetry_at_one(self): sage: Hyp(alpha_beta=[[1/2]*16,[0]*16]).has_symmetry_at_one() True - REFERENCE: + REFERENCES: - - https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + - [Roberts2017]_ """ _, beta_twist = self.twist().alpha_beta() return self.degree() % 2 == 0 and self._alpha == beta_twist @@ -901,7 +929,7 @@ def padic_H_value(self, p, f, t, prec=20): EXAMPLES: - From Benasque report, page 8:: + From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) @@ -921,9 +949,9 @@ def padic_H_value(self, p, f, t, prec=20): sage: H.padic_H_value(13,1,1/t) 0 - REFERENCE: + REFERENCES: - - http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta @@ -1005,10 +1033,8 @@ def H_value(self, p, f, t, ring=None): REFERENCES: - - https://arxiv.org/pdf/1505.02900.pdf, Theorem 1.3 - - - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf - + - [BeCoMe]_ (Theorem 1.3) + - [Benasque2009]_ """ alpha = self._alpha beta = self._beta @@ -1124,11 +1150,10 @@ def euler_factor(self, t, p, degree=0): sage: H.euler_factor(5,7) 16807*T^5 - 686*T^4 - 105*T^3 - 15*T^2 - 2*T + 1 - REFERENCE: - - - https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf - - http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf + REFERENCES: + - [Roberts2015]_ + - [Watkins]_ """ alpha = self._alpha if 0 in alpha: From df64dbef1f40c631e6b7a75a481708c0e14d0589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Sep 2017 14:33:48 +0200 Subject: [PATCH 058/218] trac 23671 more care for references --- src/sage/modular/hypergeometric_motive.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index df91a5373e1..9c1c6ed4f0a 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1090,11 +1090,10 @@ def euler_factor(self, t, p, degree=0): a polynomial - See http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf - for explicit examples of Euler factors. + See [Benasque2009]_ for explicit examples of Euler factors. For odd weight, the sign of the functional equation is +1. For even - weight, the sign is computed by a recipe found in 11.1 of Watkins. + weight, the sign is computed by a recipe found in 11.1 of [Watkins]_. EXAMPLES:: From 656112f2223b08cf80f3db77c83c3cfbf1a30294 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 13 Sep 2017 16:34:52 +0000 Subject: [PATCH 059/218] Correct description of sign --- src/sage/modular/hypergeometric_motive.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 3a6b2ce30ed..56276d2f444 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -102,8 +102,6 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign): and should have the property that reciprocals of all roots have absolute value `q^{i/2}`. - The sign specified here is the local root number times `(-1)^d`. - INPUT: - ``traces`` -- a list of integers `t_1, \dots, t_k` From 4179f4bf706a2a86bb717d20120d77c52359c466 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 14 Sep 2017 20:32:55 +0000 Subject: [PATCH 060/218] More minor edits --- src/sage/modular/hypergeometric_motive.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 56276d2f444..5e29ab9b509 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -39,6 +39,10 @@ .. [MagmaHGM] *Hypergeometric motives* in Magma, http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf +.. [Fedorov2015] Roman Fedorov, *Variations of Hodge structures for hypergeometric + differential operators and parabolic Higgs bundles*, + https://arxiv.org/pdf/1505.01704 + .. [Roberts2017] David P. Roberts, *Hypergeometric motives and an unusual application of the Guinand-Weil-Mestre explicit formula*, https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf @@ -55,7 +59,7 @@ """ #***************************************************************************** -# Copyright (C) 2017 Frederic Chapoton +# Copyright (C) 2017 Frédéric Chapoton # Kiran S. Kedlaya # # Distributed under the terms of the GNU General Public License (GPL) @@ -874,6 +878,10 @@ def hodge_numbers(self): sage: H = Hyp(gamma_list=[-3]*4 + [1]*12) sage: H.hodge_numbers() [1, 1, 1, 1, 1, 1, 1, 1] + + REFERENCES: + + - [Fedorov2015]_ """ alpha = [(x, 'a') for x in self._alpha] beta = [(x, 'b') for x in self._beta] From cc53131b6ff960faee21aafdfe35175facf2ce10 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 14 Sep 2017 20:35:29 +0000 Subject: [PATCH 061/218] Typo fix --- src/sage/modular/hypergeometric_motive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 5e29ab9b509..08958c36be5 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -389,7 +389,7 @@ def gamma_list_to_cyclotomic(galist): return (sorted(d for d in resu for k in range(resu[d])), sorted(d for d in resu for k in range(-resu[d]))) -J + class HypergeometricData(object): def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): From c859cf2e15dd2c3a1d2840462f352b11e1c3dbea Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 14 Sep 2017 23:32:15 +0200 Subject: [PATCH 062/218] speedup left_key_tableau, right_key_tableau and is_key_tableau --- src/sage/combinat/tableau.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 377ad9e2fb5..dbbbd56b72c 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1084,18 +1084,18 @@ def to_sign_matrix(self, max_entry = None): r""" Return the sign matrix of ``self``. - A sign matrix is an `m \times n` matrix of 0's, 1's and -1's such that the - partial sums of each column is either 0 or 1 and the partial sums of + A sign matrix is an `m \times n` matrix of 0's, 1's and -1's such that the + partial sums of each column is either 0 or 1 and the partial sums of each row is non-negative. [Aval2008]_ - - INPUT: - - ``max_entry`` -- A non-negative integer, the maximum allowable number in + INPUT: + + - ``max_entry`` -- A non-negative integer, the maximum allowable number in the tableau. Defaults to the largest entry in the tableau if not specified. - EXAMPLES:: - + EXAMPLES:: + sage: t = SemistandardTableau([[1,1,1,2,4],[3,3,4],[4,5],[6,6]]) sage: t.to_sign_matrix(6) [ 0 0 0 1 0 0] @@ -1125,7 +1125,7 @@ def to_sign_matrix(self, max_entry = None): .. [Aval2008] Jean-Christope Aval. *Keys and Alternating Sign Matrices*, - Seminaire Lotharingien de Combinatoire 59 (2008) B59f + Seminaire Lotharingien de Combinatoire 59 (2008) B59f :arxiv:`0711.2150` """ from sage.rings.all import ZZ @@ -1133,7 +1133,7 @@ def to_sign_matrix(self, max_entry = None): PI = PositiveIntegers() for row in self: if any(c not in PI for c in row): - raise ValueError("the entries must be non-negative integers") + raise ValueError("the entries must be non-negative integers") from sage.matrix.matrix_space import MatrixSpace if max_entry is None: max_entry=max([max(c) for c in self]) @@ -3508,8 +3508,12 @@ def is_key_tableau(self): sage: t.is_key_tableau() False """ - itr = enumerate(self.conjugate()[1:],1) - return all(x in self.conjugate()[i-1] for i, col in itr for x in col) + T_conj = self.conjugate() + for i in range(1, len(T_conj)): + if not all(x in T_conj[i-1] for x in T_conj[i]): + return False + return True + def right_key_tableau(self): """ @@ -3555,9 +3559,6 @@ def right_key_tableau(self): sage: t.right_key_tableau() == t True """ - if self.is_key_tableau(): - return self - cols_list = self.conjugate() key = [[] for row in cols_list] @@ -3619,9 +3620,6 @@ def left_key_tableau(self): sage: t.left_key_tableau() == t True """ - if self.is_key_tableau(): - return self - cols_list = self.conjugate() key = [[] for row in cols_list] key[0] = list(cols_list[0]) @@ -3903,7 +3901,7 @@ def degree(self, e, multicharge=(0,)): deg = self.shape()._initial_degree(e,multicharge) res = self.shape().initial_tableau().residue_sequence(e, multicharge) for r in self.reduced_row_word(): - if res[r] == res[r+1]: + if res[r] == res[r+1]: deg -= 2 elif res[r] == res[r+1] + 1 or res[r] == res[r+1] - 1: deg += (e == 2 and 2 or 1) @@ -3993,7 +3991,7 @@ def first_row_descent(self): def first_column_descent(self): r""" - Return the first cell where ``self`` is not column standard. + Return the first cell where ``self`` is not column standard. Cells are ordered left to right along the rows and then top to bottom. That is, the cell `(r, c)` with `r` and `c` minimal such that From f62bf2772454a0af69e5ed2723070c5936ecfdc8 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 15 Sep 2017 09:29:41 +0200 Subject: [PATCH 063/218] 23865: disable doctest in omega --- src/sage/rings/polynomial/omega.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 733abef14c6..1bd7491692e 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -550,7 +550,7 @@ def Omega_ge(a, exponents): TESTS:: - sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # long time + sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # untested (too long, 1 min) 27837 :: From b7127ce548910ff52d71867a817ab9485ca5636b Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 14 Sep 2017 14:49:09 +0200 Subject: [PATCH 064/218] Implement conversion C++ <-> str --- src/sage/ext/ccobject.h | 56 ++++++++++++------- src/sage/ext/cplusplus.pxd | 16 ++++++ src/sage/libs/ntl/GF2.pxd | 3 - src/sage/libs/ntl/GF2E.pxd | 3 - src/sage/libs/ntl/GF2EX.pxd | 3 - src/sage/libs/ntl/GF2X.pxd | 4 -- src/sage/libs/ntl/ZZ.pxd | 3 - src/sage/libs/ntl/ZZX.pxd | 3 +- src/sage/libs/ntl/ZZ_p.pxd | 3 - src/sage/libs/ntl/ZZ_pE.pxd | 3 - src/sage/libs/ntl/ZZ_pEX.pxd | 4 -- src/sage/libs/ntl/ZZ_pX.pxd | 5 -- src/sage/libs/ntl/lzz_pX.pxd | 2 - src/sage/libs/ntl/mat_GF2.pxd | 3 - src/sage/libs/ntl/mat_GF2E.pxd | 3 - src/sage/libs/ntl/mat_ZZ.pxd | 2 - src/sage/libs/ntl/ntl_GF2.pyx | 8 +-- src/sage/libs/ntl/ntl_GF2E.pyx | 4 +- src/sage/libs/ntl/ntl_GF2EX.pyx | 8 +-- src/sage/libs/ntl/ntl_GF2X.pyx | 11 ++-- src/sage/libs/ntl/ntl_GF2X_linkage.pxi | 1 - src/sage/libs/ntl/ntl_ZZ.pyx | 7 +-- src/sage/libs/ntl/ntl_ZZX.pyx | 4 +- src/sage/libs/ntl/ntl_ZZ_p.pyx | 8 +-- src/sage/libs/ntl/ntl_ZZ_pE.pyx | 9 +-- src/sage/libs/ntl/ntl_ZZ_pEX.pyx | 4 +- src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi | 1 - src/sage/libs/ntl/ntl_ZZ_pX.pyx | 11 +--- src/sage/libs/ntl/ntl_mat_GF2.pyx | 3 +- src/sage/libs/ntl/ntl_mat_GF2E.pyx | 3 +- src/sage/libs/ntl/ntl_mat_ZZ.pyx | 3 +- src/sage/libs/ntl/vec_GF2.pxd | 4 -- src/sage/libs/ntl/vec_GF2E.pxd | 4 -- src/sage/libs/polybori/decl.pxd | 28 ++++------ src/sage/libs/polybori/pb_wrap.h | 6 -- src/sage/libs/pynac/pynac.pxd | 5 -- .../rings/finite_rings/element_ntl_gf2e.pyx | 7 ++- src/sage/rings/polynomial/pbori.pyx | 9 +-- .../polynomial_integer_dense_ntl.pyx | 5 +- .../rings/polynomial/polynomial_zz_pex.pyx | 3 - src/sage/symbolic/expression.pyx | 8 +-- src/sage/symbolic/ring.pyx | 4 +- 42 files changed, 118 insertions(+), 166 deletions(-) create mode 100644 src/sage/ext/cplusplus.pxd diff --git a/src/sage/ext/ccobject.h b/src/sage/ext/ccobject.h index 7d06fa4c54a..6753a0adcb0 100644 --- a/src/sage/ext/ccobject.h +++ b/src/sage/ext/ccobject.h @@ -59,12 +59,6 @@ T* Construct_ppp(void* mem, const P &d, const Q &e, const R &f){ return new(mem) T(d, e, f); } -/* Construct with four parameters */ -template -T* Construct_pppp(void* mem, const P &d, const Q &e, const R &f, const S &g){ - return new(mem) T(d, e, f, g); -} - /* Destruct */ template void Destruct(T* mem){ @@ -77,27 +71,47 @@ void Delete(T* mem){ delete mem; } -template -void _from_str(T* dest, const char* src){ - std::istringstream out(src); - out >> *dest; -} template -void _from_str_len(T* dest, const char* src, unsigned int len){ - std::istringstream out(std::string(src, len)); - out >> *dest; +static CYTHON_INLINE int ccreadstr(T& x, PyObject* b) +{ + PyObject* converted = NULL; + +#if PY_MAJOR_VERSION >= 3 + // Accept "str" input on Python 3 + if (PyUnicode_Check(b)) + { + converted = PyUnicode_EncodeFSDefault(b); + if (!converted) {return -1;} + b = converted; + } +#endif + + char* buffer; + Py_ssize_t length; + + if (PyBytes_AsStringAndSize(b, &buffer, &length) == -1) + {Py_XDECREF(converted); return -1;} + std::istringstream input(std::string(buffer, length)); + Py_XDECREF(converted); + + input >> x; + + return 0; } + template -PyObject* _to_PyString(const T *x) +static CYTHON_INLINE PyObject* ccrepr(const T& x) { - std::ostringstream instore; - instore << (*x); - std::string instr = instore.str(); - // using PyString_FromString truncates the output if whitespace is - // encountered so we use Py_BuildValue and specify the length - return Py_BuildValue("s#",instr.c_str(), instr.size()); + std::ostringstream instore; + instore << x; + std::string instr = instore.str(); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize(instr.c_str(), instr.size()); +#else + return PyUnicode_DecodeFSDefaultAndSize(instr.c_str(), instr.size()); +#endif } /* Arrays */ diff --git a/src/sage/ext/cplusplus.pxd b/src/sage/ext/cplusplus.pxd new file mode 100644 index 00000000000..66c562c2cac --- /dev/null +++ b/src/sage/ext/cplusplus.pxd @@ -0,0 +1,16 @@ +#***************************************************************************** +# Copyright (C) 2017 Jeroen Demeyer +# +# 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/ +#***************************************************************************** + +cdef extern from "sage/ext/ccobject.h": + # Print representation of any C++ object + str ccrepr[T](T x) + + # Read a Python bytes/str into a C++ object + int ccreadstr[T](T x, object b) except -1 diff --git a/src/sage/libs/ntl/GF2.pxd b/src/sage/libs/ntl/GF2.pxd index e4e1757bb91..48e0f4b3ac2 100644 --- a/src/sage/libs/ntl/GF2.pxd +++ b/src/sage/libs/ntl/GF2.pxd @@ -1,8 +1,5 @@ from .types cimport GF2_c -cdef extern from "ccobject.h": - void GF2_from_str "_from_str"(GF2_c* dest, char* s) - object GF2_to_PyString "_to_PyString"(GF2_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": int GF2_IsOne "IsOne"(GF2_c x) diff --git a/src/sage/libs/ntl/GF2E.pxd b/src/sage/libs/ntl/GF2E.pxd index 443439ecb20..c8b5f8ecdcf 100644 --- a/src/sage/libs/ntl/GF2E.pxd +++ b/src/sage/libs/ntl/GF2E.pxd @@ -1,8 +1,5 @@ from .types cimport GF2E_c, GF2X_c, GF2_c, GF2XModulus_c, ZZ_c -cdef extern from "ccobject.h": - void GF2E_from_str "_from_str"(GF2E_c* dest, char* s) - object GF2E_to_PyString "_to_PyString"(GF2E_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void GF2E_init "GF2E::init"(GF2X_c x) diff --git a/src/sage/libs/ntl/GF2EX.pxd b/src/sage/libs/ntl/GF2EX.pxd index f4a66485c57..c1a7dd33c0c 100644 --- a/src/sage/libs/ntl/GF2EX.pxd +++ b/src/sage/libs/ntl/GF2EX.pxd @@ -1,8 +1,5 @@ from .types cimport GF2EX_c -cdef extern from "ccobject.h": - void GF2EX_from_str "_from_str"(GF2EX_c* dest, char* s) - object GF2EX_to_PyString "_to_PyString"(GF2EX_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void GF2EX_add "add"( GF2EX_c x, GF2EX_c a, GF2EX_c b) diff --git a/src/sage/libs/ntl/GF2X.pxd b/src/sage/libs/ntl/GF2X.pxd index a1930acc158..d860dd30947 100644 --- a/src/sage/libs/ntl/GF2X.pxd +++ b/src/sage/libs/ntl/GF2X.pxd @@ -1,8 +1,5 @@ from .types cimport GF2X_c, GF2_c, GF2XModulus_c, vec_GF2_c, ZZ_c -cdef extern from "ccobject.h": - void GF2X_from_str "_from_str"(GF2X_c* dest, char* s) - object GF2X_to_PyString "_to_PyString"(GF2X_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": long *GF2XHexOutput_c "(&GF2X::HexOutput)" # work-around for Cython bug @@ -57,7 +54,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void GF2X_BuildIrred "BuildIrred" (GF2X_c f, long n) #### GF2XModulus_c - void GF2XModulus_from_str "_from_str"(GF2XModulus_c* dest, char* s) void GF2XModulus_build "build"(GF2XModulus_c F, GF2X_c f) # MUST be called before using the modulus long GF2XModulus_deg "deg"(GF2XModulus_c F) diff --git a/src/sage/libs/ntl/ZZ.pxd b/src/sage/libs/ntl/ZZ.pxd index 618c6f26214..979c60a77d0 100644 --- a/src/sage/libs/ntl/ZZ.pxd +++ b/src/sage/libs/ntl/ZZ.pxd @@ -2,9 +2,6 @@ from .types cimport ZZ_c -cdef extern from "ccobject.h": - void ZZ_from_str "_from_str"(ZZ_c* dest, char* s) - object ZZ_to_PyString "_to_PyString"(ZZ_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_conv_from_int "conv"(ZZ_c x, int i) diff --git a/src/sage/libs/ntl/ZZX.pxd b/src/sage/libs/ntl/ZZX.pxd index 9d83a7d2f10..fe4643845df 100644 --- a/src/sage/libs/ntl/ZZX.pxd +++ b/src/sage/libs/ntl/ZZX.pxd @@ -5,8 +5,7 @@ from .types cimport ZZ_c, vec_ZZ_c, ZZX_c cdef extern from "ccobject.h": void ZZX_swap "swap"(ZZX_c x, ZZX_c y) - void ZZX_from_str "_from_str"(ZZX_c* dest, char* s) - object ZZX_to_PyString "_to_PyString"(ZZX_c *x) + cdef extern from "sage/libs/ntl/ntlwrap.cpp": ctypedef struct pair_ZZX_long_c "pair_ZZX_long": diff --git a/src/sage/libs/ntl/ZZ_p.pxd b/src/sage/libs/ntl/ZZ_p.pxd index 8b66c7bd673..c70c967a8f6 100644 --- a/src/sage/libs/ntl/ZZ_p.pxd +++ b/src/sage/libs/ntl/ZZ_p.pxd @@ -2,9 +2,6 @@ from .types cimport ZZ_c, ZZ_p_c -cdef extern from "ccobject.h": - void ZZ_p_from_str "_from_str"(ZZ_p_c* dest, char* s) - object ZZ_p_to_PyString "_to_PyString"(ZZ_p_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": char* ZZ_p_to_str(ZZ_p_c* x) diff --git a/src/sage/libs/ntl/ZZ_pE.pxd b/src/sage/libs/ntl/ZZ_pE.pxd index 26018eb1ffa..02ec14971b4 100644 --- a/src/sage/libs/ntl/ZZ_pE.pxd +++ b/src/sage/libs/ntl/ZZ_pE.pxd @@ -2,9 +2,6 @@ from .types cimport ZZ_c, ZZ_p_c, ZZ_pX_c, ZZ_pE_c -cdef extern from "ccobject.h": - void ZZ_pE_from_str "_from_str"(ZZ_pE_c* dest, char* s) - object ZZ_pE_to_PyString "_to_PyString"(ZZ_pE_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pE_add "add"( ZZ_pE_c x, ZZ_pE_c a, ZZ_pE_c b) diff --git a/src/sage/libs/ntl/ZZ_pEX.pxd b/src/sage/libs/ntl/ZZ_pEX.pxd index c68ebe87ea0..1bf2b94de85 100644 --- a/src/sage/libs/ntl/ZZ_pEX.pxd +++ b/src/sage/libs/ntl/ZZ_pEX.pxd @@ -3,9 +3,6 @@ from .types cimport (ZZ_c, ZZ_p_c, ZZ_pContext_c, ZZ_pE_c, vec_ZZ_p_c, vec_ZZ_pE_c, ZZ_pEX_c, ZZ_pEX_Modulus_c) -cdef extern from "ccobject.h": - void ZZ_pEX_from_str "_from_str"(ZZ_pEX_c* dest, char* s) - object ZZ_pEX_to_PyString "_to_PyString"(ZZ_pEX_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": long ZZ_pEX_IsZero "IsZero"(ZZ_pEX_c a) @@ -72,7 +69,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pEX_InvMod "InvMod"(ZZ_pEX_c x, ZZ_pEX_c a, ZZ_pEX_c f) long ZZ_pEX_InvModStatus "InvModStatus"(ZZ_pEX_c x, ZZ_pEX_c a, ZZ_pEX_c f) - void ZZ_pEX_Modulus_from_str "_from_str"(ZZ_pEX_Modulus_c* dest, char* s) void ZZ_pEX_Modulus_build "build"(ZZ_pEX_Modulus_c F, ZZ_pEX_c f) long ZZ_pEX_Modulus_deg "deg"(ZZ_pEX_Modulus_c F) diff --git a/src/sage/libs/ntl/ZZ_pX.pxd b/src/sage/libs/ntl/ZZ_pX.pxd index 2e43f9a524f..62ffaace324 100644 --- a/src/sage/libs/ntl/ZZ_pX.pxd +++ b/src/sage/libs/ntl/ZZ_pX.pxd @@ -3,9 +3,6 @@ from .types cimport (ZZ_c, ZZX_c, ZZ_p_c, vec_ZZ_p_c, ZZ_pContext_c, ZZ_pX_c, ZZ_pX_Modulus_c, ZZ_pX_Multiplier_c) -cdef extern from "ccobject.h": - void ZZ_pX_from_str "_from_str"(ZZ_pX_c* dest, char* s) - object ZZ_pX_to_PyString "_to_PyString"(ZZ_pX_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": long ZZ_pX_IsZero "IsZero"(ZZ_pX_c a) @@ -69,7 +66,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pX_InvMod "InvMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_c f) long ZZ_pX_InvModStatus "InvModStatus"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_c f) - void ZZ_pX_Modulus_from_str "_from_str"(ZZ_pX_Modulus_c* dest, char* s) void ZZ_pX_Modulus_build "build"(ZZ_pX_Modulus_c F, ZZ_pX_c f) # MUST be called before using the modulus long ZZ_pX_Modulus_deg "deg"(ZZ_pX_Modulus_c F) @@ -86,7 +82,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pX_div_pre "div"(ZZ_pX_c q, ZZ_pX_c a, ZZ_pX_Modulus_c F) void ZZ_pX_InvMod_pre "InvMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F) - void ZZ_pX_Multiplier_from_str "_from_str"(ZZ_pX_Multiplier_c* dest, char* s) void ZZ_pX_Multiplier_build "build"(ZZ_pX_Multiplier_c F, ZZ_pX_c b, ZZ_pX_Modulus_c F) # MUST be called before using the multiplier void ZZ_pX_MulMod_premul "MulMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Multiplier_c B, ZZ_pX_Modulus_c F) diff --git a/src/sage/libs/ntl/lzz_pX.pxd b/src/sage/libs/ntl/lzz_pX.pxd index afe3c7f3e18..65b42ce1975 100644 --- a/src/sage/libs/ntl/lzz_pX.pxd +++ b/src/sage/libs/ntl/lzz_pX.pxd @@ -2,8 +2,6 @@ from .types cimport ZZ_c, zz_p_c, zz_pX_c, zz_pX_Modulus_c -cdef extern from "ccobject.h": - void zz_pX_Modulus_from_str "_from_str"(zz_pX_Modulus_c* dest, char* s) cdef extern from "sage/libs/ntl/ntlwrap.cpp": char* zz_pX_repr(zz_pX_c* x) diff --git a/src/sage/libs/ntl/mat_GF2.pxd b/src/sage/libs/ntl/mat_GF2.pxd index 182887963d4..ed1f03a3cce 100644 --- a/src/sage/libs/ntl/mat_GF2.pxd +++ b/src/sage/libs/ntl/mat_GF2.pxd @@ -1,8 +1,5 @@ from .types cimport mat_GF2_c, vec_GF2_c, GF2_c -cdef extern from "ccobject.h": - void mat_GF2_from_str "_from_str"(mat_GF2_c* dest, char* s) - object mat_GF2_to_PyString "_to_PyString"(mat_GF2_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void mat_GF2_add "add"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) diff --git a/src/sage/libs/ntl/mat_GF2E.pxd b/src/sage/libs/ntl/mat_GF2E.pxd index ade3dd11f25..5c826330ecb 100644 --- a/src/sage/libs/ntl/mat_GF2E.pxd +++ b/src/sage/libs/ntl/mat_GF2E.pxd @@ -1,8 +1,5 @@ from .types cimport mat_GF2E_c, vec_GF2E_c, GF2E_c -cdef extern from "ccobject.h": - void mat_GF2E_from_str "_from_str"(mat_GF2E_c* dest, char* s) - object mat_GF2E_to_PyString "_to_PyString"(mat_GF2E_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void mat_GF2E_add "add"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) diff --git a/src/sage/libs/ntl/mat_ZZ.pxd b/src/sage/libs/ntl/mat_ZZ.pxd index b86929ab547..c2dd50e8fa2 100644 --- a/src/sage/libs/ntl/mat_ZZ.pxd +++ b/src/sage/libs/ntl/mat_ZZ.pxd @@ -1,7 +1,5 @@ from .types cimport mat_ZZ_c, ZZ_c, ZZX_c -cdef extern from "ccobject.h": - object mat_ZZ_to_PyString "_to_PyString"(mat_ZZ_c *x) cdef extern from "sage/libs/ntl/ntlwrap.cpp": void mat_ZZ_mul "mul"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index 5dea4c05533..a86990e5f77 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -16,6 +16,7 @@ from __future__ import division from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -52,10 +53,7 @@ cdef class ntl_GF2(object): elif isinstance(v, int) or isinstance(v, long) or isinstance(v, Integer): GF2_conv_long(self.x, int(v) % 2) elif v is not None: - v = str(v) - sig_on() - GF2_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, str(v)) def __repr__(self): """ @@ -65,7 +63,7 @@ cdef class ntl_GF2(object): sage: str(ntl.GF2(1)) # indirect doctest '1' """ - return GF2_to_PyString(&self.x) + return ccrepr(self.x) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index 645252604d7..ab15f89c692 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -16,6 +16,8 @@ from __future__ import absolute_import, division +from sage.ext.cplusplus cimport ccrepr + include 'misc.pxi' include 'decl.pxi' @@ -187,7 +189,7 @@ cdef class ntl_GF2E(object): [1 1 0 1] """ self.c.restore_c() - return GF2E_to_PyString(&self.x) + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_GF2EX.pyx b/src/sage/libs/ntl/ntl_GF2EX.pyx index a8b4d8918e5..b902ca3f117 100644 --- a/src/sage/libs/ntl/ntl_GF2EX.pyx +++ b/src/sage/libs/ntl/ntl_GF2EX.pyx @@ -15,6 +15,7 @@ from __future__ import absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -50,10 +51,7 @@ cdef class ntl_GF2EX(object): if modulus is None: raise ValueError("You must specify a modulus when creating a GF2E.") - s = str(x) - sig_on() - GF2EX_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, str(x)) def __cinit__(self, modulus=None, x=[]): #################### WARNING ################### @@ -147,7 +145,7 @@ cdef class ntl_GF2EX(object): sage: ntl.GF2EX(ctx, '[[1 0] [2 1]]').__repr__() '[[1] [0 1]]' """ - return GF2EX_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_GF2EX self, other): """ diff --git a/src/sage/libs/ntl/ntl_GF2X.pyx b/src/sage/libs/ntl/ntl_GF2X.pyx index cab8a2ad673..5c3fc79d689 100644 --- a/src/sage/libs/ntl/ntl_GF2X.pyx +++ b/src/sage/libs/ntl/ntl_GF2X.pyx @@ -17,6 +17,7 @@ from __future__ import absolute_import, division from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -153,10 +154,8 @@ cdef class ntl_GF2X(object): elif isinstance(x, FiniteField_ntl_gf2eElement): x = x.polynomial().list() s = str(x).replace(","," ") - sig_on() # TODO: this is very slow, but we wait until somebody complains - GF2X_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, s) def __reduce__(self): """ @@ -178,7 +177,7 @@ cdef class ntl_GF2X(object): sage: ntl.GF2X(ntl.ZZ_pX([1,1,3],2)).__repr__() '[1 1 1]' """ - return GF2X_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_GF2X self, other): """ @@ -478,7 +477,7 @@ cdef class ntl_GF2X(object): """ cdef long _hex = GF2XHexOutput_c[0] GF2XHexOutput_c[0] = 0 - s = GF2X_to_PyString(&self.x) + s = ccrepr(self.x) GF2XHexOutput_c[0] = _hex return s @@ -501,7 +500,7 @@ cdef class ntl_GF2X(object): """ cdef long _hex = GF2XHexOutput_c[0] GF2XHexOutput_c[0] = 1 - s = GF2X_to_PyString(&self.x) + s = ccrepr(self.x) GF2XHexOutput_c[0] = _hex return s diff --git a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi index 2e4768317e7..77d66c16983 100644 --- a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi +++ b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi @@ -71,7 +71,6 @@ cdef object celement_repr(GF2X_c *e, long parent): sage: x x """ - #return GF2X_to_PyString(e) raise NotImplementedError cdef inline int celement_set(GF2X_c* res, GF2X_c* a, long parent) except -2: diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 320d97b6c2e..4697562c432 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -15,6 +15,7 @@ from __future__ import print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -95,9 +96,7 @@ cdef class ntl_ZZ(object): (v[1:-1].isdigit() or (len(v) <= 2)) and \ (v[-1].isdigit() or (v[-1].lower() in ['l','r']))): raise ValueError("invalid integer: %s" % v) - sig_on() - ZZ_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, v) def __repr__(self): """ @@ -107,7 +106,7 @@ cdef class ntl_ZZ(object): sage: ntl.ZZ(5).__repr__() '5' """ - return ZZ_to_PyString(&self.x) + return ccrepr(self.x) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index e07b642a798..836d5cd4223 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -15,6 +15,7 @@ from __future__ import division, print_function, absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccreadstr include "decl.pxi" include 'misc.pxi' @@ -129,8 +130,7 @@ cdef class ntl_ZZX(object): cc = x ZZX_SetCoeff(self.x, i, cc.x) else: - v = str(v) - ZZX_from_str(&self.x, v) + ccreadstr(self.x, str(v)) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 1193b1b90ac..0ee8d5bd214 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -15,6 +15,7 @@ from __future__ import print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -105,7 +106,6 @@ cdef class ntl_ZZ_p(object): cdef ZZ_c temp, num, den cdef long failed if v is not None: - sig_on() if isinstance(v, ntl_ZZ_p): self.x = (v).x elif isinstance(v, int): @@ -121,9 +121,7 @@ cdef class ntl_ZZ_p(object): (v.denominator())._to_ZZ(&den) ZZ_p_div(self.x, ZZ_to_ZZ_p(num), ZZ_to_ZZ_p(den)) else: - v = str(v) - ZZ_p_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, str(v)) def __cinit__(self, v=None, modulus=None): #################### WARNING ################### @@ -189,7 +187,7 @@ cdef class ntl_ZZ_p(object): '7' """ self.c.restore_c() - return ZZ_p_to_PyString(&self.x) + return ccrepr(self.x) def __richcmp__(ntl_ZZ_p self, other, int op): r""" diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 77499da8f3a..1ede04efadb 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -16,6 +16,7 @@ from __future__ import absolute_import, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -126,8 +127,7 @@ cdef class ntl_ZZ_pE(object): (v)._to_ZZ(&temp) self.x = ZZ_to_ZZ_pE(temp) else: - v = str(v) - ZZ_pE_from_str(&self.x, v) + ccreadstr(self.x, str(v)) def __cinit__(ntl_ZZ_pE self, v=None, modulus=None): #################### WARNING ################### @@ -171,11 +171,8 @@ cdef class ntl_ZZ_pE(object): return self.c def __repr__(self): - #return self.get_as_ZZ_pX().__repr__() self.c.restore_c() - #sig_on() - return ZZ_pE_to_PyString(&self.x) - #return string_delete(ans) + return ccrepr(self.x) def __richcmp__(ntl_ZZ_pE self, other, int op): r""" diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index 3e0095e9299..9842b46b28e 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -23,6 +23,7 @@ AUTHORS: from __future__ import division, absolute_import, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -160,8 +161,7 @@ cdef class ntl_ZZ_pEX(object): [[3 2] [1 2] [1 2]] """ self.c.restore_c() - return ZZ_pEX_to_PyString(&self.x) - #return string_delete(ZZ_pEX_to_str(&self.x)) + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi index c6c50f554bd..ae325adc330 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi +++ b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi @@ -22,7 +22,6 @@ from cysignals.signals cimport sig_on, sig_off from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class from sage.libs.ntl.ZZ_pEX cimport * -from sage.libs.ntl.ZZ_pE cimport ZZ_pE_from_str from sage.libs.ntl.ntl_ZZ_pE cimport ntl_ZZ_pE from sage.libs.ntl.types cimport ZZ_pX_c, ZZ_pEX_c diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 7fa70db4441..33493b161b3 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -16,6 +16,7 @@ from __future__ import absolute_import, division, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -102,9 +103,7 @@ cdef class ntl_ZZ_pX(object): ZZ_pX_SetCoeff(self.x, i, cc.x) elif v is not None: s = str(v).replace(',',' ').replace('L','') - sig_on() - ZZ_pX_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, s) def __cinit__(self, v=None, modulus=None): #################### WARNING ################### @@ -160,11 +159,7 @@ cdef class ntl_ZZ_pX(object): '[1 0 3]' """ self.c.restore_c() - #cdef char* s = ZZ_pX_repr(&self.x) - #t = str(s) - #sig_free(s) - return ZZ_pX_to_PyString(&self.x) - #return t + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 3a6c91ac392..efc3fb09953 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -27,6 +27,7 @@ AUTHORS: #***************************************************************************** from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -145,7 +146,7 @@ cdef class ntl_mat_GF2(object): [0 1 1 0] ] """ - return mat_GF2_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_mat_GF2 self, other): """ diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index 6f28cfff21f..007f8281878 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -25,6 +25,7 @@ from __future__ import absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -188,7 +189,7 @@ cdef class ntl_mat_GF2E(object): '[[[] [1]]\n[[] [1]]\n]' """ self.c.restore_c() - return mat_GF2E_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_mat_GF2E self, other): """ diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index 97fc8187eb1..60d3b467c59 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -14,6 +14,7 @@ #***************************************************************************** from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -126,7 +127,7 @@ cdef class ntl_mat_ZZ(object): sage: M = ntl.mat_ZZ(2,3,[5..10]) ; M.__repr__() '[\n[5 6 7]\n[8 9 10]\n]' """ - return mat_ZZ_to_PyString(&self.x).replace('[[','[\n[',1) + return ccrepr(self.x).replace('[[','[\n[',1) def __mul__(ntl_mat_ZZ self, other): """ diff --git a/src/sage/libs/ntl/vec_GF2.pxd b/src/sage/libs/ntl/vec_GF2.pxd index 0630893b65a..81c3244e932 100644 --- a/src/sage/libs/ntl/vec_GF2.pxd +++ b/src/sage/libs/ntl/vec_GF2.pxd @@ -1,9 +1,5 @@ from .types cimport vec_GF2_c, GF2_c -cdef extern from "ccobject.h": - void vec_GF2_from_str "_from_str"(vec_GF2_c* dest, char* s) - object vec_GF2_to_PyString "_to_PyString"(vec_GF2_c *x) - void vec_GF2_swap "swap"(vec_GF2_c x, vec_GF2_c y) cdef extern from "sage/libs/ntl/ntlwrap.cpp": int vec_GF2_IsZero "IsZero"(vec_GF2_c x) diff --git a/src/sage/libs/ntl/vec_GF2E.pxd b/src/sage/libs/ntl/vec_GF2E.pxd index 20f88979f0b..1cfdd7109fa 100644 --- a/src/sage/libs/ntl/vec_GF2E.pxd +++ b/src/sage/libs/ntl/vec_GF2E.pxd @@ -1,5 +1 @@ from .types cimport vec_GF2E_c - -cdef extern from "ccobject.h": - void vec_GF2E_from_str "_from_str"(vec_GF2E_c* dest, char* s) - object vec_GF2E_to_PyString "_to_PyString"(vec_GF2E_c *x) diff --git a/src/sage/libs/polybori/decl.pxd b/src/sage/libs/polybori/decl.pxd index e7703c14291..6d1e0285cad 100644 --- a/src/sage/libs/polybori/decl.pxd +++ b/src/sage/libs/polybori/decl.pxd @@ -57,10 +57,10 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": int (*lastBlockStart)() bint isDegreeOrder() - ctypedef struct PBSet "DefaultRinged" - ctypedef struct PBPoly "DefaultRinged" + ctypedef struct PBSet "DefaultRinged " + ctypedef struct PBPoly "DefaultRinged " - ctypedef struct PBVar "DefaultRinged": + ctypedef struct PBVar "DefaultRinged ": int (* index "index")() bint (* is_equal "operator==")(PBVar right) @@ -102,7 +102,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBMonomVarIter_destruct "Destruct" \ (PBMonomVarIter *mem) - ctypedef struct PBMonom "DefaultRinged": + ctypedef struct PBMonom "DefaultRinged ": bint (* reducibleBy)(PBMonom rhs) int (* deg)() size_t (* hash)() @@ -122,8 +122,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBMonom (* GCD)(PBMonom rhs) PBRing (* ring)() - object PBMonom_to_str "_to_PyString"(PBMonom *p) - # Wrapping constructors PBMonom PBMonom_Constructor "BooleMonomial" (PBRing r) PBMonom PBMonom_Constructor_var "BooleMonomial" (PBVar m) @@ -141,7 +139,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBSetIter_destruct "Destruct"(PBSetIter *mem) - ctypedef struct PBSet "DefaultRinged": + ctypedef struct PBSet "DefaultRinged ": bint (* owns)(PBMonom val) int (* nNodes)() int (* nSupport)() @@ -169,8 +167,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBSet pb_include_divisors "include_divisors" (PBSet p) PBSet pb_minimal_elements "minimal_elements" (PBSet p) - object PBSet_to_str "_to_PyString"(PBSet *p) - # non-allocating versions PBSet PBSet_Constructor_ring "BooleSet"(PBRing r) PBSet PBSet_Constructor_poly "BooleSet"(PBPoly p) @@ -186,7 +182,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBPolyIter_destruct "Destruct"(PBPolyIter *mem) - ctypedef struct PBPoly "DefaultRinged": + ctypedef struct PBPoly "DefaultRinged ": int (* deg)() int (* leadDeg)() int (* lexLeadDeg)() @@ -240,8 +236,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBPoly PBPoly_Constructor_var "BoolePolynomial" (PBVar d) PBPoly PBPoly_Constructor_int_ring "BoolePolynomial" (int d, PBRing r) - object PBPoly_to_str "_to_PyString >"(PBPoly *p) - ctypedef struct PBPolyVectorIter \ "std::vector::iterator ": PBPoly (* value "operator*")() @@ -251,7 +245,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBPolyVectorIter_destruct "Destruct::iterator>"(PBPolyVectorIter *mem) - ctypedef struct PBPolyVector "std::vector": + ctypedef struct PBPolyVector "std::vector ": int (* size)() PBPoly (* get "operator[]")(int) PBPolyVectorIter (* begin)() @@ -291,7 +285,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": int (* size)() PBPolyEntry (* get "operator[]")(int) - ctypedef struct PBFglmStrategy "PBWrappedPtr": + ctypedef struct PBFglmStrategy "PBWrappedPtr ": PBPolyVector (* main "operator->()->main")() PBFglmStrategy PBFglmStrategy_Constructor "PBWrappedPtr" \ @@ -451,13 +445,13 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBConstant* PBConstant_construct "Construct_p" \ (void* mem, int val) - ctypedef struct PBVarFactory "DefaultRinged": + ctypedef struct PBVarFactory "DefaultRinged ": PBVar (* call "operator()")(int index) - ctypedef struct PBMonomFactory "DefaultRinged": + ctypedef struct PBMonomFactory "DefaultRinged ": PBMonom (* call "operator()")() - ctypedef struct PBPolyFactory "DefaultRinged": + ctypedef struct PBPolyFactory "DefaultRinged ": PBPoly (* call_int "operator()")(int) PBPoly (* call_poly "operator()")(PBPoly) PBPoly (* call_monom "operator()")(PBMonom) diff --git a/src/sage/libs/polybori/pb_wrap.h b/src/sage/libs/polybori/pb_wrap.h index 2ba1cc524f1..d4f3922e733 100644 --- a/src/sage/libs/polybori/pb_wrap.h +++ b/src/sage/libs/polybori/pb_wrap.h @@ -170,12 +170,6 @@ base(ring_singleton::instance(), ring_singleton::instance(), PolynomialVector()) { } -template -PyObject* preallocated_to_PyString(const DefaultRinged *wrapped) { - return _to_PyString(wrapped) ; -} - - template class PBWrappedPtr: public boost::shared_ptr { diff --git a/src/sage/libs/pynac/pynac.pxd b/src/sage/libs/pynac/pynac.pxd index 8766e458056..454e685d740 100644 --- a/src/sage/libs/pynac/pynac.pxd +++ b/src/sage/libs/pynac/pynac.pxd @@ -256,7 +256,6 @@ cdef extern from "sage/libs/pynac/wrap.h": # Conversions double GEx_to_double(GEx e, int* success) except + - GEx_to_str "_to_PyString"(GEx *s) except + GEx_to_str_latex "_to_PyString_latex"(GEx *s) except + bint is_a_symbol "is_a" (GEx e) @@ -328,10 +327,6 @@ cdef extern from "sage/libs/pynac/wrap.h": GEx unarchive_ex(GExList sym_lst, unsigned ind) except + void printraw "printraw(std::cout); " (int t) - GArchive_to_str "_to_PyString"(GArchive *s) - void GArchive_from_str "_from_str_len"(GArchive *ar, char* s, - unsigned int l) - GEx g_abs "GiNaC::abs" (GEx x) except + # absolute value GEx g_step "GiNaC::unit_step" (GEx x) except + # step function diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index ec3e0c7afcb..757c130c625 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -22,6 +22,7 @@ from __future__ import absolute_import from cysignals.memory cimport check_malloc, sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include "sage/libs/ntl/decl.pxi" from cypari2.paridecl cimport * @@ -179,7 +180,7 @@ cdef class Cache_ntl_gf2e(SageObject): GF2E_conv_long((self._one_element).x,1) if k > 1: self._gen = self._new() - GF2E_from_str(&self._gen.x, "[0 1]") + ccreadstr(self._gen.x, b"[0 1]") elif modulus[0]: self._gen = self._one_element else: @@ -221,7 +222,7 @@ cdef class Cache_ntl_gf2e(SageObject): # Print the current modulus. cdef GF2XModulus_c modulus = GF2E_modulus() cdef GF2X_c mod_poly = GF2XModulus_GF2X(modulus) - print(GF2X_to_PyString(&mod_poly)) + print(ccrepr(mod_poly)) # do another garbage collection gc.collect() @@ -229,7 +230,7 @@ cdef class Cache_ntl_gf2e(SageObject): # and print the modulus again modulus = GF2E_modulus() mod_poly = GF2XModulus_GF2X(modulus) - print(GF2X_to_PyString(&mod_poly)) + print(ccrepr(mod_poly)) cdef FiniteField_ntl_gf2eElement _new(self): """ diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 232bec764a1..d9fb1942d6e 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -186,6 +186,7 @@ from __future__ import print_function, absolute_import from cpython.object cimport Py_EQ, Py_NE from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr import operator @@ -2297,7 +2298,7 @@ cdef class BooleanMonomial(MonoidElement): sage: M(x*y) x*y """ - return PBMonom_to_str(&self._pbmonom) + return ccrepr(self._pbmonom) def _eval(self, d): """ @@ -2947,7 +2948,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: repr(a+b+z^2+1) # indirect doctest 'a + b + z + 1' """ - return PBPoly_to_str(&self._pbpoly) + return ccrepr(self._pbpoly) def _repr_with_changed_varnames(self, varnames): r""" @@ -2987,7 +2988,7 @@ cdef class BooleanPolynomial(MPolynomial): for i from 0 <= i < N: P._pbring.setVariableName(i, orig_varnames[i]) raise TypeError("varnames has entries with wrong type.") - s = PBPoly_to_str(&self._pbpoly) + s = ccrepr(self._pbpoly) for i from 0 <= i < N: P._pbring.setVariableName(i, orig_varnames[i]) return s @@ -5405,7 +5406,7 @@ cdef class BooleSet: sage: repr(BS) # indirect doctest '{}' """ - return PBSet_to_str(&self._pbset) + return ccrepr(self._pbset) def set(self): """ diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 7b610e9b01a..d0985591d68 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -36,6 +36,7 @@ from __future__ import absolute_import, print_function from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include "sage/libs/ntl/decl.pxi" @@ -381,10 +382,10 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): if sign: if sign > 0: sign_str = '+' - coeff_str = ZZ_to_PyString(&self.__poly.rep.elts()[i]) + coeff_str = ccrepr(self.__poly.rep.elts()[i]) else: sign_str = '-' - coeff_str = ZZ_to_PyString(&self.__poly.rep.elts()[i])[1:] + coeff_str = ccrepr(self.__poly.rep.elts()[i])[1:] if i > 0: if coeff_str == '1': coeff_str = '' diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index 0e22e15679e..be9e9c6bd3a 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -10,12 +10,9 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer_ring cimport IntegerRing_class from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class -from sage.libs.ntl.ZZ_pE cimport ZZ_pE_to_PyString from sage.libs.ntl.ZZ_pE cimport ZZ_pE_to_ZZ_pX -from sage.libs.ntl.ZZ_pX cimport ZZ_pX_to_PyString from sage.libs.ntl.ZZ_pX cimport ZZ_pX_deg, ZZ_pX_coeff from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX -from sage.libs.ntl.ZZ_p cimport ZZ_p_to_PyString from sage.libs.ntl.ZZ_p cimport ZZ_p_rep from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 4f1252ca34d..3c167efba9f 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -138,6 +138,7 @@ Test if :trac:`9947` is fixed:: from __future__ import print_function, absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr from inspect import ismethod import operator @@ -398,7 +399,7 @@ cdef class Expression(CommutativeRingElement): cdef GConstant* c if is_a_constant(self._gobj): from sage.symbolic.constants import constants_name_table - return constants_name_table[GEx_to_str(&self._gobj)] + return constants_name_table[ccrepr(self._gobj)] if is_a_infinity(self._gobj): if (ex_to_infinity(self._gobj).is_unsigned_infinity()): return unsigned_infinity @@ -466,8 +467,7 @@ cdef class Expression(CommutativeRingElement): """ cdef GArchive ar ar.archive_ex(self._gobj, "sage_ex") - ar_str = GArchive_to_str(&ar) - return (0, map(repr, self.variables()), ar_str) + return (0, [repr(x) for x in self.variables()], ccrepr(ar)) def _dbgprint(self): r""" @@ -569,7 +569,7 @@ cdef class Expression(CommutativeRingElement): # initialize archive cdef GArchive ar - GArchive_from_str(&ar, state[2], len(state[2])) + ccreadstr(ar, state[2]) # extract the expression from the archive self._gobj = GEx(ar.unarchive_ex(sym_lst, 0)) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index f668c30558c..0d7e6036374 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -14,6 +14,8 @@ The symbolic ring #***************************************************************************** from __future__ import absolute_import +from sage.ext.cplusplus cimport ccrepr + from sage.libs.pynac.pynac cimport * from sage.rings.integer cimport Integer @@ -881,7 +883,7 @@ cdef class SymbolicRing(CommutativeRing): sage: SR._repr_element_(x+2) 'x + 2' """ - return GEx_to_str(&x._gobj) + return ccrepr(x._gobj) def _latex_element_(self, Expression x): """ From 6700ab33f3844190f9dcfc323492b65188796d85 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 15 Sep 2017 13:45:46 +0200 Subject: [PATCH 065/218] Fix cython_metaclass header --- src/sage/cpython/cython_metaclass.pxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/cpython/cython_metaclass.pxd b/src/sage/cpython/cython_metaclass.pxd index b9bacfa67c5..189eb04f1c4 100644 --- a/src/sage/cpython/cython_metaclass.pxd +++ b/src/sage/cpython/cython_metaclass.pxd @@ -1,2 +1,2 @@ -cdef extern from "sage/cpython/cython_metaclass.h": +cdef extern from "cython_metaclass.h": PyMethodDescr_CallSelf(desc, self) From c73ce0c31678f8b126c8de0edcb820a9c28c5fe7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 16 Sep 2017 09:38:49 +0200 Subject: [PATCH 066/218] base implementation: singular expansion of implicit function --- .../asymptotic_expansion_generators.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 0b87be89c8b..937b7089424 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -992,6 +992,98 @@ def inverse_gamma_derivative(shift, r): return result + @staticmethod + def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): + """ + Return the singular expansion for a function `y(z)` defined + implicitly by `y(z) = z \Phi(y(z))`. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`, which is assumed to be + not an affine function, the coefficients of the expansion around + `0` need to be non-negative, and it needs to satisfy + `\Phi(0) \neq 0`. This is not checked! + + - ``period`` -- (default: 1) the period `p` of the function `\Phi`, i.e., the largest + integer `p` such that the power series `\Phi(u)` can be written as `\Psi(u^p)`, + where `\Psi` is another power series. (Not yet implemented) + + - ``tau`` -- (default: ``None``) the unique positive solution `\tau` of + the characteristic equation, `\Phi(\tau) - \tau \Phi'(\tau) = 0`. If ``None``, + then `\tau` is tried to be determined automatically. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + In the given case, the radius of convergence of the function of + interest is known to be `\rho = \tau/\Phi(\tau)`. For technical + reasons, the variable in the returned asymptotic expansion + represents a singular element of the form `(1 - z/\rho)^{-1}`, + for the variable `z\to\rho`. + + + EXAMPLES:: + + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=exp, precision=8) + 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) + + """ + from sage.symbolic.ring import SR + y = SR('y') + + if tau is None: + u = SR('u') + positive_solution = filter(lambda s: s.rhs() > 0, solve(phi(u) - u*phi(u).diff(u), u)) + if len(positive_solution) == 1: + tau = positive_solution[0].rhs() + else: + raise ValueError('Fundamental constant tau could not be determined') + + def H(y): + return tau/phi(tau) - y/phi(y) + + A = AsymptoticRing(growth_group='{Z}^QQ'.format(Z=var), + coefficient_ring=SR, + default_prec=precision) + if precision is None: + precision = A.default_prec + Z = A.gen() + + def ansatz(precision=precision): + if precision < 1: + return O(A(1)) + if precision == 1: + return O((1/Z)^(1/2)) + return (-sqrt(2*tau/phi(tau)/H(y).diff(y,2)(y=tau)) * (1/Z)^(1/2) + + sum([SR("d{}".format(j)) * (1/Z)^(j/2) for j in srange(2, precision)]) + + O((1/Z)^(precision/2))) + + # we compare coefficients between a "single" Z and the + # following expansion, this allows us to compute the constants d_j + z_expansion = sum([H(z).diff(z, k)(z=tau)/factorial(k) * + ansatz(precision=precision+2-k)^k + for k in srange(2, precision)]) + O((1/Z)^(precision/2)) + + solution_dict = dict() + for k in srange(2, precision-1): + coef = z_expansion.monomial_coefficient((1/Z)^((k+1)/2)) + current_var = SR('d{k}'.format(k=k)) + solution_dict[current_var] = coef.subs(solution_dict).solve(current_var)[0].rhs() + + return A(tau) + ansatz(precision=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) + def _sa_coefficients_lambda_(K, beta=0): r""" Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis. From be30ed88e02d33442167f36c4ea8e608351e7e2c Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sat, 16 Sep 2017 13:25:28 +0200 Subject: [PATCH 067/218] trac #18395: fresh rebase on 8.1.beta5 --- src/sage/graphs/generic_graph.py | 35 ++--- src/sage/graphs/generic_graph_pyx.pxd | 8 +- src/sage/graphs/generic_graph_pyx.pyx | 198 ++++++++++++++++---------- 3 files changed, 147 insertions(+), 94 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 19c1b21232f..852bd85e9c0 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -18337,10 +18337,10 @@ def layout(self, layout = None, pos = None, dim = 2, save_pos = False, **options sage: g = digraphs.ButterflyGraph(1) sage: g.layout() - {('0', 0): [2.22..., 0.832...], - ('0', 1): [0.833..., 0.543...], - ('1', 0): [1.12..., -0.830...], - ('1', 1): [2.50..., -0.545...]} + {('0', 0): [2.69..., 0.43...], + ('0', 1): [1.35..., 0.86...], + ('1', 0): [0.89..., -0.42...], + ('1', 1): [2.26..., -0.87...]} sage: g.layout(layout="acyclic_dummy", save_pos=True) {('0', 0): [0.3..., 0], @@ -18349,10 +18349,10 @@ def layout(self, layout = None, pos = None, dim = 2, save_pos = False, **options ('1', 1): [0.6..., 1]} sage: g.layout(dim = 3) - {('0', 0): [2.02..., 0.528..., 0.343...], - ('0', 1): [1.61..., 0.260..., -0.927...], - ('1', 0): [0.674..., -0.528..., -0.343...], - ('1', 1): [1.07..., -0.260..., 0.927...]} + {('0', 0): [0.68..., 0.50..., -0.24...], + ('0', 1): [1.02..., -0.02..., 0.93...], + ('1', 0): [2.06..., -0.49..., 0.23...], + ('1', 1): [1.74..., 0.01..., -0.92...]} Here is the list of all the available layout options:: @@ -18430,12 +18430,12 @@ def layout_spring(self, by_component = True, **options): sage: g = graphs.LadderGraph(3) #TODO!!!! sage: g.layout_spring() - {0: [1.28..., -0.94...], - 1: [1.57..., -0.10...], - 2: [1.83..., 0.74...], - 3: [0.53..., -0.75...], - 4: [0.79..., 0.10...], - 5: [1.08..., 0.94...]} + {0: [0.73..., -0.29...], + 1: [1.37..., 0.30...], + 2: [2.08..., 0.89...], + 3: [1.23..., -0.83...], + 4: [1.88..., -0.30...], + 5: [2.53..., 0.22...]} sage: g = graphs.LadderGraph(7) sage: g.plot(layout = "spring") Graphics object consisting of 34 graphics primitives @@ -18444,13 +18444,6 @@ def layout_spring(self, by_component = True, **options): layout_default = layout_spring -# if not isinstance(graph.get_pos(), dict): -# if graph.is_planar(): -# graph.set_planar_positions() -# else: -# import sage.graphs.generic_graph_pyx as ggp -# graph.set_pos(ggp.spring_layout_fast_split(graph, iterations=1000)) - def layout_ranked(self, heights = None, dim = 2, spring = False, **options): """ Computes a ranked layout for this graph diff --git a/src/sage/graphs/generic_graph_pyx.pxd b/src/sage/graphs/generic_graph_pyx.pxd index 29bfaf91275..e25d08f023e 100644 --- a/src/sage/graphs/generic_graph_pyx.pxd +++ b/src/sage/graphs/generic_graph_pyx.pxd @@ -1,7 +1,13 @@ from sage.structure.sage_object cimport SageObject from sage.graphs.base.dense_graph cimport DenseGraph -cdef run_spring(int, int, double*, int*, int, bint) +ctypedef int * D_TWO +ctypedef char * D_THREE +ctypedef fused dimension_t: + D_TWO + D_THREE + +cdef run_spring(int, dimension_t, double*, int*, int, int, bint) cdef class GenericGraph_pyx(SageObject): pass diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 0605ee7203c..6a480b78243 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -22,11 +22,13 @@ AUTHORS: from __future__ import absolute_import, print_function -from cysignals.memory cimport check_allocarray, sig_free +from cysignals.memory cimport check_allocarray, check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off +import cython + include "sage/data_structures/binary_matrix.pxi" -from libc.math cimport sqrt +from libc.math cimport sqrt, fabs from libc.string cimport memset from sage.libs.gmp.mpz cimport * @@ -61,7 +63,9 @@ def spring_layout_fast_split(G, **options): sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast_split sage: spring_layout_fast_split(G) - {0: [0.452..., 0.247...], ..., 502: [25.7..., 0.505...]} + {0: [0.77..., 0.06...], + ... + 902: [3.13..., 0.22...]} AUTHOR: @@ -73,8 +77,8 @@ def spring_layout_fast_split(G, **options): buffer = 1/sqrt(len(G)) for g in Gs: cur_pos = spring_layout_fast(g, **options) - xmin = min([x[0] for x in cur_pos.values()]) - xmax = max([x[0] for x in cur_pos.values()]) + xmin = min(x[0] for x in cur_pos.itervalues()) + xmax = max(x[0] for x in cur_pos.itervalues()) if len(g) > 1: buffer = (xmax - xmin)/sqrt(len(g)) for v, loc in cur_pos.iteritems(): @@ -104,7 +108,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G) - {0: [-0.0733..., 0.157...], ..., 502: [-0.551..., 0.682...]} + {0: [0.00..., 0.04...], + ... + 902: [-0.47..., -0.10...]} With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -120,7 +126,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G, by_component = True) - {0: [2.12..., -0.321...], ..., 502: [26.0..., -0.812...]} + {0: [2.21..., -0.00...], + ... + 902: [3.07..., 0.86...]} """ if by_component: @@ -136,32 +144,34 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True if n == 0: return {} - cdef double* pos = check_allocarray(n, dim * sizeof(double)) + cdef double* pos # position of each vertex (for dim=2: x1,y1,x2,y2,...) + cdef int* elist # lexicographically ordered list of edges (u1,v1,u2,v2,...) + cdef double* cen # array of 'dim' doubles + try: + elist = check_allocarray(2 * G.size() + 2, sizeof(int)) + pos = check_allocarray( n*dim , sizeof(double)) + cen = check_calloc(dim, sizeof(double)) + except: + sig_free(pos) + sig_free(elist) + sig_free(cen) + raise - # convert or create the starting positions as a flat list of doubles - if vpos is None: # set the initial positions randomly in 1x1 box - for i from 0 <= i < n*dim: - pos[i] = random() + # Initialize the starting positions + if vpos is None: + for i in range(n*dim): + pos[i] = random() # random in 1x1 box else: - for i from 0 <= i < n: + for i in range(n): loc = vpos[vlist[i]] - for x from 0 <= x check_allocarray(2 * len(G.edges()) + 2, sizeof(int)) - except MemoryError: - sig_free(pos) - raise - + # Lexicographically ordered list of edges cdef int cur_edge = 0 - for i from 0 <= i < n: - for j from i < j < n: + for i in range(n): + for j in range(i+1, n): if G.has_edge(vlist[i], vlist[j]): elist[cur_edge] = i elist[cur_edge+1] = j @@ -169,52 +179,51 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True # finish the list with -1, -1 which never gets matched # but does get compared against when looking for the "next" edge - elist[cur_edge] = -1 + elist[cur_edge] = -1 elist[cur_edge+1] = -1 - run_spring(iterations, dim, pos, elist, n, height) + if dim == 2: + run_spring( iterations, NULL, pos, elist, n, G.size(), height) + elif dim == 3: + run_spring( iterations, NULL, pos, elist, n, G.size(), height) + else: + raise ValueError("'dim' must be equal to 2 or 3") # recenter - cdef double* cen cdef double r, r2, max_r2 = 0 if rescale: - try: - cen = check_allocarray(dim, sizeof(double)) - except MemoryError: - sig_free(elist) - sig_free(pos) - raise - for x from 0 <= x < dim: cen[x] = 0 - for i from 0 <= i < n: - for x from 0 <= x < dim: + for i in range(n): + for x in range(dim): cen[x] += pos[i*dim + x] - for x from 0 <= x < dim: cen[x] /= n - for i from 0 <= i < n: + for x in range(dim): + cen[x] /= n + for i in range(n): r2 = 0 - for x from 0 <= x < dim: + for x in range(dim): pos[i*dim + x] -= cen[x] r2 += pos[i*dim + x] * pos[i*dim + x] if r2 > max_r2: max_r2 = r2 r = 1 if max_r2 == 0 else sqrt(max_r2) - for i from 0 <= i < n: - for x from 0 <= x < dim: + for i in range(n): + for x in range(dim): pos[i*dim + x] /= r - sig_free(cen) # put the data back into a position dictionary vpos = {} - for i from 0 <= i < n: - vpos[vlist[i]] = [pos[i*dim+x] for x from 0 <= x < dim] + for i in range(n): + vpos[vlist[i]] = [pos[i*dim+x] for x in range(dim)] sig_free(pos) sig_free(elist) + sig_free(cen) return vpos -cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint height): - """ +@cython.cdivision(True) +cdef run_spring(int iterations, dimension_t _dim, double* pos, int* edges, int n, int m, bint height): + r""" Find a locally optimal layout for this graph, according to the constraints that neighboring nodes want to be a fixed distance from each other, and non-neighboring nodes always repel. @@ -229,7 +238,10 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he INPUT: iterations -- number of steps to take - dim -- number of dimensions of freedom + _dim -- number of dimensions of freedom. Provide a value of type + `D_TWO` for 2 dimensions, or type `D_THREE` for three + dimensions. The actual value does not matter: only its + type is important. pos -- already initialized initial positions Each vertex is stored as [dim] consecutive doubles. These doubles are then placed consecutively in the array. @@ -249,18 +261,25 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he Robert Bradshaw """ + cdef int dim cdef int cur_iter, cur_edge cdef int i, j, x + if dimension_t is D_TWO: + dim = 2 + else: + dim = 3 + # k -- the equilibrium distance between two adjacent nodes cdef double t = 1, dt = t/(1e-20 + iterations), k = sqrt(1.0/n) - cdef double square_dist, force, scale + cdef double square_dist, dist, force, scale cdef double* disp_i cdef double* disp_j - cdef double* delta + cdef double delta[3] + cdef double d_tmp + cdef double xx,yy,zz - cdef double* disp = check_allocarray(n+1, dim * sizeof(double)) - delta = &disp[n*dim] + cdef double* disp = check_allocarray(n, dim * sizeof(double)) if height: update_dim = dim-1 @@ -269,57 +288,92 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he sig_on() - for cur_iter from 0 <= cur_iter < iterations: + for cur_iter in range(iterations): cur_edge = 1 # offset by one for fast checking against 2nd element first # zero out the disp vectors memset(disp, 0, n * dim * sizeof(double)) - for i from 0 <= i < n: + for i in range(n): disp_i = disp + (i*dim) - for j from i < j < n: + for j in range(i+1, n): disp_j = disp + (j*dim) - for x from 0 <= x < dim: + for x in range(dim): delta[x] = pos[i*dim+x] - pos[j*dim+x] - square_dist = delta[0] * delta[0] - for x from 1 <= x < dim: - square_dist += delta[x] * delta[x] + xx = delta[0] * delta[0] + yy = delta[1] * delta[1] + if dim == 2: + square_dist = xx+yy + else: + zz = delta[2] * delta[2] + square_dist = xx+yy+zz - if square_dist < 0.01: - square_dist = 0.01 + if square_dist < 0.0001: + square_dist = 0.0001 # they repel according to the (capped) inverse square law - force = k*k/square_dist + force = (k*k)/square_dist # and if they are neighbors, attract according Hooke's law if edges[cur_edge] == j and edges[cur_edge-1] == i: - force -= sqrt(square_dist)/k + if dim == 2: + dist = sqrt_approx(delta[0],delta[1],xx,yy) + else: + dist = sqrt(square_dist) + force -= dist/k cur_edge += 2 # add this factor into each of the involved points - for x from 0 <= x < dim: - disp_i[x] += delta[x] * force - disp_j[x] -= delta[x] * force + for x in range(dim): + d_tmp = delta[x] * force + disp_i[x] += d_tmp + disp_j[x] -= d_tmp # now update the positions - for i from 0 <= i < n: + for i in range(n): disp_i = disp + (i*dim) square_dist = disp_i[0] * disp_i[0] - for x from 1 <= x < dim: + for x in range(1, dim): square_dist += disp_i[x] * disp_i[x] - scale = t / (1 if square_dist < 0.01 else sqrt(square_dist)) + if square_dist < 0.0001: + scale = 1 + else: + scale = t/sqrt(square_dist) - for x from 0 <= x < update_dim: + for x in range(update_dim): pos[i*dim+x] += disp_i[x] * scale t -= dt sig_off() - sig_free(disp) +@cython.cdivision(True) +cdef inline double sqrt_approx(double x,double y,double xx,double yy): + r""" + Approximation of sqrt(x^2+y^2). + + Assuming that x>y>0, it is a taylor expansion at x^2. To see how 'bad' the + approximation is:: + + sage: def dist(x,y): + ....: x = abs(x) + ....: y = abs(y) + ....: return max(x,y) + min(x,y)**2/(2*max(x,y)) + + sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*pi)) + Graphics object consisting of 2 graphics primitives + """ + if xx Date: Sat, 16 Sep 2017 23:31:20 +0200 Subject: [PATCH 068/218] handle period p > 1 --- .../rings/asymptotic/asymptotic_expansion_generators.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 937b7089424..b263e6a026b 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1040,6 +1040,12 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) """ + if period > 1: + tau_p = None if tau is None else tau**p + aperiodic_result = ImplicitExpansion(var, phi=lambda u: phi(u^(1/p))^p, + period=1, tau=tau_p, precision=precision) + return (aperiodic_result)^(1/p) + from sage.symbolic.ring import SR y = SR('y') From 0b75114174fadd5536d0eab7582ab2ea7e759277 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sun, 17 Sep 2017 00:45:37 +0200 Subject: [PATCH 069/218] fix imports and other errors --- .../asymptotic_expansion_generators.py | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index b263e6a026b..bd345006d00 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1041,17 +1041,22 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): """ if period > 1: - tau_p = None if tau is None else tau**p - aperiodic_result = ImplicitExpansion(var, phi=lambda u: phi(u^(1/p))^p, - period=1, tau=tau_p, precision=precision) - return (aperiodic_result)^(1/p) + tau_p = None if tau is None else tau**period + aperiodic_result = asymptotic_expansions.ImplicitExpansion(var, + phi=lambda u: phi(u**(1/period))**period, + period=1, tau=tau_p, precision=precision) + return (aperiodic_result)**(1/period) from sage.symbolic.ring import SR + from sage.rings.rational_field import QQ + from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing + from sage.arith.srange import srange y = SR('y') + one_half = QQ(1)/2 if tau is None: u = SR('u') - positive_solution = filter(lambda s: s.rhs() > 0, solve(phi(u) - u*phi(u).diff(u), u)) + positive_solution = filter(lambda s: s.rhs() > 0, (phi(u) - u*phi(u).diff(u)).solve(u)) if len(positive_solution) == 1: tau = positive_solution[0].rhs() else: @@ -1067,28 +1072,30 @@ def H(y): precision = A.default_prec Z = A.gen() - def ansatz(precision=precision): - if precision < 1: - return O(A(1)) - if precision == 1: - return O((1/Z)^(1/2)) - return (-sqrt(2*tau/phi(tau)/H(y).diff(y,2)(y=tau)) * (1/Z)^(1/2) - + sum([SR("d{}".format(j)) * (1/Z)^(j/2) for j in srange(2, precision)]) - + O((1/Z)^(precision/2))) + def ansatz(prec=precision): + if prec < 1: + return A(1).O() + if prec == 1: + return ((1/Z)**one_half).O() + return (-(2*tau/phi(tau)/H(y).diff(y,2)(y=tau)).sqrt() * (1/Z)**one_half + + sum([SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)]) + + ((1/Z)**(prec * one_half)).O()) + # we compare coefficients between a "single" Z and the # following expansion, this allows us to compute the constants d_j - z_expansion = sum([H(z).diff(z, k)(z=tau)/factorial(k) * - ansatz(precision=precision+2-k)^k - for k in srange(2, precision)]) + O((1/Z)^(precision/2)) + z = SR('z') + z_expansion = sum([H(z).diff(z, k)(z=tau)/k.factorial() * + ansatz(prec=precision+2-k)**k + for k in srange(2, precision)]) + ((1/Z)**(precision * one_half)).O() solution_dict = dict() for k in srange(2, precision-1): - coef = z_expansion.monomial_coefficient((1/Z)^((k+1)/2)) + coef = z_expansion.monomial_coefficient((1/Z)**((k+1) * one_half)) current_var = SR('d{k}'.format(k=k)) solution_dict[current_var] = coef.subs(solution_dict).solve(current_var)[0].rhs() - return A(tau) + ansatz(precision=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) + return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) def _sa_coefficients_lambda_(K, beta=0): r""" From a13e716cfd3f908ee6ee36f360d98df204af4ee9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sun, 17 Sep 2017 00:46:15 +0200 Subject: [PATCH 070/218] add doctest for period --- .../rings/asymptotic/asymptotic_expansion_generators.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index bd345006d00..05d3aaeaccd 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1039,6 +1039,13 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) + :: + + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + u^2, + ....: period=2, precision=8) + 1 - Z^(-1/2) + 1/2*Z^(-1) - 1/2*Z^(-3/2) + 3/8*Z^(-2) - + 3/8*Z^(-5/2) + 5/16*Z^(-3) + O(Z^(-7/2)) + """ if period > 1: tau_p = None if tau is None else tau**period From ed02cfb81b50b180110c40e19d062146e1242824 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 17 Sep 2017 19:54:29 +0200 Subject: [PATCH 071/218] trac #18395: reviewers comments on the documentation --- src/sage/graphs/generic_graph_pyx.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 6a480b78243..b9e6b863c53 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -353,10 +353,10 @@ cdef run_spring(int iterations, dimension_t _dim, double* pos, int* edges, int n @cython.cdivision(True) cdef inline double sqrt_approx(double x,double y,double xx,double yy): r""" - Approximation of sqrt(x^2+y^2). + Approximation of `\sqrt(x^2+y^2)`. - Assuming that x>y>0, it is a taylor expansion at x^2. To see how 'bad' the - approximation is:: + Assuming that `x > y > 0`, it is a taylor expansion at `x^2`. To see how + 'bad' the approximation is:: sage: def dist(x,y): ....: x = abs(x) From d4931f0ec98fbe21b6edf6ee672013df42221f3e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 18 Sep 2017 08:37:06 +0200 Subject: [PATCH 072/218] move loop into all check, thanks Travis! --- src/sage/combinat/tableau.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index dbbbd56b72c..fbf980d4a4a 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -3509,11 +3509,7 @@ def is_key_tableau(self): False """ T_conj = self.conjugate() - for i in range(1, len(T_conj)): - if not all(x in T_conj[i-1] for x in T_conj[i]): - return False - return True - + return all(x in T_conj[i-1] for i in range(1, len(T_conj)) for x in T_conj[i]) def right_key_tableau(self): """ From bcafc89f1be0e8fb613579f7d0c00010593b19f1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 18 Sep 2017 11:03:00 +0200 Subject: [PATCH 073/218] changes in doc (raw string; period implemented) --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 05d3aaeaccd..257bc2a2e91 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -994,7 +994,7 @@ def inverse_gamma_derivative(shift, r): @staticmethod def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): - """ + r""" Return the singular expansion for a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))`. @@ -1009,7 +1009,7 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): - ``period`` -- (default: 1) the period `p` of the function `\Phi`, i.e., the largest integer `p` such that the power series `\Phi(u)` can be written as `\Psi(u^p)`, - where `\Psi` is another power series. (Not yet implemented) + where `\Psi` is another power series. - ``tau`` -- (default: ``None``) the unique positive solution `\tau` of the characteristic equation, `\Phi(\tau) - \tau \Phi'(\tau) = 0`. If ``None``, From 3cdb07c4ab1b9d5274d68d224209ce0a180a1b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 18 Sep 2017 14:44:04 +0200 Subject: [PATCH 074/218] trac 23671 fix wrong syntax for raise --- src/sage/modular/hypergeometric_motive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 08958c36be5..1524dc73216 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -289,7 +289,7 @@ def alpha_to_cyclotomic(alpha): try: Alpha.remove(QQ((k, d))) except ValueError: - raise ValueError, "multiplicities not balanced" + raise ValueError("multiplicities not balanced") cyclo.append(d) return sorted(cyclo) From db4764b4be212b611b627fcf786212b3991ae697 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 18 Sep 2017 15:54:28 +0200 Subject: [PATCH 075/218] Fix InheritComparisonClasscallMetaclass.__new__() --- src/sage/misc/inherit_comparison.pyx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/inherit_comparison.pyx b/src/sage/misc/inherit_comparison.pyx index 7c9bd1a0342..fc360533cad 100644 --- a/src/sage/misc/inherit_comparison.pyx +++ b/src/sage/misc/inherit_comparison.pyx @@ -85,5 +85,15 @@ cdef class InheritComparisonMetaclass(type): inherit_comparison(t, b) super(InheritComparisonMetaclass, self).__init__(*args) -class InheritComparisonClasscallMetaclass(InheritComparisonMetaclass, ClasscallMetaclass): - pass + +class InheritComparisonClasscallMetaclass(ClasscallMetaclass, InheritComparisonMetaclass): + """ + Combine :class:`ClasscallMetaclass` with + :class:`InheritComparisonMetaclass`. + + TESTS:: + + sage: from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass as M + sage: M.__new__(M, "myclass", (object,), {}) + + """ From 021188a3c9f6517baa8a8138caf4686613fa71e1 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 19 Sep 2017 17:19:59 +0200 Subject: [PATCH 076/218] trac #18395: specific doctests for 32 and 64 bits machines --- src/sage/graphs/generic_graph_pyx.pyx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index b9e6b863c53..cdc06afd0be 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -108,9 +108,12 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G) - {0: [0.00..., 0.04...], - ... - 902: [-0.47..., -0.10...]} + {0: [0.00..., 0.03...], # 32-bit + ... # 32-bit + 902: [-0.48..., -0.10...]} # 32-bit + {0: [0.00..., 0.04...], # 64-bit + ... # 64-bit + 902: [-0.47..., -0.10...]} # 64-bit With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -126,9 +129,12 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G, by_component = True) - {0: [2.21..., -0.00...], - ... - 902: [3.07..., 0.86...]} + {0: [2.22..., -0.00...], # 32-bit + ... # 32-bit + 902: [3.07..., 0.86...]} # 32-bit + {0: [2.21..., -0.00...], # 64-bit + ... # 64-bit + 902: [3.07..., 0.86...]} # 64-bit """ if by_component: From 1401a24b8d300c8714b03cefc4a2da41e5b1cabd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 19 Sep 2017 18:26:13 +0200 Subject: [PATCH 077/218] 23865: untested --> not tested --- src/sage/rings/polynomial/omega.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 1bd7491692e..1e342dd7c77 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -550,7 +550,7 @@ def Omega_ge(a, exponents): TESTS:: - sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # untested (too long, 1 min) + sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # not tested (too long, 1 min) 27837 :: From 12734e4b684ac9eac6f7484169bb7c7e37ba5d62 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 19 Sep 2017 18:26:25 +0200 Subject: [PATCH 078/218] 23865: add one long time doctest --- src/sage/rings/polynomial/omega.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 1e342dd7c77..80813b856e4 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -550,6 +550,8 @@ def Omega_ge(a, exponents): TESTS:: + sage: Omega_ge(0, (2, 2, 1, 1, 1, -1, -1))[0].number_of_terms() # long time + 1695 sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # not tested (too long, 1 min) 27837 From 2c17000b31537538acf2bd1b41c778fca8822a02 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 20 Sep 2017 17:51:34 +0200 Subject: [PATCH 079/218] Trac #23872: PEP8 --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 257bc2a2e91..b8132c8d191 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1084,11 +1084,10 @@ def ansatz(prec=precision): return A(1).O() if prec == 1: return ((1/Z)**one_half).O() - return (-(2*tau/phi(tau)/H(y).diff(y,2)(y=tau)).sqrt() * (1/Z)**one_half + sum([SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)]) + return (-(2*tau/phi(tau)/H(y).diff(y, 2)(y=tau)).sqrt() * (1/Z)**one_half + ((1/Z)**(prec * one_half)).O()) - # we compare coefficients between a "single" Z and the # following expansion, this allows us to compute the constants d_j z = SR('z') From 987a3081dd7f959772ee138abfbc61cf54915642 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 20 Sep 2017 17:51:51 +0200 Subject: [PATCH 080/218] Trac #23872: sum of sequence Replace sum of list of sequence by sum of sequence --- .../rings/asymptotic/asymptotic_expansion_generators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index b8132c8d191..ae2d961a99a 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1084,16 +1084,16 @@ def ansatz(prec=precision): return A(1).O() if prec == 1: return ((1/Z)**one_half).O() - + sum([SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)]) return (-(2*tau/phi(tau)/H(y).diff(y, 2)(y=tau)).sqrt() * (1/Z)**one_half + + sum(SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)) + ((1/Z)**(prec * one_half)).O()) # we compare coefficients between a "single" Z and the # following expansion, this allows us to compute the constants d_j z = SR('z') - z_expansion = sum([H(z).diff(z, k)(z=tau)/k.factorial() * - ansatz(prec=precision+2-k)**k - for k in srange(2, precision)]) + ((1/Z)**(precision * one_half)).O() + z_expansion = sum(H(z).diff(z, k)(z=tau)/k.factorial() * + ansatz(prec=precision+2-k)**k + for k in srange(2, precision)) + ((1/Z)**(precision * one_half)).O() solution_dict = dict() for k in srange(2, precision-1): From 5739955aee97bc0baccddf7484b79fe29822dd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 21 Sep 2017 02:04:59 +0700 Subject: [PATCH 081/218] Base change factorization to the right parent Base change actually changes the ring in which the factors live, not the base ring of the polynomial ring. --- src/sage/rings/fraction_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 007525a3d9b..741cfc24101 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -856,7 +856,7 @@ def _factor_univariate_polynomial(self, f): # The default implementation would try to convert this element to singular and factor there. # This fails silently over some base fields, see #23642, so we convert # to the function field and factor there. - return f.change_ring(self.function_field()).factor().base_change(self) + return f.change_ring(self.function_field()).factor().base_change(f.parent()) class FractionFieldEmbedding(DefaultConvertMap_unique): From f684cb0e4834a0041da29ef7a1f8f0b01cf84994 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 20 Sep 2017 12:04:33 +0200 Subject: [PATCH 082/218] Implement _element_constructor_ for Homset --- src/sage/categories/homset.py | 185 ++++++++++++++++------------------ src/sage/quivers/morphism.py | 2 +- 2 files changed, 89 insertions(+), 98 deletions(-) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 3013ab20587..bd9ef682266 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -508,6 +508,7 @@ def end(X, f): """ return End(X)(f) + class Homset(Set_generic): """ The class for collections of morphisms in a category. @@ -708,74 +709,6 @@ def __bool__(self): __nonzero__ = __bool__ - def _generic_convert_map(self, S, category=None): - """ - Return a generic map from a given homset to ``self``. - - INPUT: - - - ``S`` -- a homset - - - ``category`` -- a category - - OUTPUT: - - A map (by default: a Call morphism) from ``S`` to ``self``. - - EXAMPLES: - - By :trac:`14711`, conversion and coerce maps should be copied - before using them outside of the coercion system:: - - sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups()) - sage: P. = ZZ[] - sage: f = P.hom([2*t]) - sage: phi = H._generic_convert_map(f.parent()); phi - Call morphism: - From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring - To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups - sage: H._generic_convert_map(f.parent())(f) - Composite map: - From: Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: (map internal to coercion system -- copy before use) - Polynomial base injection morphism: - From: Integer Ring - To: Univariate Polynomial Ring in t over Integer Ring - then - Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring - Defn: t |--> 2*t - then - (map internal to coercion system -- copy before use) - Ring morphism: - From: Univariate Polynomial Ring in t over Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - sage: copy(H._generic_convert_map(f.parent())(f)) - Composite map: - From: Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: Polynomial base injection morphism: - From: Integer Ring - To: Univariate Polynomial Ring in t over Integer Ring - then - Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring - Defn: t |--> 2*t - then - Ring morphism: - From: Univariate Polynomial Ring in t over Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: Induced from base ring by - Natural morphism: - From: Integer Ring - To: Rational Field - """ - if self._element_constructor is None: - from sage.categories.morphism import CallMorphism - from sage.categories.homset import Hom - return CallMorphism(Hom(S, self)) - else: - return Parent._generic_convert_map(self, S, category) - def homset_category(self): """ Return the category that this is a Hom in, i.e., this is typically @@ -789,7 +722,7 @@ def homset_category(self): """ return self.__category - def __call__(self, x=None, y=None, check=True, **options): + def _element_constructor_(self, x, check=None, **options): r""" Construct a morphism in this homset from ``x`` if possible. @@ -827,8 +760,8 @@ def __call__(self, x=None, y=None, check=True, **options): From: Symmetric group of order 6! as a permutation group To: Symmetric group of order 7! as a permutation group - Also note that making a copy of the resulting map will automatically - make strengthened copies of the composed maps:: + Also note that making a copy of the resulting map will automatically + make strengthened copies of the composed maps:: sage: copy(H(phi)) Composite map: @@ -869,6 +802,70 @@ def __call__(self, x=None, y=None, check=True, **options): sage: f(1), f(2), f(3) (2/3, 2/3, 2/3) + By :trac:`14711`, conversion and coerce maps should be copied + before using them outside of the coercion system:: + + sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups()) + sage: P. = ZZ[] + sage: f = P.hom([2*t]) + sage: phi = H._generic_convert_map(f.parent()); phi + Conversion map: + From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring + To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups + sage: H._generic_convert_map(f.parent())(f) + Composite map: + From: Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: (map internal to coercion system -- copy before use) + Polynomial base injection morphism: + From: Integer Ring + To: Univariate Polynomial Ring in t over Integer Ring + then + Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + Defn: t |--> 2*t + then + (map internal to coercion system -- copy before use) + Ring morphism: + From: Univariate Polynomial Ring in t over Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + sage: copy(H._generic_convert_map(f.parent())(f)) + Composite map: + From: Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: Polynomial base injection morphism: + From: Integer Ring + To: Univariate Polynomial Ring in t over Integer Ring + then + Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + Defn: t |--> 2*t + then + Ring morphism: + From: Univariate Polynomial Ring in t over Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: Induced from base ring by + Natural morphism: + From: Integer Ring + To: Rational Field + + TESTS:: + + sage: G. = FreeGroup() + sage: H = Hom(G, G) + sage: H(H.identity()) + Identity endomorphism of Free Group on generators {x, y, z} + sage: H() + Traceback (most recent call last): + ... + TypeError: unable to convert 0 to an element of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + sage: H("whatever") + Traceback (most recent call last): + ... + TypeError: unable to convert 'whatever' to an element of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + sage: H(H.identity(), foo="bar") + Traceback (most recent call last): + ... + NotImplementedError: no keywords are implemented for constructing elements of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + AUTHORS: - Robert Bradshaw, with changes by Nicolas M. Thiery @@ -877,36 +874,30 @@ def __call__(self, x=None, y=None, check=True, **options): # TODO: this is specific for ModulesWithBasis; generalize # this to allow homsets and categories to provide more # morphism constructors (on_algebra_generators, ...) - if 'on_basis' or 'diagonal' in options: - return self.__call_on_basis__(category = self.homset_category(), - **options) - else: - raise NotImplementedError + try: + call_with_keywords = self.__call_on_basis__ + except AttributeError: + raise NotImplementedError("no keywords are implemented for constructing elements of {}".format(self)) + options.setdefault("category", self.homset_category()) + return call_with_keywords(**options) - assert x is not None if isinstance(x, morphism.Morphism): - if x.parent() is self: - return x - elif x.parent() == self: - x._set_parent(self) # needed due to non-uniqueness of homsets - return x - else: - if x.domain() != self.domain(): - mor = x.domain()._internal_coerce_map_from(self.domain()) - if mor is None: - raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s"%(x,self)) - x = x * mor - if x.codomain() != self.codomain(): - mor = self.codomain()._internal_coerce_map_from(x.codomain()) - if mor is None: - raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)) - x = mor * x - return x - - if isinstance(x, (types.FunctionType, types.MethodType, ConstantFunction)): + if x.domain() != self.domain(): + mor = x.domain()._internal_coerce_map_from(self.domain()) + if mor is None: + raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s"%(x,self)) + x = x * mor + if x.codomain() != self.codomain(): + mor = self.codomain()._internal_coerce_map_from(x.codomain()) + if mor is None: + raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)) + x = mor * x + return x + + if callable(x): return self.element_class_set_morphism(self, x) - raise TypeError("Unable to coerce x (=%s) to a morphism in %s"%(x,self)) + raise TypeError("unable to convert {!r} to an element of {}".format(x, self)) @lazy_attribute def _abstract_element_class(self): diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index a0ed5e77aa7..b6cd04e27bd 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -591,7 +591,7 @@ def _assert_valid_hom(self): sage: f = S.hom(maps2, S) # indirect doctest Traceback (most recent call last): ... - TypeError: Unable to coerce x (={...}) to a morphism in Dimension 2 QuiverHomSpace + TypeError: unable to convert {2: [1, -1], 3: 1} to an element of Dimension 2 QuiverHomSpace """ # Check that the domain and codomains dimensions add correctly totaldim = 0 From b87032e4aad9ce2064ac46ed365ff93c0c4b0e57 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 21 Sep 2017 15:04:56 +0200 Subject: [PATCH 083/218] In parent(x), do not call x.parent() --- src/sage/combinat/partition.py | 11 ----------- src/sage/structure/element.pxd | 13 +------------ 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index feb04f7e17c..a221cf9c74e 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4211,17 +4211,6 @@ def k_conjugate(self, k): """ return Partition(self.k_skew(k).conjugate().row_lengths()) -# def parent(self): -# """ -# Returns the combinatorial class of partitions of ``sum(self)``. -# -# EXAMPLES:: -# -# sage: Partition([3,2,1]).parent() -# Partitions of the integer 6 -# """ -# return Partitions(sum(self[:])) - def arms_legs_coeff(self, i, j): r""" This is a statistic on a cell `c = (i,j)` in the diagram of partition diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 819963968a9..43fe75d9ee2 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -19,9 +19,6 @@ cpdef inline parent(x): - If ``x`` is a Sage :class:`Element`, return ``x.parent()``. - - If ``x`` has a ``parent`` method and ``x`` does not have an - ``__int__`` or ``__float__`` method, return ``x.parent()``. - - Otherwise, return ``type(x)``. .. SEEALSO:: @@ -62,15 +59,7 @@ cpdef inline parent(x): """ if isinstance(x, Element): return (x)._parent - # Fast check for "number" types, including int and float - if PyNumber_Check(x): - return type(x) - try: - p = x.parent - except AttributeError: - return type(x) - else: - return p() + return type(x) cdef inline int classify_elements(left, right): From 79c3c47e7d730ba39dbe4316b00457e4b905433f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 15:23:59 +0200 Subject: [PATCH 084/218] remove separate handling of period --- .../asymptotic_expansion_generators.py | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index ae2d961a99a..f15eb45882d 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -993,7 +993,7 @@ def inverse_gamma_derivative(shift, r): @staticmethod - def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): + def ImplicitExpansion(var, phi, tau=None, precision=None): r""" Return the singular expansion for a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))`. @@ -1007,10 +1007,6 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): `0` need to be non-negative, and it needs to satisfy `\Phi(0) \neq 0`. This is not checked! - - ``period`` -- (default: 1) the period `p` of the function `\Phi`, i.e., the largest - integer `p` such that the power series `\Phi(u)` can be written as `\Psi(u^p)`, - where `\Psi` is another power series. - - ``tau`` -- (default: ``None``) the unique positive solution `\tau` of the characteristic equation, `\Phi(\tau) - \tau \Phi'(\tau) = 0`. If ``None``, then `\tau` is tried to be determined automatically. @@ -1039,21 +1035,7 @@ def ImplicitExpansion(var, phi, period=1, tau=None, precision=None): 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) - :: - - sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + u^2, - ....: period=2, precision=8) - 1 - Z^(-1/2) + 1/2*Z^(-1) - 1/2*Z^(-3/2) + 3/8*Z^(-2) - - 3/8*Z^(-5/2) + 5/16*Z^(-3) + O(Z^(-7/2)) - """ - if period > 1: - tau_p = None if tau is None else tau**period - aperiodic_result = asymptotic_expansions.ImplicitExpansion(var, - phi=lambda u: phi(u**(1/period))**period, - period=1, tau=tau_p, precision=precision) - return (aperiodic_result)**(1/period) - from sage.symbolic.ring import SR from sage.rings.rational_field import QQ from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing From 7a75adc8b6fa8547f918bd97b860c74ea46d519a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 15:43:24 +0200 Subject: [PATCH 085/218] improve documentation --- .../asymptotic_expansion_generators.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index f15eb45882d..36fc84a56c3 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -998,18 +998,23 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): Return the singular expansion for a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))`. + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. + + The fundamental constant `\tau` is assumed to be the unique positive + solution of `\Phi(\tau) - \Phi'(\tau) = 0`. + INPUT: - ``var`` -- a string for the variable name. - - ``phi`` -- the function `\Phi`, which is assumed to be - not an affine function, the coefficients of the expansion around - `0` need to be non-negative, and it needs to satisfy - `\Phi(0) \neq 0`. This is not checked! + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. - - ``tau`` -- (default: ``None``) the unique positive solution `\tau` of - the characteristic equation, `\Phi(\tau) - \tau \Phi'(\tau) = 0`. If ``None``, - then `\tau` is tried to be determined automatically. + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is tried to + be determined automatically. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. From 588ffefd04b33cf50837a218fbbd5f30c70f7e50 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 15:43:35 +0200 Subject: [PATCH 086/218] check phi for requirements --- .../rings/asymptotic/asymptotic_expansion_generators.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 36fc84a56c3..4e87b2ff861 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1045,11 +1045,13 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): from sage.rings.rational_field import QQ from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing from sage.arith.srange import srange - y = SR('y') + y, u = SR('y'), SR('u') one_half = QQ(1)/2 + if phi(0).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): + raise ValueError('The function phi does not satisfy the requirements') + if tau is None: - u = SR('u') positive_solution = filter(lambda s: s.rhs() > 0, (phi(u) - u*phi(u).diff(u)).solve(u)) if len(positive_solution) == 1: tau = positive_solution[0].rhs() From 022a19da4cf59f3bcc25301aeeab7412b373a9a4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 15:49:20 +0200 Subject: [PATCH 087/218] tests for phi; don't pass int(0) to phi --- .../asymptotic/asymptotic_expansion_generators.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 4e87b2ff861..8035a63c437 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1040,6 +1040,17 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) + TESTS:: + + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 42*u, precision=5) + Traceback (most recent call last): + ... + ValueError: The function phi does not satisfy the requirements + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 42*u + u^2, precision=5) + Traceback (most recent call last): + ... + ValueError: The function phi does not satisfy the requirements + """ from sage.symbolic.ring import SR from sage.rings.rational_field import QQ @@ -1048,7 +1059,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): y, u = SR('y'), SR('u') one_half = QQ(1)/2 - if phi(0).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): + if phi(QQ(0)).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): raise ValueError('The function phi does not satisfy the requirements') if tau is None: From c0c2772fd9252d6401f7c14ebbaf1bb3d40d758f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 15:54:30 +0200 Subject: [PATCH 088/218] test: tau cannot be determined --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 8035a63c437..5c46958dbc3 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1050,6 +1050,10 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): Traceback (most recent call last): ... ValueError: The function phi does not satisfy the requirements + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + u^2 + u^42, precision=5) + Traceback (most recent call last): + ... + ValueError: Fundamental constant tau could not be determined """ from sage.symbolic.ring import SR From b656293e3fcecf5a961d7fc93deb7eb67dc1b74c Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 17:20:09 +0200 Subject: [PATCH 089/218] add more examples to ImplicitExpansion --- .../asymptotic_expansion_generators.py | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 5c46958dbc3..f06884f2b70 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1034,12 +1034,56 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): for the variable `z\to\rho`. - EXAMPLES:: + EXAMPLES: + + We can, for example, determine the singular expansion of the well-known + tree function `T` (which satisfies `T(z) = z \exp(T(z))`):: sage: asymptotic_expansions.ImplicitExpansion('Z', phi=exp, precision=8) 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) + Another classical example in this context is the generating function `B(z)` + enumerating binary trees with respect to the number of inner nodes. The + function satisfies `B(z) = z (1 + 2B(z) + B(z)^2)`, which can also be + solved explicitly, yielding `B(z) = \frac{1 - \sqrt{1 - 4z}}{2z} - 1`. We + compare the expansions from both approaches:: + + sage: def B(z): + ....: return (1 - sqrt(1 - 4*z))/(2*z) - 1 + sage: A. = AsymptoticRing('Z^QQ', QQ, default_prec=3) + sage: B((1-1/Z)/4) + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) + - 2*Z^(-5/2) + O(Z^(-3)) + sage: asymptotic_expansions.ImplicitExpansion(Z, phi=lambda u: 1 + 2*u + u^2, precision=7) + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) + - 2*Z^(-5/2) + O(Z^(-3)) + + Neither `\tau` nor `\Phi` have to be known explicitly, they can + also be passed symbolically:: + + sage: tau = var('tau') + sage: phi = function('phi') + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=phi, tau=tau, precision=3) # long time + tau + (-sqrt(2)*sqrt(-tau*phi(tau)^2/(2*tau*diff(phi(tau), tau)^2 + - tau*phi(tau)*diff(phi(tau), tau, tau) + - 2*phi(tau)*diff(phi(tau), tau))))*Z^(-1/2) + O(Z^(-1)) + + Note that we do not check whether a passed `\tau` actually + satisfies the requirements. Only the first of the following + expansions is correct:: + + sage: asymptotic_expansion.ImplicitExpansion('Z', + ....: phi=lambda u: 1 + 2*u + u^2, precision=5) # correct expansion + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + O(Z^(-2)) + sage: asymptotic_expansion.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=2, precision=5) + Traceback (most recent call last): + ... + ZeroDivisionError: Symbolic division by zero + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=3, precision=5) + 3 - 4*I*sqrt(3)*Z^(-1/2) + 6*I*sqrt(3)*Z^(-3/2) + O(Z^(-2)) + + TESTS:: sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 42*u, precision=5) From 700c291046c65bc18a77e4847f7b50f810361f6c Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 17:32:01 +0200 Subject: [PATCH 090/218] references, toc --- .../asymptotic_expansion_generators.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index f06884f2b70..8a52ba319fe 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -43,6 +43,9 @@ * - :meth:`~AsymptoticExpansionGenerators.SingularityAnalysis` - an asymptotic expansion obtained by singularity analysis + * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion` + - the singular expansion of a function `y(z)` satisfying `y(z) = z \Phi(y(z))` + AUTHORS: @@ -56,6 +59,11 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +REFERENCES: + +.. [FS2009] Philippe Flajolet and Robert Sedgewick, + `Analytic combinatorics `_. + Cambridge University Press, Cambridge, 2009. Classes and Methods =================== @@ -92,6 +100,7 @@ class AsymptoticExpansionGenerators(SageObject): - :meth:`~log_Stirling` - :meth:`~Binomial_kn_over_n` - :meth:`~SingularityAnalysis` + - :meth:`~ImplicitExpansion` """ @staticmethod @@ -719,11 +728,6 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, See [FS2009]_ together with the `errata list `_. - REFERENCES: - - .. [FS2009] Philippe Flajolet and Robert Sedgewick, - `Analytic combinatorics `_. - Cambridge University Press, Cambridge, 2009. TESTS:: @@ -1003,7 +1007,10 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): `\Phi(0) \neq 0`. The fundamental constant `\tau` is assumed to be the unique positive - solution of `\Phi(\tau) - \Phi'(\tau) = 0`. + solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + All details are given in Chapter VI.7 of [FS2009]_; also see the corresponding + `errata list `_. INPUT: From 68e5f88d594224a2918294a148afb18c491010fb Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 18:38:25 +0200 Subject: [PATCH 091/218] fix doctests --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 8a52ba319fe..e4818d574e3 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1080,10 +1080,10 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): satisfies the requirements. Only the first of the following expansions is correct:: - sage: asymptotic_expansion.ImplicitExpansion('Z', + sage: asymptotic_expansions.ImplicitExpansion('Z', ....: phi=lambda u: 1 + 2*u + u^2, precision=5) # correct expansion 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + O(Z^(-2)) - sage: asymptotic_expansion.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=2, precision=5) + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=2, precision=5) Traceback (most recent call last): ... ZeroDivisionError: Symbolic division by zero From d0a25639bd52875c87881be6ba30c9bd1d284384 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 18:39:13 +0200 Subject: [PATCH 092/218] separate method for determining tau --- .../asymptotic_expansion_generators.py | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index e4818d574e3..644399d816b 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1118,11 +1118,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): raise ValueError('The function phi does not satisfy the requirements') if tau is None: - positive_solution = filter(lambda s: s.rhs() > 0, (phi(u) - u*phi(u).diff(u)).solve(u)) - if len(positive_solution) == 1: - tau = positive_solution[0].rhs() - else: - raise ValueError('Fundamental constant tau could not be determined') + tau = _fundamental_constant_(phi=phi) def H(y): return tau/phi(tau) - y/phi(y) @@ -1158,6 +1154,43 @@ def ansatz(prec=precision): return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) +def _fundamental_constant_(phi): + r""" + Return the fundamental constant `\tau` occurring in the analysis of + implicitly defined functions. + + For a function `y(z)` satisfying `y(z) = z \Phi(y(z))`, the fundamental + constant `\tau` is the unique positive solution of the equation + `\Phi(\tau) - \tau \Phi'(\tau) = 0`. + + INPUT: + + - ``phi`` -- the function `\Phi`. + + .. SEEALSO:: + + :meth:`AsymptoticExpansionGenerators.ImplicitExpansion` + :meth:`AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart` + + TESTS:: + + sage: from sage.rings.asymptotic.asymptotic_expansion_generators \ + ....: import _fundamental_constant_ + sage: _fundamental_constant_(phi=exp) + 1 + sage: _fundamental_constant_(phi=lambda u: 1 + u^2) + 1 + sage: _fundamental_constant_(phi=lambda u: 1 + 2*u + 2*u^2) + 1/2*sqrt(2) + + """ + from sage.symbolic.ring import SR + u = SR('u') + positive_solution = filter(lambda s: s.rhs() > 0, (phi(u) - u*phi(u).diff(u)).solve(u)) + if len(positive_solution) == 1: + return positive_solution[0].rhs() + raise ValueError('Fundamental constant tau could not be determined') + def _sa_coefficients_lambda_(K, beta=0): r""" Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis. From b807e053e151eb78edcfd5509f40512d86b22635 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 18:40:08 +0200 Subject: [PATCH 093/218] new method: ImplictExpansionPeriodicPart --- .../asymptotic_expansion_generators.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 644399d816b..c05cf1291f5 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1154,6 +1154,91 @@ def ansatz(prec=precision): return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) + + @staticmethod + def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): + r""" + Return the singular expansion for the periodic part of a function `y(z)` + defined implicitly by `y(z) = z \Phi(y(z))`. + + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. For an integer `p`, `\Phi` is called `p`-periodic + if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` + where `p` is maximal. + + The fundamental constant `\tau` is assumed to be the unique positive + solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + If `\Phi` is `p`-periodic, then we have `y(z) = z g(z^p)`. This method + returns the singular expansion of `g(z)`. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. + + - ``period`` -- (default: `1`) the period of the function `\Phi`. See + the extended description for details. + + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is tried to + be determined automatically. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + In the given case, the radius of convergence of the function of + interest is known to be `\rho = \tau/\Phi(\tau)`. For technical + reasons, the variable in the returned asymptotic expansion + represents a singular element of the form `(1 - z/\rho)^{-1}`, + for the variable `z\to\rho`. + + + EXAMPLES: + + The generating function enumerating binary trees with respect to + tree size satisfies `B(z) = z (1 + B(z)^2)`. This function can be + written as `B(z) = z g(z^2)`, and as `B(z)` can be determined + explicitly we have `g(z) = \frac{1 - \sqrt{1 - 4z}{2z}}`. We + compare the corresponding expansions:: + + sage: asymptotic_expansions.ImplicitExpansionPeriodicPart('Z', phi=lambda u: 1 + u^2, + ....: period=2, precision=7) + 2 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) - 2*Z^(-5/2) + O(Z^(-3)) + sage: def g(z): + ....: return (1 - sqrt(1 - 4*z))/(2*z) + sage: A. = AsymptoticRing('Z^QQ', QQ, default_prec=3) + sage: g((1 - 1/Z)/4) + 2 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) - 2*Z^(-5/2) + O(Z^(-3)) + + """ + from sage.symbolic.ring import SR + u = SR('u') + + if tau is None: + tau = _fundamental_constant_(phi=phi) + + tau_p = tau**period + aperiodic_expansion = asymptotic_expansions.ImplicitExpansion(var, + phi=lambda u: phi(u**(1/period))**period, + tau=tau_p, precision=precision) + + rho = tau/phi(tau) + Z = aperiodic_expansion.parent().gen() + return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) + + def _fundamental_constant_(phi): r""" Return the fundamental constant `\tau` occurring in the analysis of From a041106b9214a2b1d1fd6a3102968f5ead1f7aee Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 21 Sep 2017 18:44:00 +0200 Subject: [PATCH 094/218] fix typo, toc --- .../rings/asymptotic/asymptotic_expansion_generators.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index c05cf1291f5..1cfea4b2184 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -46,6 +46,9 @@ * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion` - the singular expansion of a function `y(z)` satisfying `y(z) = z \Phi(y(z))` + * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart` + - the singular expansion of the periodic part of a function `y(z)` satisfying `y(z) = z\Phi(y(z))` + AUTHORS: @@ -101,6 +104,7 @@ class AsymptoticExpansionGenerators(SageObject): - :meth:`~Binomial_kn_over_n` - :meth:`~SingularityAnalysis` - :meth:`~ImplicitExpansion` + - :meth:`~ImplicitExpansionPeriodicPart` """ @staticmethod @@ -1210,7 +1214,7 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): The generating function enumerating binary trees with respect to tree size satisfies `B(z) = z (1 + B(z)^2)`. This function can be written as `B(z) = z g(z^2)`, and as `B(z)` can be determined - explicitly we have `g(z) = \frac{1 - \sqrt{1 - 4z}{2z}}`. We + explicitly we have `g(z) = \frac{1 - \sqrt{1 - 4z}}{2z}`. We compare the corresponding expansions:: sage: asymptotic_expansions.ImplicitExpansionPeriodicPart('Z', phi=lambda u: 1 + u^2, From 4f3cfbe3878af0f480f1d14b7d549a1092dc1cf5 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:27:36 +0200 Subject: [PATCH 095/218] Trac #23872: rename _fundamental_constant_ Renamed _fundamental_constant_ to _fundamental_constant_implicit_function_ because is it is only fundamental w.r.t. this area --- .../asymptotic/asymptotic_expansion_generators.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 1cfea4b2184..4e270afd4d5 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1122,7 +1122,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): raise ValueError('The function phi does not satisfy the requirements') if tau is None: - tau = _fundamental_constant_(phi=phi) + tau = _fundamental_constant_implicit_function_(phi=phi) def H(y): return tau/phi(tau) - y/phi(y) @@ -1231,7 +1231,7 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): u = SR('u') if tau is None: - tau = _fundamental_constant_(phi=phi) + tau = _fundamental_constant_implicit_function_(phi=phi) tau_p = tau**period aperiodic_expansion = asymptotic_expansions.ImplicitExpansion(var, @@ -1243,7 +1243,7 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) -def _fundamental_constant_(phi): +def _fundamental_constant_implicit_function_(phi): r""" Return the fundamental constant `\tau` occurring in the analysis of implicitly defined functions. @@ -1264,12 +1264,12 @@ def _fundamental_constant_(phi): TESTS:: sage: from sage.rings.asymptotic.asymptotic_expansion_generators \ - ....: import _fundamental_constant_ - sage: _fundamental_constant_(phi=exp) + ....: import _fundamental_constant_implicit_function_ + sage: _fundamental_constant_implicit_function_(phi=exp) 1 - sage: _fundamental_constant_(phi=lambda u: 1 + u^2) + sage: _fundamental_constant_implicit_function_(phi=lambda u: 1 + u^2) 1 - sage: _fundamental_constant_(phi=lambda u: 1 + 2*u + 2*u^2) + sage: _fundamental_constant_implicit_function_(phi=lambda u: 1 + 2*u + 2*u^2) 1/2*sqrt(2) """ From 1212cbb7ee6ea5c31d127858551473ea07d12c2c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:29:14 +0200 Subject: [PATCH 096/218] Trac #23872: add experimental decorator As the output should change after #20050, an experimental warning is printed. --- .../asymptotic/asymptotic_expansion_generators.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 4e270afd4d5..6b35cd6ce9e 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -85,6 +85,7 @@ from __future__ import print_function from __future__ import absolute_import +from sage.misc.superseded import experimental from sage.structure.sage_object import SageObject @@ -1001,6 +1002,7 @@ def inverse_gamma_derivative(shift, r): @staticmethod + @experimental(20050) def ImplicitExpansion(var, phi, tau=None, precision=None): r""" Return the singular expansion for a function `y(z)` defined @@ -1051,6 +1053,10 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): tree function `T` (which satisfies `T(z) = z \exp(T(z))`):: sage: asymptotic_expansions.ImplicitExpansion('Z', phi=exp, precision=8) + doctest:warning + ... + FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/20050 for details. 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) @@ -1161,6 +1167,7 @@ def ansatz(prec=precision): @staticmethod def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): + @experimental(20050) r""" Return the singular expansion for the periodic part of a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))`. @@ -1219,6 +1226,10 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): sage: asymptotic_expansions.ImplicitExpansionPeriodicPart('Z', phi=lambda u: 1 + u^2, ....: period=2, precision=7) + doctest:warning + ... + FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/20050 for details. 2 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) - 2*Z^(-5/2) + O(Z^(-3)) sage: def g(z): ....: return (1 - sqrt(1 - 4*z))/(2*z) From ca161c2194f29a52f2053f62293072a7601b6606 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:30:42 +0200 Subject: [PATCH 097/218] Trac #23872: two rewordings --- .../asymptotic_expansion_generators.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 6b35cd6ce9e..d0a9fce48bf 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1012,8 +1012,8 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): `\Phi` is not allowed to be an affine-linear function and we require `\Phi(0) \neq 0`. - The fundamental constant `\tau` is assumed to be the unique positive - solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. All details are given in Chapter VI.7 of [FS2009]_; also see the corresponding `errata list `_. @@ -1026,8 +1026,8 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): assumptions on `\Phi`. - ``tau`` -- (default: ``None``) the fundamental constant described - in the extended description. If ``None``, then `\tau` is tried to - be determined automatically. + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. @@ -1178,8 +1178,8 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` where `p` is maximal. - The fundamental constant `\tau` is assumed to be the unique positive - solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. If `\Phi` is `p`-periodic, then we have `y(z) = z g(z^p)`. This method returns the singular expansion of `g(z)`. @@ -1195,8 +1195,8 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): the extended description for details. - ``tau`` -- (default: ``None``) the fundamental constant described - in the extended description. If ``None``, then `\tau` is tried to - be determined automatically. + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. From 12e463b25af92cc1d465f00841f95e44744a021d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:31:10 +0200 Subject: [PATCH 098/218] Trac #23872: explicitly mention #20050 instead of simply citing "technical reasons" --- .../rings/asymptotic/asymptotic_expansion_generators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index d0a9fce48bf..7ff997fca84 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1041,8 +1041,8 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): .. NOTE:: In the given case, the radius of convergence of the function of - interest is known to be `\rho = \tau/\Phi(\tau)`. For technical - reasons, the variable in the returned asymptotic expansion + interest is known to be `\rho = \tau/\Phi(\tau)`. Until :trac:`20050` + is implemented, the variable in the returned asymptotic expansion represents a singular element of the form `(1 - z/\rho)^{-1}`, for the variable `z\to\rho`. @@ -1210,8 +1210,8 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): .. NOTE:: In the given case, the radius of convergence of the function of - interest is known to be `\rho = \tau/\Phi(\tau)`. For technical - reasons, the variable in the returned asymptotic expansion + interest is known to be `\rho = \tau/\Phi(\tau)`. Until :trac:`20050` + is implemented, the variable in the returned asymptotic expansion represents a singular element of the form `(1 - z/\rho)^{-1}`, for the variable `z\to\rho`. From 87512ba3c9361b8680cf2fd2cc405be7502c84c0 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:31:47 +0200 Subject: [PATCH 099/218] Trac #23872: period without default As calling ImplicitExpansionPeriodicPart does not make sense for aperiodic functions, the default 1 for period is removed. --- .../rings/asymptotic/asymptotic_expansion_generators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 7ff997fca84..54a4058526f 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1166,8 +1166,8 @@ def ansatz(prec=precision): @staticmethod - def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): @experimental(20050) + def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): r""" Return the singular expansion for the periodic part of a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))`. @@ -1191,8 +1191,8 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): - ``phi`` -- the function `\Phi`. See the extended description for assumptions on `\Phi`. - - ``period`` -- (default: `1`) the period of the function `\Phi`. See - the extended description for details. + - ``period`` -- the period of the function `\Phi`. See the + extended description for details. - ``tau`` -- (default: ``None``) the fundamental constant described in the extended description. If ``None``, then `\tau` is determined From 30305cfdef4a16e148bcaba1d9eabf4d8b1674dc Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 11:32:40 +0200 Subject: [PATCH 100/218] Trac #23872: improve seealso block --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 54a4058526f..c1d058fbb11 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1269,8 +1269,8 @@ def _fundamental_constant_implicit_function_(phi): .. SEEALSO:: - :meth:`AsymptoticExpansionGenerators.ImplicitExpansion` - :meth:`AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart` + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`. TESTS:: From 4a6f4877c180634ed6bae900191f3a2c649d1c47 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 12:02:31 +0200 Subject: [PATCH 101/218] Trac #23872: Move FS2009 to master reference list and link to errata list on book page instead of Flajolet's homepage which only contains errata until a certain point in time. --- src/doc/en/reference/references/index.rst | 5 +++++ .../asymptotic/asymptotic_expansion_generators.py | 11 ++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 8fb702d9be6..ff2a63840c3 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -856,6 +856,11 @@ REFERENCES: und Geometrie", Dissertation, University of Bayreuth, 2013. +.. [FS2009] Philippe Flajolet and Robert Sedgewick, + `Analytic combinatorics `_. + Cambridge University Press, Cambridge, 2009. + See also the `Errata list `_. + .. [FM2014] Cameron Franc and Marc Masdeu, "Computing fundamental domains for the Bruhat-Tits tree for GL_2(Qp), p-adic automorphic forms, and the canonical embedding of Shimura diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index c1d058fbb11..ffc1efd3184 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -62,11 +62,6 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. -REFERENCES: - -.. [FS2009] Philippe Flajolet and Robert Sedgewick, - `Analytic combinatorics `_. - Cambridge University Press, Cambridge, 2009. Classes and Methods =================== @@ -730,8 +725,7 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, ALGORITHM: - See [FS2009]_ together with the - `errata list `_. + See [FS2009]_. TESTS:: @@ -1015,8 +1009,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): Furthermore, it is assumed that there is a unique positive solution `\tau` of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. - All details are given in Chapter VI.7 of [FS2009]_; also see the corresponding - `errata list `_. + All details are given in Chapter VI.7 of [FS2009]_. INPUT: From ab7e2c2edbe8b3b79e88df4be554b32d990af5c5 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 22 Sep 2017 12:19:04 +0200 Subject: [PATCH 102/218] Trac #23872: move FS2009 according to label --- src/doc/en/reference/references/index.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index ff2a63840c3..4f9a0aaa38a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -856,11 +856,6 @@ REFERENCES: und Geometrie", Dissertation, University of Bayreuth, 2013. -.. [FS2009] Philippe Flajolet and Robert Sedgewick, - `Analytic combinatorics `_. - Cambridge University Press, Cambridge, 2009. - See also the `Errata list `_. - .. [FM2014] Cameron Franc and Marc Masdeu, "Computing fundamental domains for the Bruhat-Tits tree for GL_2(Qp), p-adic automorphic forms, and the canonical embedding of Shimura @@ -885,6 +880,11 @@ REFERENCES: *Quantization of Lie Groups and Lie Algebras*. Leningrad Math. J. vol. **1** (1990), no. 1. +.. [FS2009] Philippe Flajolet and Robert Sedgewick, + `Analytic combinatorics `_. + Cambridge University Press, Cambridge, 2009. + See also the `Errata list `_. + .. [FST2012] \A. Felikson, \M. Shapiro, and \P. Tumarkin, *Cluster Algebras of Finite Mutation Type Via Unfoldings*, Int Math Res Notices (2012) 2012 (8): 1768-1804. From eaf9e8f4e0695285440a2b64d5cb530013b8ae88 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 22 Sep 2017 16:23:52 +0200 Subject: [PATCH 103/218] initial version of InverseFunctionAnalysis --- .../asymptotic_expansion_generators.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 1cfea4b2184..9c113271c3d 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1243,6 +1243,73 @@ def ImplicitExpansionPeriodicPart(var, phi, tau=None, period=1, precision=None): return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) + @staticmethod + def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): + r""" + Return the coefficient growth of a function `y(z)` defined implicitly + by `y(z) = z \Phi(y(z))`. + + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. For an integer `p`, `\Phi` is called `p`-periodic + if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` + where `p` is maximal. + + The fundamental constant `\tau` is assumed to be the unique positive + solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. + + - ``period`` -- (default: `1`) the period of the function `\Phi`. See + the extended description for details. + + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is tried to + be determined automatically. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + It is not checked that the passed period actually fits to + the passed function `\Phi`. + + The resulting asymptotic expansion is only valid + for `n \equiv 1 \mod p`, where `p` is the period. All other + coefficients are `0`. + + + EXAMPLES: + + TODO + """ + if tau is None: + tau = _fundamental_constant_(phi=phi) + + rho = tau/phi(tau) + + if period == 1: + expansion = asymptotic_expansions.ImplicitExpansion(var=var, phi=phi, + tau=tau, precision=precision) + return expansion._singularity_analysis_(var, zeta=rho, precision=precision) + expansion = asymptotic_expansions.ImplicitExpansionPeriodicPart(var=var, phi=phi, + period=period, tau=tau, precision=precision) + growth = expansion._singularity_analysis_(var, zeta=rho**period, precision=precision) + n = growth.parent().gen() + return growth.subs({n: (n-1)/period}) + def _fundamental_constant_(phi): r""" Return the fundamental constant `\tau` occurring in the analysis of From 741f32fbf78266674146422d93d611cdf7d5e534 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 22 Sep 2017 15:28:55 +0200 Subject: [PATCH 104/218] Upgrade to Python 2.7.14 --- build/pkgs/python2/checksums.ini | 6 +++--- build/pkgs/python2/package-version.txt | 2 +- src/sage/misc/fast_methods.pyx | 4 +--- src/sage/misc/weak_dict.pyx | 8 +------- src/sage/parallel/use_fork.py | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/build/pkgs/python2/checksums.ini b/build/pkgs/python2/checksums.ini index bbdd7d43c6b..44d5f9f5f40 100644 --- a/build/pkgs/python2/checksums.ini +++ b/build/pkgs/python2/checksums.ini @@ -1,4 +1,4 @@ tarball=Python-VERSION.tgz -sha1=dce2b862a30099ee48c19a7c34e2d7c2eeff5670 -md5=17add4bf0ad0ec2f08e0cae6d205c700 -cksum=2666254648 +sha1=e29c3fa7865895e0f01299e0358b59bfd0462766 +md5=cee2e4b33ad3750da77b2e85f2f8b724 +cksum=937191707 diff --git a/build/pkgs/python2/package-version.txt b/build/pkgs/python2/package-version.txt index ccf883e0dde..a682fe232c8 100644 --- a/build/pkgs/python2/package-version.txt +++ b/build/pkgs/python2/package-version.txt @@ -1 +1 @@ -2.7.13.p1 +2.7.14.p0 diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index 29bacd43f7b..7c32126246e 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -305,9 +305,7 @@ class Singleton(WithEqualityById, metaclass=ClasscallMetaclass): sage: loads(dumps(c)) Traceback (most recent call last): ... - AssertionError: ((" is not a direct - subclass of ",), - , ()) + AssertionError: is not a direct subclass of """ @staticmethod def __classcall__(cls): diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index 40e8f5dbebb..f6f30c65955 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -35,16 +35,10 @@ value that is being garbage collected:: sage: len(D) 10 sage: del ValList, v - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - ... sage: len(D) > 1 True -Hence, there are scary error messages, and moreover the defunct items have not -been removed from the dictionary. +Hence, the defunct items have not been removed from the dictionary. Therefore, Sage provides an alternative implementation :class:`sage.misc.weak_dict.WeakValueDictionary`, using a callback that diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index 02ff810336b..228bf9d987d 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -145,7 +145,7 @@ def __call__(self, f, inputs): sage: L = list(Polygen([QQ])) sage: L [(((Rational Field,), {}), - "INVALID DATA ('__init__() takes at most 2 positional arguments (4 given)', , (Univariate Polynomial Ring in x over Rational Field, [0, 1], False, True))")] + 'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')] Fix the unpickling:: From 9fc741e9e49b7b3ca3ccdeda6951e5d749a39135 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 22 Sep 2017 17:16:38 +0200 Subject: [PATCH 105/218] add doctest for InverseFunctionAnalysis --- .../asymptotic_expansion_generators.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index f255d9e3d5a..25e77f10821 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1297,7 +1297,24 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): EXAMPLES: - TODO + There are `C_n` (the `n`-th Catalan number) different binary trees + of size `2n+1`, and there are no binary trees with an even number of + nodes. The corresponding generating function satisfies + `B(z) = z (1 + B(z)^2)`, which allows us to compare the asymptotic + expansions for the number of binary trees of size `n` obtained via + `C_n` and obtained via the analysis of `B(z)`:: + + sage: A. = AsymptoticRing('QQ^n * n^QQ', SR) + sage: binomial_expansion = asymptotic_expansions.Binomial_kn_over_n(n, k=2, precision=3) + sage: catalan_expansion = binomial_expansion / (n+1) + sage: catalan_expansion.subs(n=(n-1)/2) + 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + u^2, period=2, + ....: tau=1, precision=8) + 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + """ if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) From 92b22674c6675a2778500bbcccff847022df8f18 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 23 Sep 2017 10:39:56 +0200 Subject: [PATCH 106/218] Trac #23872: rewording; exchange order of params Same rewording as in ca161c2; exchange order of parameters in INPUT block for consistency with the prototype --- .../asymptotic/asymptotic_expansion_generators.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 25e77f10821..efcbb1c96e7 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1259,8 +1259,8 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` where `p` is maximal. - The fundamental constant `\tau` is assumed to be the unique positive - solution of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. INPUT: @@ -1269,13 +1269,13 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): - ``phi`` -- the function `\Phi`. See the extended description for assumptions on `\Phi`. + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. + - ``period`` -- (default: `1`) the period of the function `\Phi`. See the extended description for details. - - ``tau`` -- (default: ``None``) the fundamental constant described - in the extended description. If ``None``, then `\tau` is tried to - be determined automatically. - - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. From e40edb21a022de86c695900ee914ec2445236361 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 23 Sep 2017 10:41:14 +0200 Subject: [PATCH 107/218] Trac #23872: include in toc --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index efcbb1c96e7..aaac4745c31 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -49,6 +49,9 @@ * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart` - the singular expansion of the periodic part of a function `y(z)` satisfying `y(z) = z\Phi(y(z))` + * - :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis` + - coefficient growth of a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))` + AUTHORS: @@ -101,6 +104,7 @@ class AsymptoticExpansionGenerators(SageObject): - :meth:`~SingularityAnalysis` - :meth:`~ImplicitExpansion` - :meth:`~ImplicitExpansionPeriodicPart` + - :meth:`~InverseFunctionAnalysis` """ @staticmethod From 7079781b5273ace2331c21f793291e016870a1ad Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 23 Sep 2017 10:41:46 +0200 Subject: [PATCH 108/218] Trac #23872: see also blocks --- .../asymptotic/asymptotic_expansion_generators.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index aaac4745c31..3209092728d 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1097,6 +1097,10 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=3, precision=5) 3 - 4*I*sqrt(3)*Z^(-1/2) + 6*I*sqrt(3)*Z^(-3/2) + O(Z^(-2)) + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`, + :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis`. TESTS:: @@ -1212,6 +1216,10 @@ def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): represents a singular element of the form `(1 - z/\rho)^{-1}`, for the variable `z\to\rho`. + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis`. EXAMPLES: @@ -1319,6 +1327,11 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`. + """ if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) From fc913138e3278895d50191d29ef97352cf03c448 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 23 Sep 2017 10:42:30 +0200 Subject: [PATCH 109/218] Trac #23872: add doctest for aperiodic case --- .../asymptotic/asymptotic_expansion_generators.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 3209092728d..89ba2480304 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1327,6 +1327,20 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + The code in the aperiodic case is more efficient, however. Therefore, + it is recommended to use combinatorial identities to reduce to the + aperiodic case. In the example above, this is well-known: we now count + binary trees with `n` internal nodes. The corresponding generating function + satisfies `B(z) = z (1 + 2B(z) + B(z)^2)`:: + + sage: catalan_expansion + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + + 145/128/sqrt(pi)*4^n*n^(-7/2) + O(4^n*n^(-9/2)) + sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + 2*u + u^2, + ....: tau=1, precision=8) + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + + 145/128/sqrt(pi)*4^n*n^(-7/2) + O(4^n*n^(-9/2)) + .. SEEALSO:: :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, From 065d1af95c5fa81908b3f6c2719a959730e18d0e Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 23 Sep 2017 10:42:51 +0200 Subject: [PATCH 110/218] Trac #23872: document bug --- .../asymptotic/asymptotic_expansion_generators.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 89ba2480304..5712af8c41e 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1346,6 +1346,16 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`. + + TESTS:: + + Omitting the precision parameter does lead to an error:: + + sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + 2*u + u^2, + ....: tau=1) + Traceback (most recent call last): + ... + AttributeError: 'int' object has no attribute 'factorial' """ if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) From a6358f1b57e955f7f15ea6541ffa3edcea42949b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 23 Sep 2017 18:45:38 +0200 Subject: [PATCH 111/218] fix bug with omitted precision --- src/sage/rings/asymptotic/asymptotic_expansion_generators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 5712af8c41e..b4f6fbabaf1 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1120,6 +1120,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): """ from sage.symbolic.ring import SR from sage.rings.rational_field import QQ + from sage.rings.integer_ring import ZZ from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing from sage.arith.srange import srange y, u = SR('y'), SR('u') @@ -1138,7 +1139,7 @@ def H(y): coefficient_ring=SR, default_prec=precision) if precision is None: - precision = A.default_prec + precision = ZZ(A.default_prec) Z = A.gen() def ansatz(prec=precision): From 189ac2b4a6b37dbe49ea70ab09e6e68b8b091d59 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 23 Sep 2017 18:24:54 +0000 Subject: [PATCH 112/218] Add _test_fraction_field to the coercion tutorial --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 3b124e8d744..09b78706963 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -1552,6 +1552,7 @@ Here are the tests that form the test suite of quotient fields:: '_test_elements_eq_transitive', '_test_elements_neq', '_test_euclidean_degree', + '_test_fraction_field', '_test_gcd_vs_xgcd', '_test_one', '_test_prod', '_test_quo_rem', @@ -1606,6 +1607,7 @@ Let us see what tests are actually performed:: running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass @@ -1778,6 +1780,7 @@ interesting. running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass From 1d1039f8b082cb4e36d7ef0e34f6860a5385b9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 23 Sep 2017 21:59:51 +0200 Subject: [PATCH 113/218] trac 23671 moving refs to the huge list of refs --- src/doc/en/reference/references/index.rst | 28 +++++++++++++++++++++++ src/sage/modular/hypergeometric_motive.py | 28 +++++++---------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 67765a94f61..b619a89f585 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -248,6 +248,10 @@ REFERENCES: and Applications - FQ9, volume 518 of Contemporary Mathematics, pages 33–42. AMS, 2010. +.. [BeCoMe] Frits Beukers, Henri Cohen, Anton Mellit, + *Finite hypergeometric functions*, + :arxiv:`1505.02900` + .. [Bee] Robert A. Beezer, *A First Course in Linear Algebra*, http://linear.ups.edu/. Accessed 15 July 2010. @@ -255,6 +259,9 @@ REFERENCES: *Information technologies. Data protection. Cryptograpic algorithms for encryption and integrity control*; in STB 34.101.31-2011, (2011). +.. [Benasque2009] Fernando Rodriguez Villegas, *The L-function of the quintic*, + http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + .. [Ber2008] \W. Bertram : *Differential Geometry, Lie Groups and Symmetric Spaces over General Base Fields and Rings*, Memoirs of the American Mathematical Society, vol. 192 @@ -263,6 +270,10 @@ REFERENCES: .. [Ber1991] \C. Berger, "Une version effective du théorème de Hurewicz", https://tel.archives-ouvertes.fr/tel-00339314/en/. +.. [BeukersHeckman] \F. Beukers and \G. Heckman, + *Monodromy for the hypergeometric function `{}_n F_{n-1}`*, + Invent. Math. 95 (1989) + .. [BF1999] Thomas Britz, Sergey Fomin, *Finite posets and Ferrers shapes*, Advances in Mathematics 158, pp. 86-127 (2001), @@ -836,6 +847,10 @@ REFERENCES: **F** +.. [Fedorov2015] Roman Fedorov, *Variations of Hodge structures for hypergeometric + differential operators and parabolic Higgs bundles*, + :arxiv:`1505.01704` + .. [Fe1997] Stefan Felsner, "On the Number of Arrangements of Pseudolines", Proceedings SoCG 96, 30-37. Discrete & Computational Geometry 18 (1997), @@ -1536,6 +1551,9 @@ REFERENCES: **M** +.. [MagmaHGM] *Hypergeometric motives* in Magma, + http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + .. [Mas94] James L. Massey, *SAFER K-64: A byte-oriented block-ciphering algorithm*; in FSE’93, Volume 809 of LNCS, pages 1-17. @@ -1845,6 +1863,12 @@ REFERENCES: polynomials. Mathematical Programming, Series B, 129 (2011) 5-31. +.. [Roberts2015] David P. Roberts, *Hypergeometric Motives I*, https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + +.. [Roberts2017] David P. Roberts, *Hypergeometric motives and an unusual + application of the Guinand-Weil-Mestre explicit formula*, + https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + .. [Roc1970] \R.T. Rockafellar, *Convex Analysis*. Princeton University Press, Princeton, 1970. @@ -2171,6 +2195,10 @@ REFERENCES: .. [Was1997] \L. C. Washington, *Cyclotomic Fields*, Springer-Verlag, GTM volume 83, 1997. +.. [Watkins] Mark Watkins, + *Hypergeometric motives over Q and their L-functions*, + http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf + .. [Wat2003] Joel Watson. *Strategy: an introduction to game theory*. WW Norton, 2002. diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 1524dc73216..b6d37c90e41 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -29,33 +29,21 @@ REFERENCES: -.. [BeukersHeckman] \F. Beukers and \G. Heckman, - *Monodromy for the hypergeometric function `{}_n F_{n-1}`*, - Invent. Math. 95 (1989) +- [BeukersHeckman]_ -.. [Benasque2009] Fernando Rodriguez Villegas, *The L-function of the quintic*, - http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf +- [Benasque2009]_ -.. [MagmaHGM] *Hypergeometric motives* in Magma, - http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf +- [MagmaHGM]_ -.. [Fedorov2015] Roman Fedorov, *Variations of Hodge structures for hypergeometric - differential operators and parabolic Higgs bundles*, - https://arxiv.org/pdf/1505.01704 +- [Fedorov2015]_ -.. [Roberts2017] David P. Roberts, *Hypergeometric motives and an unusual - application of the Guinand-Weil-Mestre explicit formula*, - https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf +- [Roberts2017]_ -.. [Roberts2015] David P. Roberts, *Hypergeometric Motives I*, https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf +- [Roberts2015]_ -.. [BeCoMe] Frits Beukers, Henri Cohen, Anton Mellit, - *Finite hypergeometric functions*, - https://arxiv.org/pdf/1505.02900.pdf +- [BeCoMe]_ -.. [Watkins] Mark Watkins, - *Hypergeometric motives over Q and their L-functions*, - http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf +- [Watkins]_ """ #***************************************************************************** From bce429bd44068d25bc82bee228c67afdea34ca2a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 24 Sep 2017 21:55:09 +0200 Subject: [PATCH 114/218] 23734: faster map_to_list --- src/sage/combinat/permutation_cython.pxd | 4 +-- src/sage/combinat/permutation_cython.pyx | 34 +++++++++++++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index 0ff39b13c4f..b8b503765f4 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -3,8 +3,8 @@ import array cdef void reset_swap(int n, int *c, int *o) cdef int next_swap(int n, int *c, int *o) -cpdef next_perm(array.array l) -cpdef list map_to_list(array.array l, tuple values, int n) +cpdef bint next_perm(array.array l) +cpdef list map_to_list(array.array l, values, int n) cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 3088399d8d0..0fe31bacb8a 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -31,10 +31,18 @@ from __future__ import print_function cimport cython -from cpython.list cimport * +from cpython.object cimport PyObject + from cysignals.memory cimport sig_malloc, sig_free -########################################################## +cdef extern from "Python.h": + void Py_INCREF(PyObject *) + PyObject * PyInt_FromLong(long ival) + list PyList_New(Py_ssize_t size) + void PyList_SET_ITEM(list l, Py_ssize_t, PyObject *) + PyObject * PyTuple_GET_ITEM(PyObject *op, Py_ssize_t i) + +######################################################### # # The next two functions, reset_swap and next_swap do the # real work. They've been implemented separately because @@ -178,7 +186,7 @@ def permutation_iterator_transposition_list(int n): reset_swap(n,c,o) for m in range(N-1): - PyList_SET_ITEM(T, m, next_swap(n,c,o)) + PyList_SET_ITEM(T, m, PyInt_FromLong(next_swap(n,c,o))) sig_free(c) return T @@ -189,7 +197,7 @@ def permutation_iterator_transposition_list(int n): @cython.wraparound(False) @cython.boundscheck(False) -cpdef next_perm(array.array l): +cpdef bint next_perm(array.array l): """ Obtain the next permutation under lex order of ``l`` by mutating ``l``. @@ -268,10 +276,16 @@ cpdef next_perm(array.array l): return True -cpdef list map_to_list(array.array l, tuple values, int n): +cpdef list map_to_list(array.array l, values, int n): """ Build a list by mapping the array ``l`` using ``values``. + .. WARNING:: + + There is no check of the input data at any point. Using wrong + types or values with wrong length is likely to result in a Sage + crash. + INPUT: - ``l`` -- array of unsigned int (i.e., type ``'I'``) @@ -291,12 +305,14 @@ cpdef list map_to_list(array.array l, tuple values, int n): ['a', 'b', 'a', 'd', 'd', 'a', 'b'] """ cdef int i - cdef list ret = [] - for i in xrange(n): - ret.append(values[l.data.as_uints[i]]) + cdef list ret = PyList_New(n) + cdef PyObject * t + for i in range(n): + t = PyTuple_GET_ITEM( values, l.data.as_uints[i]) + Py_INCREF(t) + PyList_SET_ITEM(ret, i, t) return ret - ##################################################################### ## Multiplication functions for permutations From 7eb3973d76b5a1ed1ccee8038f3c5bc7dc9538b5 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 24 Sep 2017 21:55:18 +0200 Subject: [PATCH 115/218] 23734: proper copyright banner --- src/sage/combinat/permutation_cython.pyx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 0fe31bacb8a..918c14b7e45 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -22,11 +22,17 @@ speed, we provide a class that wraps our struct. """ - -# Free for any use. -# Unfit for any purpose. +#***************************************************************************** +# Copyright (C) 2010 Tom Boothby +# Copyright (C) 2017 Travis Scrimshaw +# Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> # -# Copyright 2010, Tom Boothby +# 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/ +#***************************************************************************** + from __future__ import print_function cimport cython From e619e5d01e2c11baeee076910655d5a67ef60b27 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 26 Sep 2017 15:56:43 +0200 Subject: [PATCH 116/218] fix caching issue with default_prec of AsymptoticRing --- .../rings/asymptotic/asymptotic_expansion_generators.py | 7 ++++--- src/sage/rings/asymptotic/asymptotic_ring.py | 5 +---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index b4f6fbabaf1..3927f2529a5 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -85,6 +85,7 @@ from sage.misc.superseded import experimental from sage.structure.sage_object import SageObject +from sage.misc.defaults import series_precision class AsymptoticExpansionGenerators(SageObject): @@ -284,7 +285,7 @@ def log_Stirling(var, precision=None, skip_constant_summand=False): n = A.gen() if precision is None: - precision = AsymptoticRing.__default_prec__ + precision = series_precision() from sage.functions.log import log result = A.zero() @@ -439,7 +440,7 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): n = A.gen() if precision is None: - precision = A.default_prec + precision = series_precision() from sage.functions.log import log result = A.zero() @@ -927,7 +928,7 @@ def inverse_gamma_derivative(shift, r): delta = ZZ(delta) if precision is None: - precision = AsymptoticRing.__default_prec__ + precision = series_precision() if not normalized and not (beta in ZZ and delta in ZZ): diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0b03a4ad151..854411a6263 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -3347,9 +3347,6 @@ class AsymptoticRing(Algebra, UniqueRepresentation): Element = AsymptoticExpansion - __default_prec__ = series_precision() # default default-precision - - @staticmethod def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, category=None, default_prec=None): @@ -3469,7 +3466,7 @@ def format_names(N): category = CommutativeAlgebras(Rings()) if default_prec is None: - default_prec = cls.__default_prec__ + default_prec = series_precision() return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, From 9d40353bc8b0c425ca376387f8068108cd4e5b14 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 26 Sep 2017 15:56:55 +0200 Subject: [PATCH 117/218] adapt default_prec-doctest --- .../rings/asymptotic/asymptotic_expansion_generators.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 3927f2529a5..4e204c1a74d 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1351,13 +1351,12 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): TESTS:: - Omitting the precision parameter does lead to an error:: + Omitting the precision parameter does not lead to an error:: - sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + 2*u + u^2, + sage: set_series_precision(5) + sage: asymptotic_expansions.InverseFunctionAnalysis('n', phi=lambda u: 1 + 2*u + u^2, ....: tau=1) - Traceback (most recent call last): - ... - AttributeError: 'int' object has no attribute 'factorial' + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3)) """ if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) From 7f1c1597f631832a356db0398ff7051175d2e626 Mon Sep 17 00:00:00 2001 From: Koen van Woerden Date: Wed, 27 Sep 2017 15:15:19 +0200 Subject: [PATCH 118/218] Add O method. Add O method that is a synonym for the add_bigoh method. --- src/sage/rings/laurent_series_ring_element.pyx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 397e5bc291f..1688f1f28b2 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -691,6 +691,21 @@ cdef class LaurentSeries(AlgebraElement): u = self.__u.add_bigoh(prec - self.__n) return type(self)(P, u, self.__n) + def O(self, prec): + r""" + Return the Laurent series of precission at most ``prec`` got by adding + `O(q^\text{prec})` to `f`, where `q` is the variable. + + EXAMPLES:: + + sage: R. = LaurentSeriesRing(QQ) + sage: f = t^-5 + t^-4 + t^3 + O(t^10); f + t^-5 + t^-4 + t^3 + O(t^10) + sage: f.O(-4) + t^-5 + O(t^-4) + """ + return self.add_bigoh(prec) + def degree(self): """ Return the degree of a polynomial equivalent to this power series From d3679562368021af54af8e3cff8673b3b0c0012e Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Wed, 27 Sep 2017 17:05:30 +0200 Subject: [PATCH 119/218] 23925: Bulk fix of signal handling in symbolics --- src/sage/symbolic/expression.pyx | 219 +++++++++++++++++++++++++------ 1 file changed, 181 insertions(+), 38 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 94252ea86b2..80a6e1f75f9 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -478,7 +478,11 @@ cdef class Expression(CommutativeRingElement): sage: (1+x)._dbgprint() x + 1 """ - self._gobj.dbgprint() + sig_on() + try: + self._gobj.dbgprint() + finally: + sig_off() def _dbgprinttree(self): r""" @@ -531,7 +535,11 @@ cdef class Expression(CommutativeRingElement): x (symbol) ... ===== """ - self._gobj.dbgprinttree(); + sig_on() + try: + self._gobj.dbgprinttree() + finally: + sig_off() def __setstate__(self, state): """ @@ -1189,6 +1197,7 @@ cdef class Expression(CommutativeRingElement): 0.9036020036... """ cdef GEx res + sig_on() try: res = self._gobj.evalf(0, {'parent':R}) except TypeError as err: @@ -1202,6 +1211,9 @@ cdef class Expression(CommutativeRingElement): except (TypeError, AttributeError): raise err res = self._gobj.evalf(0, {'parent':R_complex}) + finally: + sig_off() + if is_a_numeric(res): ans = py_object_from_numeric(res) # Convert ans to R. @@ -1258,7 +1270,12 @@ cdef class Expression(CommutativeRingElement): sage: f._convert({'parent':int}) 0 """ - cdef GEx res = self._gobj.evalf(0, kwds) + cdef GEx res + sig_on() + try: + res = self._gobj.evalf(0, kwds) + finally: + sig_off() return new_Expression_from_GEx(self._parent, res) def _mpfr_(self, R): @@ -1582,7 +1599,33 @@ cdef class Expression(CommutativeRingElement): sage: hash(unsigned_infinity) == hash(SR(unsigned_infinity)) True """ - return self._gobj.gethash() + sig_on() + try: + return self._gobj.gethash() + finally: + sig_off() + + def _rel_equal1(self, right): + cdef Expression l, r + l = self + r = right + sig_on() + try: + return (l._gobj.lhs().is_equal(r._gobj.lhs()) + and l._gobj.rhs().is_equal(r._gobj.rhs())) + finally: + sig_off() + + def _rel_equal2(self, right): + cdef Expression l, r + l = self + r = right + sig_on() + try: + return (l._gobj.lhs().is_equal(r._gobj.rhs()) + and l._gobj.rhs().is_equal(r._gobj.lhs())) + finally: + sig_off() cpdef _richcmp_(left, right, int op): """ @@ -1655,15 +1698,12 @@ cdef class Expression(CommutativeRingElement): # both lhs and rhs are relations, so we can get to work if l.operator() == r.operator(): e2 = ( # case: (x _ y) ?= (x _ y) - ( l._gobj.lhs().is_equal(r._gobj.lhs()) and - l._gobj.rhs().is_equal(r._gobj.rhs()) ) or - + left._rel_equal1(right) or # case: (x == y) ?= (y == x) # (x != y) ?= (y != x) ( ( l.operator() == operator.eq or l.operator() == operator.ne ) and - l._gobj.lhs().is_equal(r._gobj.rhs()) and - l._gobj.rhs().is_equal(r._gobj.lhs()) )) + left._rel_equal2(right) )) else: e2 = ( # case: (x < y) ?= (y > x) (or vice versa) # (x <= y) ?= (y >= x) (or vice versa) @@ -1675,9 +1715,7 @@ cdef class Expression(CommutativeRingElement): r.operator() == operator.ge ) or ( l.operator() == operator.ge and r.operator() == operator.le ) ) and - l._gobj.lhs().is_equal(r._gobj.rhs()) and - l._gobj.rhs().is_equal(r._gobj.lhs()) ) - + left._rel_equal2(right) ) else: e2 = False # l is relational but r isn't. @@ -2353,7 +2391,11 @@ cdef class Expression(CommutativeRingElement): False """ cdef Expression symbol0 = self.coerce_in(var) - return self._gobj.is_polynomial(symbol0._gobj) + sig_on() + try: + return self._gobj.is_polynomial(symbol0._gobj) + finally: + sig_off() cpdef bint is_relational(self): """ @@ -4823,7 +4865,12 @@ cdef class Expression(CommutativeRingElement): """ cdef Expression p = self.coerce_in(pattern) cdef GExList mlst - cdef bint res = self._gobj.match(p._gobj, mlst) + cdef bint res + sig_on() + try: + res = self._gobj.match(p._gobj, mlst) + finally: + sig_off() if not res: return None @@ -4872,7 +4919,11 @@ cdef class Expression(CommutativeRingElement): from sage.symbolic.comparison import print_sorted cdef Expression p = self.coerce_in(pattern) cdef GExList found - self._gobj.find(p._gobj, found) + sig_on() + try: + self._gobj.find(p._gobj, found) + finally: + sig_off() res = [] cdef GExListIter itr = found.begin() while itr != found.end(): @@ -5165,6 +5216,7 @@ cdef class Expression(CommutativeRingElement): (x, y, t) |--> x^2 + y^2 + t + cos(x) + sin(y) """ cdef dict sdict = {} + cdef GEx res if args and args[0] is None: # this is needed because sometimes this function get called as @@ -5186,9 +5238,12 @@ cdef class Expression(CommutativeRingElement): for k, v in sdict.iteritems(): smap.insert(make_pair((self.coerce_in(k))._gobj, (self.coerce_in(v))._gobj)) - - return new_Expression_from_GEx(self._parent, - self._gobj.subs_map(smap, 0)) + sig_on() + try: + res = self._gobj.subs_map(smap, 0) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, res) subs = substitute @@ -5235,8 +5290,13 @@ cdef class Expression(CommutativeRingElement): x - 1 """ cdef Expression p = self.coerce_in(expr) - return new_Expression_from_GEx(self._parent, self._gobj.subs(p._gobj)) - + cdef GEx res + sig_on() + try: + res = self._gobj.subs(p._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, res) substitute_expression = deprecated_function_alias(12834, substitute) subs_expr = deprecated_function_alias(12834, subs) @@ -6074,6 +6134,7 @@ cdef class Expression(CommutativeRingElement): 1 """ cdef Expression ss = self.coerce_in(s) + cdef GEx r if n != 1 and not is_a_symbol(ss._gobj): raise TypeError("n != 1 only allowed for s being a variable") @@ -6083,7 +6144,12 @@ cdef class Expression(CommutativeRingElement): for i from 0 <= i < ss._gobj.nops(): res = res.coefficient(new_Expression_from_GEx(self._parent, ss._gobj.op(i))) return res - return new_Expression_from_GEx(self._parent, self._gobj.coeff(ss._gobj, n)) + sig_on() + try: + r = self._gobj.coeff(ss._gobj, n) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) coeff = deprecated_function_alias(17438, coefficient) @@ -6185,7 +6251,11 @@ cdef class Expression(CommutativeRingElement): if x is None: x = self.default_variable() xx = self.coerce_in(x) - self._gobj.coefficients(xx._gobj, vec) + sig_on() + try: + self._gobj.coefficients(xx._gobj, vec) + finally: + sig_off() l = [] for p in vec: l.append([new_Expression_from_GEx(self._parent, p.first), @@ -6260,7 +6330,13 @@ cdef class Expression(CommutativeRingElement): x^3 + 2/x """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.lcoeff(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.lcoeff(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) leading_coeff = leading_coefficient @@ -6283,7 +6359,13 @@ cdef class Expression(CommutativeRingElement): a*x + x*y + x/y + 100 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.tcoeff(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.tcoeff(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) trailing_coeff = trailing_coefficient @@ -6311,7 +6393,11 @@ cdef class Expression(CommutativeRingElement): 0 """ cdef Expression ss = self.coerce_in(s) - return self._gobj.ldegree(ss._gobj) + sig_on() + try: + return self._gobj.ldegree(ss._gobj) + finally: + sig_off() def degree(self, s): """ @@ -6337,7 +6423,11 @@ cdef class Expression(CommutativeRingElement): 0 """ cdef Expression ss = self.coerce_in(s) - return self._gobj.degree(ss._gobj) + sig_on() + try: + return self._gobj.degree(ss._gobj) + finally: + sig_off() def unit(self, s): """ @@ -6370,7 +6460,13 @@ cdef class Expression(CommutativeRingElement): -1 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.unit(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.unit(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def content(self, s): """ @@ -6409,7 +6505,13 @@ cdef class Expression(CommutativeRingElement): 2 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.content(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.content(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def primitive_part(self, s): """ @@ -6443,7 +6545,13 @@ cdef class Expression(CommutativeRingElement): x + 2*sin(y) """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.primpart(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.primpart(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def unit_content_primitive(self, s): """ @@ -6474,7 +6582,11 @@ cdef class Expression(CommutativeRingElement): """ cdef Expression ss = self.coerce_in(s) cdef GEx unit, cont, prim - self._gobj.unitcontprim(ss._gobj, unit, cont, prim) + sig_on() + try: + self._gobj.unitcontprim(ss._gobj, unit, cont, prim) + finally: + sig_off() return (new_Expression_from_GEx(self._parent, unit), new_Expression_from_GEx(self._parent, cont), new_Expression_from_GEx(self._parent, prim)) @@ -7365,7 +7477,13 @@ cdef class Expression(CommutativeRingElement): sage: abs(pi+i) abs(pi + I) """ - return new_Expression_from_GEx(self._parent, g_abs(self._gobj)) + cdef GEx r + sig_on() + try: + r = g_abs(self._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def abs(self, hold=False): """ @@ -8926,8 +9044,13 @@ cdef class Expression(CommutativeRingElement): sage: (1+sin((x + 1)/x - 1/x)).combine(deep=True) sin(1) + 1 """ - return new_Expression_from_GEx(self._parent, - self._gobj.combine_fractions(deep)) + cdef GEx r + sig_on() + try: + r = self._gobj.combine_fractions(deep) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def normalize(self): """ @@ -8970,7 +9093,13 @@ cdef class Expression(CommutativeRingElement): ALGORITHM: Uses GiNaC. """ - return new_Expression_from_GEx(self._parent, self._gobj.normal(0, False, True)) + cdef GEx r + sig_on() + try: + r = self._gobj.normal(0, False, True) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def numerator(self, bint normalize = True): """ @@ -9039,9 +9168,14 @@ cdef class Expression(CommutativeRingElement): TypeError: self is not a rational expression """ cdef GExVector vec - cdef GEx oper, power + cdef GEx oper, power, ex if normalize: - return new_Expression_from_GEx(self._parent, self._gobj.numer()) + sig_on() + try: + ex = self._gobj.numer() + finally: + sig_off() + return new_Expression_from_GEx(self._parent, ex) elif is_a_mul(self._gobj): for i from 0 <= i < self._gobj.nops(): oper = self._gobj.op(i) @@ -9126,7 +9260,12 @@ cdef class Expression(CommutativeRingElement): cdef GExVector vec cdef GEx oper, ex, power if normalize: - return new_Expression_from_GEx(self._parent, self._gobj.denom()) + sig_on() + try: + ex = self._gobj.denom() + finally: + sig_off() + return new_Expression_from_GEx(self._parent, ex) elif is_a_mul(self._gobj): for i from 0 <= i < self._gobj.nops(): oper = self._gobj.op(i) @@ -9213,7 +9352,11 @@ cdef class Expression(CommutativeRingElement): cdef GEx oper, ex, power cdef GNumeric power_num if normalize: - ex = self._gobj.numer_denom() + sig_on() + try: + ex = self._gobj.numer_denom() + finally: + sig_off() return (new_Expression_from_GEx(self._parent, ex.op(0)), new_Expression_from_GEx(self._parent, ex.op(1))) elif is_a_mul(self._gobj): From 317eb16079189d8e6f1b03c377fe36add34bc239 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 28 Sep 2017 07:31:27 +0200 Subject: [PATCH 120/218] Trac #23872: test needs to simulate python integer --- .../rings/asymptotic/asymptotic_expansion_generators.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 4e204c1a74d..c52c8696327 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1351,9 +1351,11 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): TESTS:: - Omitting the precision parameter does not lead to an error:: + Omitting the precision parameter does not lead to an error (per default, + the default series precision is a python integer, which led to an error + in an earlier version of the code):: - sage: set_series_precision(5) + sage: set_series_precision(int(5)) sage: asymptotic_expansions.InverseFunctionAnalysis('n', phi=lambda u: 1 + 2*u + u^2, ....: tau=1) 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3)) From 732c03f66bbe3cffea7600a585f2bb7cab1ec533 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Thu, 28 Sep 2017 07:57:16 +0200 Subject: [PATCH 121/218] 23925: address reviewer's comments --- src/sage/symbolic/expression.pxd | 2 ++ src/sage/symbolic/expression.pyx | 30 ++++++++++-------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/sage/symbolic/expression.pxd b/src/sage/symbolic/expression.pxd index 1c38335bbbc..0dfe83295eb 100644 --- a/src/sage/symbolic/expression.pxd +++ b/src/sage/symbolic/expression.pxd @@ -17,6 +17,8 @@ cdef class Expression(CommutativeRingElement): cpdef Expression _subs_expr(self, expr) cpdef int _cmp_add(Expression left, Expression right) except -2 cpdef int _cmp_mul(Expression left, Expression right) except -2 + cdef bint _rel_equal1(Expression self, Expression other) except -1 + cdef bint _rel_equal2(Expression self, Expression other) except -1 cpdef bint is_Expression(x) cdef Expression new_Expression_from_GEx(parent, GEx juice) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 80a6e1f75f9..75ae0f7f316 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1196,10 +1196,8 @@ cdef class Expression(CommutativeRingElement): sage: e._eval_self(float) 0.9036020036... """ - cdef GEx res - sig_on() try: - res = self._gobj.evalf(0, {'parent':R}) + res = self._convert({'parent':R}) except TypeError as err: # try the evaluation again with the complex field # corresponding to the parent R @@ -1210,12 +1208,10 @@ cdef class Expression(CommutativeRingElement): R_complex = R.complex_field() except (TypeError, AttributeError): raise err - res = self._gobj.evalf(0, {'parent':R_complex}) - finally: - sig_off() + res = self._convert({'parent':R_complex}) - if is_a_numeric(res): - ans = py_object_from_numeric(res) + if res.is_numeric(): + ans = res.pyobject() # Convert ans to R. if R is float and isinstance(ans, complex) and not ans.imag: # Python does not automatically convert "real" complex @@ -1605,25 +1601,19 @@ cdef class Expression(CommutativeRingElement): finally: sig_off() - def _rel_equal1(self, right): - cdef Expression l, r - l = self - r = right + cdef bint _rel_equal1(Expression self, Expression other) except -1: sig_on() try: - return (l._gobj.lhs().is_equal(r._gobj.lhs()) - and l._gobj.rhs().is_equal(r._gobj.rhs())) + return (self._gobj.lhs().is_equal(other._gobj.lhs()) + and self._gobj.rhs().is_equal(other._gobj.rhs())) finally: sig_off() - def _rel_equal2(self, right): - cdef Expression l, r - l = self - r = right + cdef bint _rel_equal2(Expression self, Expression other) except -1: sig_on() try: - return (l._gobj.lhs().is_equal(r._gobj.rhs()) - and l._gobj.rhs().is_equal(r._gobj.lhs())) + return (self._gobj.lhs().is_equal(other._gobj.rhs()) + and self._gobj.rhs().is_equal(other._gobj.lhs())) finally: sig_off() From 3fba90f76e57a7bda6b45e3305283f70df135c15 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Thu, 28 Sep 2017 08:03:53 +0200 Subject: [PATCH 122/218] 23925: please the coverage plugin --- src/sage/symbolic/expression.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 75ae0f7f316..a3207345925 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1602,6 +1602,9 @@ cdef class Expression(CommutativeRingElement): sig_off() cdef bint _rel_equal1(Expression self, Expression other) except -1: + """ + Internal helper function. + """ sig_on() try: return (self._gobj.lhs().is_equal(other._gobj.lhs()) @@ -1610,6 +1613,9 @@ cdef class Expression(CommutativeRingElement): sig_off() cdef bint _rel_equal2(Expression self, Expression other) except -1: + """ + Internal helper function. + """ sig_on() try: return (self._gobj.lhs().is_equal(other._gobj.rhs()) From a06d53edc45507923deecf83bacdc1c33ca9870b Mon Sep 17 00:00:00 2001 From: Koen van Woerden Date: Thu, 28 Sep 2017 10:04:04 +0200 Subject: [PATCH 123/218] Fixed typo. --- src/sage/rings/laurent_series_ring_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 1688f1f28b2..61b451f4f76 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -693,7 +693,7 @@ cdef class LaurentSeries(AlgebraElement): def O(self, prec): r""" - Return the Laurent series of precission at most ``prec`` got by adding + Return the Laurent series of precision at most ``prec`` got by adding `O(q^\text{prec})` to `f`, where `q` is the variable. EXAMPLES:: From 12aa8f264e4b454e991c75d48373a3d6f2f8b0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 28 Sep 2017 10:31:54 +0200 Subject: [PATCH 124/218] trac 23671 better ref to slides --- src/sage/modular/hypergeometric_motive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index b6d37c90e41..52b9be3858b 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -945,7 +945,7 @@ def padic_H_value(self, p, f, t, prec=20): sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] - From slides (but note conventions regarding `t`):: + From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 From eb0deb7b017a084f4cd893a78187390e85401de4 Mon Sep 17 00:00:00 2001 From: Koen van Woerden Date: Thu, 28 Sep 2017 11:52:24 +0200 Subject: [PATCH 125/218] Expand doctest. Add doctest which illustrates that O does not increase precision. --- src/sage/rings/laurent_series_ring_element.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 61b451f4f76..2aee1cc232b 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -703,6 +703,8 @@ cdef class LaurentSeries(AlgebraElement): t^-5 + t^-4 + t^3 + O(t^10) sage: f.O(-4) t^-5 + O(t^-4) + sage: f.O(15) + t^-5 + t^-4 + t^3 + O(t^10) """ return self.add_bigoh(prec) From a0d1e19b22522c31a49463717506511247281567 Mon Sep 17 00:00:00 2001 From: Koen van Woerden Date: Thu, 28 Sep 2017 12:23:32 +0200 Subject: [PATCH 126/218] Expand docstring. Expand docstring and explain what is meant by adding O(q^prec). --- src/sage/rings/laurent_series_ring_element.pyx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 2aee1cc232b..710454f5f0d 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -694,8 +694,13 @@ cdef class LaurentSeries(AlgebraElement): def O(self, prec): r""" Return the Laurent series of precision at most ``prec`` got by adding - `O(q^\text{prec})` to `f`, where `q` is the variable. - + `O(q^\text{prec})` to `f`, where `q` is the variable. + + The precision of `f` and the integer ``prec`` can be arbitrary. The + resulting Laurent series will have precision equal to the minimum of + the precision of `f` and ``prec``. The term `O(q^\text{prec})` is the + zero series with precision ``prec``. + EXAMPLES:: sage: R. = LaurentSeriesRing(QQ) From b9670952c258c69d6350e91a8d926916ccce3399 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sat, 30 Sep 2017 10:53:13 +0200 Subject: [PATCH 127/218] Minor corrections regarding multivector fields --- src/sage/manifolds/differentiable/diff_map.py | 9 ++++++--- .../differentiable/multivectorfield.py | 18 ++++++++++-------- .../manifolds/differentiable/scalarfield.py | 2 +- .../differentiable/tensorfield_module.py | 9 +++------ 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py index 4e897f48b66..366a6c0518a 100644 --- a/src/sage/manifolds/differentiable/diff_map.py +++ b/src/sage/manifolds/differentiable/diff_map.py @@ -928,7 +928,8 @@ def _pullback_chart(diff_map, tensor): dom1 = diff_map._domain dom2 = diff_map._codomain ncov = tensor._tensor_type[1] - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if diff_map._name is not None and tensor._name is not None: resu_name = diff_map._name + '_*(' + tensor._name + ')' if (diff_map._latex_name is not None and @@ -1001,7 +1002,8 @@ def _pullback_chart(diff_map, tensor): if ncon != 0: raise TypeError("the pullback cannot be taken on a tensor " + "with some contravariant part") - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and tensor._name is not None: resu_name = self._name + '_*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: @@ -1214,7 +1216,8 @@ def pushforward(self, tensor): res += t ptcomp[ind_new] = res # Name of the result: - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and tensor._name is not None: resu_name = self._name + '^*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 8411f47a7b8..ec01d6e99df 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -566,14 +566,15 @@ def bracket(self, other): INPUT: - - ``other`` -- a multivector field, `b` say + - ``other`` -- a multivector field OUTPUT: - instance of :class:`MultivectorField` (or of :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` if `p=1` and `q=0`) representing the - Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` and `b` is + ``other`` EXAMPLES: @@ -653,7 +654,8 @@ def bracket(self, other): return MultivectorFieldParal.bracket(self_r, other_r) # otherwise, the result is created here: # Name of the result: - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and other._name is not None: resu_name = '[' + self._name + ',' + other._name + ']' if self._latex_name is not None and other._latex_name is not None: @@ -845,8 +847,6 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: ab.lie_der(a) 2-vector field on the 3-dimensional differentiable manifold R3 - - """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -1215,14 +1215,15 @@ def bracket(self, other): INPUT: - - ``other`` -- a multivector field, `b` say + - ``other`` -- a multivector field OUTPUT: - instance of :class:`MultivectorFieldParal` (or of :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` if `p=1` and `q=0`) representing the - Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` and `b` is + ``other`` EXAMPLES: @@ -1491,7 +1492,8 @@ def bracket(self, other): else: resuc[[ind]] += sum # Name of the result: - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and other._name is not None: resu_name = '[' + self._name + ',' + other._name + ']' if self._latex_name is not None and other._latex_name is not None: diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 72b6290908b..3303434c78a 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -941,7 +941,7 @@ def bracket(self, other): INPUT: - - ``other`` -- a multivector field, of degree `p` + - ``other`` -- a multivector field of degree `p` OUTPUT: diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 2eb67cf03c4..90dd1b556f1 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -326,8 +326,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=form._latex_name, antisym=asym) for dom, rst in form._restrictions.items(): - resu._restrictions[dom] = \ - dom.tensor_field_module((0,p))(rst) + resu._restrictions[dom] = dom.tensor_field_module((0,p))(rst) return resu if isinstance(comp, MultivectorField): # coercion of a p-vector field to a type-(p,0) tensor: @@ -346,8 +345,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=pvect._latex_name, antisym=asym) for dom, rst in pvect._restrictions.items(): - resu._restrictions[dom] = \ - dom.tensor_field_module((p,0))(rst) + resu._restrictions[dom] = dom.tensor_field_module((p,0))(rst) return resu if isinstance(comp, AutomorphismField): # coercion of an automorphism to a type-(1,1) tensor: @@ -360,8 +358,7 @@ def _element_constructor_(self, comp=[], frame=None, name=None, name=autom._name, latex_name=autom._latex_name) for dom, rest in autom._restrictions.items(): - resu._restrictions[dom] = \ - dom.tensor_field_module((1,1))(rest) + resu._restrictions[dom] = dom.tensor_field_module((1,1))(rest) return resu if isinstance(comp, TensorField): # coercion by domain restriction From dc5b80a6317cd0d17d48b7e89313e4abb6a48dfe Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sat, 30 Sep 2017 14:28:28 +0200 Subject: [PATCH 128/218] trac #18395: python3 compatibility --- src/sage/graphs/generic_graph_pyx.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index cdc06afd0be..69243471569 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -77,11 +77,11 @@ def spring_layout_fast_split(G, **options): buffer = 1/sqrt(len(G)) for g in Gs: cur_pos = spring_layout_fast(g, **options) - xmin = min(x[0] for x in cur_pos.itervalues()) - xmax = max(x[0] for x in cur_pos.itervalues()) + xmin = min(x[0] for x in cur_pos.values()) + xmax = max(x[0] for x in cur_pos.values()) if len(g) > 1: buffer = (xmax - xmin)/sqrt(len(g)) - for v, loc in cur_pos.iteritems(): + for v, loc in cur_pos.items(): loc[0] += left - xmin + buffer pos[v] = loc left += xmax - xmin + buffer From fc4ef8e0eeecf09da501d9816b6ba401c0c2b016 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sat, 30 Sep 2017 17:11:31 +0200 Subject: [PATCH 129/218] Correct typo in TensorField.__call__ --- src/sage/manifolds/differentiable/tensorfield.py | 2 +- src/sage/manifolds/differentiable/vectorfield_module.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index b42f6d7200b..77214b42ac5 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -2238,7 +2238,7 @@ def __call__(self, *args): resu_rr = self_rr(*args_rr) if resu_rr.is_trivial_zero(): for chart in resu_rr._domain._atlas: - resu._express[chart] = chart._zero_function + resu._express[chart] = chart.zero_function() else: for chart, expr in resu_rr._express.items(): resu._express[chart] = expr diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index beed4d579aa..2f13188cc0b 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -41,7 +41,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.modules import Modules -from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule From 1a13169a74cf260e469c3826495989f69802c0ec Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 6 Sep 2017 15:51:22 +0200 Subject: [PATCH 130/218] PARI private header anal.h is no longer needed --- build/pkgs/pari/spkg-install | 7 ------- 1 file changed, 7 deletions(-) diff --git a/build/pkgs/pari/spkg-install b/build/pkgs/pari/spkg-install index 2c177be4f81..823c264d7f3 100644 --- a/build/pkgs/pari/spkg-install +++ b/build/pkgs/pari/spkg-install @@ -179,13 +179,6 @@ install() exit 1 fi - # Copy anal.h - cp -f "src/language/anal.h" "$SAGE_LOCAL/include/pari/anal.h" - if [ $? -ne 0 ]; then - echo >&2 "Error copying anal.h" - exit 1 - fi - cd "$CUR" } From 8304843cfa8e6d3b611a1813506f8423bdbee723 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 27 Jul 2017 12:14:48 +0200 Subject: [PATCH 131/218] Upgrade PARI to git master version --- build/pkgs/pari/checksums.ini | 6 +- build/pkgs/pari/package-version.txt | 2 +- build/pkgs/pari/patches/README.txt | 3 - build/pkgs/pari/patches/config_graphic.patch | 47 - build/pkgs/pari/patches/pari_str_1.patch | 597 ----------- build/pkgs/pari/patches/pari_str_2.patch | 19 - build/pkgs/pari/patches/plot_libpari.patch | 993 ------------------- build/pkgs/pari/patches/plot_svg.patch | 228 ----- build/pkgs/pari/patches/prot_none_1.patch | 237 ----- build/pkgs/pari/patches/prot_none_2.patch | 25 - build/pkgs/pari/patches/prot_none_3.patch | 59 -- build/pkgs/pari/patches/prot_none_4.patch | 53 - build/pkgs/pari/patches/stackwarn.patch | 30 +- 13 files changed, 20 insertions(+), 2279 deletions(-) delete mode 100644 build/pkgs/pari/patches/config_graphic.patch delete mode 100644 build/pkgs/pari/patches/pari_str_1.patch delete mode 100644 build/pkgs/pari/patches/pari_str_2.patch delete mode 100644 build/pkgs/pari/patches/plot_libpari.patch delete mode 100644 build/pkgs/pari/patches/plot_svg.patch delete mode 100644 build/pkgs/pari/patches/prot_none_1.patch delete mode 100644 build/pkgs/pari/patches/prot_none_2.patch delete mode 100644 build/pkgs/pari/patches/prot_none_3.patch delete mode 100644 build/pkgs/pari/patches/prot_none_4.patch diff --git a/build/pkgs/pari/checksums.ini b/build/pkgs/pari/checksums.ini index 9983fa901ed..8ae0dd5e0aa 100644 --- a/build/pkgs/pari/checksums.ini +++ b/build/pkgs/pari/checksums.ini @@ -1,4 +1,4 @@ tarball=pari-VERSION.tar.gz -sha1=99a8ecd47ee6cdd22098d8585db183e357fb7b71 -md5=ae178b3c984af32f2008d147e901aa76 -cksum=4215303198 +sha1=49958e45f5a198ef6462eda2b95af4994a7766eb +md5=1fb3ae3066c21baf6cd4f5fa77b190e4 +cksum=700493771 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index 97f22211f46..6b404559f12 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.9.3.p0 +2.10-1280-g88fb5b3.p0 diff --git a/build/pkgs/pari/patches/README.txt b/build/pkgs/pari/patches/README.txt index 39b66f0877a..c9b7fa89801 100644 --- a/build/pkgs/pari/patches/README.txt +++ b/build/pkgs/pari/patches/README.txt @@ -11,6 +11,3 @@ Patches to configuration files: C files: * stackwarn.patch (Jeroen Demeyer, #19883): do not display warnings regarding the stack size (unless DEBUGMEM is set). - -Bugfixes: -* polredabs.patch (Maarten Derickx, #23259): Fix bug in polredabs diff --git a/build/pkgs/pari/patches/config_graphic.patch b/build/pkgs/pari/patches/config_graphic.patch deleted file mode 100644 index 66881e37a6b..00000000000 --- a/build/pkgs/pari/patches/config_graphic.patch +++ /dev/null @@ -1,47 +0,0 @@ -commit d02e043959bd90e7354e7675633abb8de5f27857 -Author: Jeroen Demeyer -Date: Mon Jan 9 16:06:02 2017 +0100 - - Simplify handling of --graphic option and check validity - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index def1a9c..bba22ff 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -69,6 +69,7 @@ esac - PLOTCFLAGS= - PLOTLIBS= - postconfig=: -+plotrunpath= - case "$which_graphic_lib" in - none) - graph=plotnull;; -@@ -90,20 +91,18 @@ fltk) - win32) - PLOTLIBS="-lgdi32" - graph=plotWin32;; -+X11) -+ PLOTCFLAGS="$PLOTCFLAGS $X11_INC" -+ PLOTLIBS="$PLOTLIBS $X11_LIBS" -+ plotrunpath=$X11 -+ graph=plotX;; -+*) -+ echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." -+ exit 1;; - esac - graph="plotport $graph" - libgraph="plottty" - --plotrunpath= --case "$which_graphic_lib" in -- *X11*) -- PLOTCFLAGS="$PLOTCFLAGS $X11_INC" -- PLOTLIBS="$PLOTLIBS $X11_LIBS" -- plotrunpath=$X11 -- graph="plotX $graph" -- ;; --esac -- - KERNOBJS= - for f in $kernel; do - KERNOBJS="$KERNOBJS $f\$(_O)" diff --git a/build/pkgs/pari/patches/pari_str_1.patch b/build/pkgs/pari/patches/pari_str_1.patch deleted file mode 100644 index f340d343b86..00000000000 --- a/build/pkgs/pari/patches/pari_str_1.patch +++ /dev/null @@ -1,597 +0,0 @@ -commit 723b30bbad0e9f6aa578c87a843ece37655b4cfd -Author: Karim Belabas -Date: Tue Jan 24 17:24:57 2017 +0100 - - 34- [libpari] str_init, str_printf, str_putc, str_puts - -diff --git a/doc/usersch5.tex b/doc/usersch5.tex -index 213ddec..02cdf94 100644 ---- a/doc/usersch5.tex -+++ b/doc/usersch5.tex -@@ -11744,6 +11744,35 @@ not a malloc'ed string. - \fun{GEN}{gvsprintf}{const char *fmt, va_list ap} variadic version of - \tet{gsprintf} - -+\subsec{Dynamic strings} -+ -+A \tet{pari_str} is a dynamic string which grows dynamically as needed. -+This structure contains private data and two public members \kbd{char *string}, -+which is the string itself and \kbd{use\_stack} which tells whether the -+string lives -+ -+\item on the PARI stack (value $1$), meaning that it will be destroyed by any -+manipulation of the stack, e.g. a \kbd{gerepile} call or resetting -+\kbd{avma}; -+ -+\item in malloc'ed memory (value $0$), in which case it is impervious to -+stack manipulation but will need to be explicitly freed by the user -+after use, via \kbd{pari\_free(s.string)}. -+ -+ -+\fun{void}{str_init}{pari_str *S, int use_stack} initializes a dynamic -+string; if \kbd{use\_stack} is 0, then the string is malloc'ed, else -+it lives on the PARI stack. -+ -+\fun{void}{str_printf}{pari_str *S, const char *fmt, ...} write to the end -+of $S$ the remaining arguments according to PARI format \kbd{fmt}. -+ -+\fun{void}{str_putc}{pari_str *S, char c} write the character $c$ to the end -+of $S$. -+ -+\fun{void}{str_puts}{pari_str *S, const char *s} write the string $s$ to the -+end of $S$. -+ - \section{Output} - - \subsec{Output contexts} -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index a0da6e6..391873d 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -2806,6 +2806,10 @@ void printtex(GEN g); - char* stack_sprintf(const char *fmt, ...); - char* stack_strcat(const char *s, const char *t); - char* stack_strdup(const char *s); -+void str_init(pari_str *S, int use_stack); -+void str_printf(pari_str *S, const char *fmt, ...); -+void str_putc(pari_str *S, char c); -+void str_puts(pari_str *S, char c); - void strftime_expand(const char *s, char *buf, long max); - GEN Strprintf(const char *fmt, GEN args); - FILE* switchin(const char *name); -diff --git a/src/headers/paristio.h b/src/headers/paristio.h -index 7abce5d..a4fec9e 100644 ---- a/src/headers/paristio.h -+++ b/src/headers/paristio.h -@@ -17,6 +17,14 @@ typedef struct { - long s, us; - } pari_timer; - -+typedef struct pari_str { -+ char *string; /* start of the output buffer */ -+ char *end; /* end of the output buffer */ -+ char *cur; /* current writing place in the output buffer */ -+ size_t size; /* buffer size */ -+ int use_stack; /* use stack_malloc instead of malloc ? */ -+} pari_str; -+ - typedef unsigned char *byteptr; - typedef ulong pari_sp; - -diff --git a/src/language/es.c b/src/language/es.c -index 90ce368..e1bfc8d 100644 ---- a/src/language/es.c -+++ b/src/language/es.c -@@ -41,23 +41,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - - static const char esc = (0x1f & '['); /* C-[ = escape */ - --typedef struct outString { -- char *string; /* start of the output buffer */ -- char *end; /* end of the output buffer */ -- char *cur; /* current writing place in the output buffer */ -- size_t size; /* buffer size */ -- int use_stack; /* use stack_malloc instead of malloc ? */ --} outString; -+typedef void (*OUT_FUN)(GEN, pariout_t *, pari_str *); - --typedef void (*OUT_FUN)(GEN, pariout_t *, outString *); -+static void bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign); -+static void matbruti(GEN g, pariout_t *T, pari_str *S); -+static void texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign); - --static void bruti_sign(GEN g, pariout_t *T, outString *S, int addsign); --static void matbruti(GEN g, pariout_t *T, outString *S); --static void texi_sign(GEN g, pariout_t *T, outString *S, int addsign); -- --static void bruti(GEN g, pariout_t *T, outString *S) -+static void bruti(GEN g, pariout_t *T, pari_str *S) - { bruti_sign(g,T,S,1); } --static void texi(GEN g, pariout_t *T, outString *S) -+static void texi(GEN g, pariout_t *T, pari_str *S) - { texi_sign(g,T,S,1); } - - void -@@ -877,7 +869,7 @@ absrtostr(GEN x, int sp, char FORMAT, long wanted_dec) - - /* l = old len, L = new len */ - static void --str_alloc0(outString *S, long l, long L) -+str_alloc0(pari_str *S, long l, long L) - { - char *s; - if (S->use_stack) -@@ -896,20 +888,21 @@ str_alloc0(outString *S, long l, long L) - * To avoid automatic extension in between av = avma / avma = av pairs - * [ would destroy S->string if (S->use_stack) ] */ - static void --str_alloc(outString *S, long l) -+str_alloc(pari_str *S, long l) - { - l *= 20; - if (S->end - S->cur <= l) - str_alloc0(S, S->cur - S->string, S->size + maxss(S->size, l)); - } --static void --str_putc(outString *S, char c) { -+void -+str_putc(pari_str *S, char c) -+{ - *S->cur++ = c; - if (S->cur == S->end) str_alloc0(S, S->size, S->size << 1); - } - --static void --str_init(outString *S, int use_stack) -+void -+str_init(pari_str *S, int use_stack) - { - char *s; - S->size = 1024; -@@ -918,14 +911,15 @@ str_init(outString *S, int use_stack) - s = (char*)stack_malloc(S->size); - else - s = (char*)pari_malloc(S->size); -+ *s = 0; - S->string = S->cur = s; - S->end = S->string + S->size; - } --static void --str_puts(outString *S, const char *s) { while (*s) str_putc(S, *s++); } -+void -+str_puts(pari_str *S, const char *s) { while (*s) str_putc(S, *s++); } - - static void --str_putscut(outString *S, const char *str, int cut) -+str_putscut(pari_str *S, const char *str, int cut) - { - if (cut < 0) str_puts(S, str); - else { -@@ -937,7 +931,7 @@ str_putscut(outString *S, const char *str, int cut) - static char * - stack_GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) - { -- outString S; str_init(&S, 1); -+ pari_str S; str_init(&S, 1); - out(x, T, &S); *S.cur = 0; - return S.string; - } -@@ -951,14 +945,14 @@ static char * - GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) - { - pari_sp av = avma; -- outString S; str_init(&S, 0); -+ pari_str S; str_init(&S, 0); - out(x, T, &S); *S.cur = 0; - avma = av; return S.string; - } - - /* lbuf = strlen(buf), len < 0: unset */ - static void --outpad(outString *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad) -+outpad(pari_str *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad) - { - long padlen = len - lbuf; - if (padlen < 0) padlen = 0; -@@ -983,7 +977,7 @@ outpad(outString *S, const char *buf, long lbuf, int sign, long ljust, long len, - - /* len < 0 or maxwidth < 0: unset */ - static void --fmtstr(outString *S, const char *buf, int ljust, int len, int maxwidth) -+fmtstr(pari_str *S, const char *buf, int ljust, int len, int maxwidth) - { - int padlen, lbuf = strlen(buf); - -@@ -1000,9 +994,10 @@ fmtstr(outString *S, const char *buf, int ljust, int len, int maxwidth) - /* abs(base) is 8, 10, 16. If base < 0, some "alternate" form - * -- print hex in uppercase - * -- prefix octal with 0 -- * signvalue = -1: unsigned, otherwise ' ' or '+' */ -+ * signvalue = -1: unsigned, otherwise ' ' or '+'. Leaves a messy stack if -+ * S->use_stack */ - static void --fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, -+fmtnum(pari_str *S, long lvalue, GEN gvalue, int base, int signvalue, - int ljust, int len, int zpad) - { - int caps; -@@ -1010,7 +1005,7 @@ fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, - long lbuf, mxl; - GEN uvalue = NULL; - ulong ulvalue = 0; -- pari_sp av = avma; /* Assume !S->use_stack */ -+ pari_sp av = avma; - - if (gvalue) - { -@@ -1159,7 +1154,7 @@ fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, - lbuf = (buf0 - buf) - 1; - END: - outpad(S, buf, lbuf, signvalue, ljust, len, zpad); -- avma = av; -+ if (!S->use_stack) avma = av; - } - - static GEN -@@ -1213,10 +1208,10 @@ get_sigd(GEN gvalue, char ch, int maxwidth) - } - - static void --fmtreal(outString *S, GEN gvalue, int space, int signvalue, int FORMAT, -+fmtreal(pari_str *S, GEN gvalue, int space, int signvalue, int FORMAT, - int maxwidth, int ljust, int len, int zpad) - { -- pari_sp av = avma; /* Assume !S->use_stack */ -+ pari_sp av = avma; - long sigd; - char *buf; - -@@ -1281,14 +1276,16 @@ fmtreal(outString *S, GEN gvalue, int space, int signvalue, int FORMAT, - buf = absrtostr(gvalue, space, FORMAT, sigd); - if (signe(gvalue) < 0) signvalue = '-'; - outpad(S, buf, strlen(buf), signvalue, ljust, len, zpad); -- avma = av; -+ if (!S->use_stack) avma = av; - } --/* format handling "inspired" by the standard draft at -+/* Format handling "inspired" by the standard draft at - -- http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf pages 274ff - * fmt is a standard printf format, except 'P' is a "length modifier" -- * allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list */ --static char * --sm_dopr(const char *fmt, GEN arg_vector, va_list args) -+ * allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list. -+ * Appent output to the pari_str S, which must be initialized; clean if -+ * !S->use_stack, else leaves objects of stack. */ -+static void -+str_arg_vprintf(pari_str *S, const char *fmt, GEN arg_vector, va_list args) - { - int GENflag = 0, longflag = 0, pointflag = 0; - int print_plus, print_blank, with_sharp, ch, ljust, len, maxwidth, zpad; -@@ -1296,9 +1293,6 @@ sm_dopr(const char *fmt, GEN arg_vector, va_list args) - int index = 1; - GEN gvalue; - const char *save_fmt = fmt; -- outString __S, *S = &__S; -- -- str_init(S, 0); - - while ((ch = *fmt++) != '\0') { - switch(ch) { -@@ -1453,7 +1447,8 @@ nextch: - } - if (gvalue) strvalue = GENtostr_unquoted(gvalue); - fmtstr(S, strvalue, ljust, len, maxwidth); -- avma = av; break; -+ if (!S->use_stack) avma = av; -+ break; - } - case 'c': - if (arg_vector) { -@@ -1489,7 +1484,8 @@ nextch: - } - fmtreal(S, gvalue, GP_DATA->fmt->sp, dosign(print_blank,print_plus), - ch, maxwidth, ljust, len, zpad); -- avma = av; break; -+ if (!S->use_stack) avma = av; -+ break; - } - default: - pari_err(e_MISC, "invalid conversion or specification %c in format `%s'", ch, save_fmt); -@@ -1501,7 +1497,6 @@ nextch: - } /* first switch on ch */ - } /* while loop on ch */ - *S->cur = 0; -- return S->string; - } - - void -@@ -1976,7 +1971,7 @@ itostr(GEN x) { - - /* x != 0 t_INT, write abs(x) to S */ - static void --str_absint(outString *S, GEN x) -+str_absint(pari_str *S, GEN x) - { - pari_sp av; - long l; -@@ -1993,7 +1988,7 @@ str_absint(outString *S, GEN x) - - /* print e to S (more efficient than sprintf) */ - static void --str_ulong(outString *S, ulong e) -+str_ulong(pari_str *S, ulong e) - { - if (e == 0) str_putc(S, '0'); - else -@@ -2010,14 +2005,14 @@ str_ulong(outString *S, ulong e) - } - } - static void --str_long(outString *S, long e) -+str_long(pari_str *S, long e) - { - if (e >= 0) str_ulong(S, (ulong)e); - else { str_putc(S, '-'); str_ulong(S, -(ulong)e); } - } - - static void --wr_vecsmall(pariout_t *T, outString *S, GEN g) -+wr_vecsmall(pariout_t *T, pari_str *S, GEN g) - { - long i, l; - str_puts(S, "Vecsmall(["); l = lg(g); -@@ -2103,7 +2098,7 @@ blancs(long nb) { while (nb-- > 0) pari_putc(' '); } - - /* write an "address" */ - static void --str_addr(outString *S, ulong x) -+str_addr(pari_str *S, ulong x) - { char s[128]; sprintf(s,"%0*lx", BITS_IN_LONG/4, x); str_puts(S, s); } - static void - dbg_addr(ulong x) { pari_printf("[&=%0*lx] ", BITS_IN_LONG/4, x); } -@@ -2578,7 +2573,7 @@ isdenom(GEN g) - /********************************************************************/ - /* ^e */ - static void --texexpo(outString *S, long e) -+texexpo(pari_str *S, long e) - { - if (e != 1) { - str_putc(S, '^'); -@@ -2591,27 +2586,27 @@ texexpo(outString *S, long e) - } - } - static void --wrexpo(outString *S, long e) -+wrexpo(pari_str *S, long e) - { if (e != 1) { str_putc(S, '^'); str_long(S, e); } } - - /* v^e */ - static void --VpowE(outString *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); } -+VpowE(pari_str *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); } - static void --texVpowE(outString *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); } -+texVpowE(pari_str *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); } - static void --monome(outString *S, const char *v, long e) -+monome(pari_str *S, const char *v, long e) - { if (e) VpowE(S, v, e); else str_putc(S, '1'); } - static void --texnome(outString *S, const char *v, long e) -+texnome(pari_str *S, const char *v, long e) - { if (e) texVpowE(S, v, e); else str_putc(S, '1'); } - - /* ( a ) */ - static void --paren(pariout_t *T, outString *S, GEN a) -+paren(pariout_t *T, pari_str *S, GEN a) - { str_putc(S, '('); bruti(a,T,S); str_putc(S, ')'); } - static void --texparen(pariout_t *T, outString *S, GEN a) -+texparen(pariout_t *T, pari_str *S, GEN a) - { - if (T->TeXstyle & TEXSTYLE_PAREN) - str_puts(S, " ("); -@@ -2626,15 +2621,15 @@ texparen(pariout_t *T, outString *S, GEN a) - - /* * v^d */ - static void --times_texnome(outString *S, const char *v, long d) -+times_texnome(pari_str *S, const char *v, long d) - { if (d) { str_puts(S, "\\*"); texnome(S,v,d); } } - static void --times_monome(outString *S, const char *v, long d) -+times_monome(pari_str *S, const char *v, long d) - { if (d) { str_putc(S, '*'); monome(S,v,d); } } - - /* write a * v^d */ - static void --wr_monome(pariout_t *T, outString *S, GEN a, const char *v, long d) -+wr_monome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) - { - long sig = isone(a); - -@@ -2648,7 +2643,7 @@ wr_monome(pariout_t *T, outString *S, GEN a, const char *v, long d) - } - } - static void --wr_texnome(pariout_t *T, outString *S, GEN a, const char *v, long d) -+wr_texnome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) - { - long sig = isone(a); - -@@ -2666,7 +2661,7 @@ wr_texnome(pariout_t *T, outString *S, GEN a, const char *v, long d) - } - - static void --wr_lead_monome(pariout_t *T, outString *S, GEN a,const char *v, long d, int addsign) -+wr_lead_monome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) - { - long sig = isone(a); - if (sig) { -@@ -2679,7 +2674,7 @@ wr_lead_monome(pariout_t *T, outString *S, GEN a,const char *v, long d, int adds - } - } - static void --wr_lead_texnome(pariout_t *T, outString *S, GEN a,const char *v, long d, int addsign) -+wr_lead_texnome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) - { - long sig = isone(a); - if (sig) { -@@ -2693,11 +2688,11 @@ wr_lead_texnome(pariout_t *T, outString *S, GEN a,const char *v, long d, int add - } - - static void --prints(GEN g, pariout_t *T, outString *S) -+prints(GEN g, pariout_t *T, pari_str *S) - { (void)T; str_long(S, (long)g); } - - static void --quote_string(outString *S, char *s) -+quote_string(pari_str *S, char *s) - { - str_putc(S, '"'); - while (*s) -@@ -2720,7 +2715,7 @@ quote_string(outString *S, char *s) - } - - static int --print_0_or_pm1(GEN g, outString *S, int addsign) -+print_0_or_pm1(GEN g, pari_str *S, int addsign) - { - long r; - if (!g) { str_puts(S, "NULL"); return 1; } -@@ -2735,7 +2730,7 @@ print_0_or_pm1(GEN g, outString *S, int addsign) - } - - static void --print_precontext(GEN g, outString *S, long tex) -+print_precontext(GEN g, pari_str *S, long tex) - { - if (lg(g)<8 || lg(gel(g,7))==1) return; - else -@@ -2755,7 +2750,7 @@ print_precontext(GEN g, outString *S, long tex) - } - - static void --print_context(GEN g, pariout_t *T, outString *S, long tex) -+print_context(GEN g, pariout_t *T, pari_str *S, long tex) - { - GEN str = closure_get_text(g); - if (lg(g)<8 || lg(gel(g,7))==1) return; -@@ -2804,7 +2799,7 @@ print_context(GEN g, pariout_t *T, outString *S, long tex) - } - - static void --bruti_intern(GEN g, pariout_t *T, outString *S, int addsign) -+bruti_intern(GEN g, pariout_t *T, pari_str *S, int addsign) - { - long l,i,j,r, tg = typ(g); - GEN a,b; -@@ -3036,14 +3031,14 @@ bruti_intern(GEN g, pariout_t *T, outString *S, int addsign) - } - - static void --bruti_sign(GEN g, pariout_t *T, outString *S, int addsign) -+bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign) - { - if (!print_0_or_pm1(g, S, addsign)) - bruti_intern(g, T, S, addsign); - } - - static void --matbruti(GEN g, pariout_t *T, outString *S) -+matbruti(GEN g, pariout_t *T, pari_str *S) - { - long i, j, r, w, l, *pad = NULL; - pari_sp av; -@@ -3060,7 +3055,7 @@ matbruti(GEN g, pariout_t *T, outString *S) - { - long lgall = 2; /* opening [ and closing ] */ - pari_sp av2; -- outString scratchstr; -+ pari_str scratchstr; - pad = cgetg(l*r+1, t_VECSMALL); /* left on stack if (S->use_stack)*/ - av2 = avma; - str_init(&scratchstr, 1); -@@ -3106,7 +3101,7 @@ matbruti(GEN g, pariout_t *T, outString *S) - /********************************************************************/ - /* this follows bruti_sign */ - static void --texi_sign(GEN g, pariout_t *T, outString *S, int addsign) -+texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign) - { - long tg,i,j,l,r; - GEN a,b; -@@ -4519,13 +4514,16 @@ out_print0(PariOUT *out, const char *sep, GEN g, long flag) - } - } - static void --str_print0(outString *S, GEN g, long flag) -+str_print0(pari_str *S, GEN g, long flag) - { - pari_sp av = avma; - OUT_FUN f = get_fun(flag); - long i, l = lg(g); -- for (i = 1; i < l; i++, avma = av) -+ for (i = 1; i < l; i++) -+ { - str_puts(S, stack_GENtostr_fun_unquoted(gel(g,i), GP_DATA->fmt, f)); -+ if (!S->use_stack) avma = av; -+ } - *(S->cur) = 0; - } - -@@ -4533,7 +4531,7 @@ str_print0(outString *S, GEN g, long flag) - char * - pari_sprint0(const char *s, GEN g, long flag) - { -- outString S; -+ pari_str S; - str_init(&S, 0); - str_puts(&S, s); - str_print0(&S, g, flag); -@@ -4544,7 +4542,7 @@ static void - print0_file(FILE *out, GEN g, long flag) - { - pari_sp av = avma; -- outString S; -+ pari_str S; - str_init(&S, 1); - str_print0(&S, g, flag); - fputs(S.string, out); -@@ -4559,7 +4557,16 @@ printsep(const char *s, GEN g) - void - printsep1(const char *s, GEN g) { out_print0(pariOut, s, g, f_RAW); pari_flush(); } - --/* dummy needed to pass a (empty!) va_list to sm_dopr */ -+static char * -+sm_dopr(const char *fmt, GEN arg_vector, va_list args) -+{ -+ pari_str s; -+ str_init(&s, 0); -+ str_arg_vprintf(&s, fmt, arg_vector, args); -+ return s.string; -+} -+ -+/* dummy needed to pass an empty va_list to sm_dopr */ - static char * - dopr_arg_vector(GEN arg_vector, const char* fmt, ...) - { -@@ -4625,6 +4632,14 @@ pari_sprintf(const char *fmt, ...) /* variadic version of Strprintf */ - va_end(ap); return s; - } - -+void -+str_printf(pari_str *S, const char *fmt, ...) -+{ -+ va_list ap; va_start(ap, fmt); -+ str_arg_vprintf(S, fmt, NULL, ap); -+ va_end(ap); -+} -+ - char * - stack_sprintf(const char *fmt, ...) - { diff --git a/build/pkgs/pari/patches/pari_str_2.patch b/build/pkgs/pari/patches/pari_str_2.patch deleted file mode 100644 index 424cdf600c8..00000000000 --- a/build/pkgs/pari/patches/pari_str_2.patch +++ /dev/null @@ -1,19 +0,0 @@ -commit 2383190eaceafc234980dfff973477edfa192875 -Author: Karim Belabas -Date: Tue Jan 24 17:29:33 2017 +0100 - - typo in previous patch - -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 391873d..0cbcf02 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -2809,7 +2809,7 @@ char* stack_strdup(const char *s); - void str_init(pari_str *S, int use_stack); - void str_printf(pari_str *S, const char *fmt, ...); - void str_putc(pari_str *S, char c); --void str_puts(pari_str *S, char c); -+void str_puts(pari_str *S, const char *s); - void strftime_expand(const char *s, char *buf, long max); - GEN Strprintf(const char *fmt, GEN args); - FILE* switchin(const char *name); diff --git a/build/pkgs/pari/patches/plot_libpari.patch b/build/pkgs/pari/patches/plot_libpari.patch deleted file mode 100644 index 6c892f6de3f..00000000000 --- a/build/pkgs/pari/patches/plot_libpari.patch +++ /dev/null @@ -1,993 +0,0 @@ -commit bd96c260a028ece5b5a76b43182d839591eac2c9 -Author: Jeroen Demeyer -Date: Mon Jan 9 15:55:05 2017 +0100 - - Move plotting frontend to libpari; initial support for multiple plotting engines - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index ddebdac..a28f9b9 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -72,26 +72,32 @@ postconfig=: - plotrunpath= - case "$which_graphic_lib" in - none) -- graph=plotnull;; -+ graph="";; - ps) -+ enable_plot_ps=yes - graph=plotps;; - Qt) -+ enable_plot_qt=yes - PLOTCFLAGS='-D__FANCY_WIN__ -I$(QTDIR)/include' - PLOTLIBS="-L\$(QTDIR)/lib $QTLIB" - graph=plotQt;; - Qt4) -+ enable_plot_qt4=yes - PLOTCFLAGS='-D__FANCY_WIN__ -I$(QTDIR)/include' - PLOTLIBS="-L\$(QTDIR)/lib $QTLIB" - graph=plotQt4;; - fltk) -+ enable_plot_fltk=yes - PLOTCFLAGS= - PLOTLIBS="$FLTK_LIBS" - postconfig='fltk-config --post ' - graph=plotfltk;; - win32) -+ enable_plot_win32=yes - PLOTLIBS="-lgdi32" - graph=plotWin32;; - X11) -+ enable_plot_x=yes - PLOTCFLAGS="$PLOTCFLAGS $X11_INC" - PLOTLIBS="$PLOTLIBS $X11_LIBS" - plotrunpath=$X11 -@@ -100,8 +106,7 @@ win32) - echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." - exit 1;; - esac --graph="plotport $graph" --libgraph="plottty" -+libgraph="plotport plottty" - - KERNOBJS= - for f in $kernel; do -@@ -736,10 +741,6 @@ for dir in basemath modules language gp graph systems mt; do - depend="./paricfg.h" - cflags="$cflags \$(DLCFLAGS)" - ;; -- plotport) -- cflags="$cflags -I$src/graph" -- depend="$RECT_H" -- ;; - plotQt) - cflags="$cflags \$(PLOTCFLAGS)" - depend="$RECT_H" -@@ -755,7 +756,7 @@ for dir in basemath modules language gp graph systems mt; do - depend="$RECT_H" - compile="\$(CXX)" - ;; -- plottty) -+ plotport|plottty) - depend="$RECT_H" - cflags="$cflags \$(DLCFLAGS)" - ;; -diff --git a/config/paricfg.h.SH b/config/paricfg.h.SH -index 6fb22fa..c0c9e04 100644 ---- a/config/paricfg.h.SH -+++ b/config/paricfg.h.SH -@@ -188,4 +188,28 @@ case $enable_tls in - yes) echo '#define ENABLE_TLS' >> $file;; - esac - -+case $enable_plot_ps in -+yes) echo '#define ENABLE_PLOT_PS' >> $file;; -+esac -+ -+case $enable_plot_qt in -+yes) echo '#define ENABLE_PLOT_QT' >> $file;; -+esac -+ -+case $enable_plot_qt4 in -+yes) echo '#define ENABLE_PLOT_QT4' >> $file;; -+esac -+ -+case $enable_plot_fltk in -+yes) echo '#define ENABLE_PLOT_FLTK' >> $file;; -+esac -+ -+case $enable_plot_win32 in -+yes) echo '#define ENABLE_PLOT_WIN32' >> $file;; -+esac -+ -+case $enable_plot_x in -+yes) echo '#define ENABLE_PLOT_X' >> $file;; -+esac -+ - echo '#endif' >> $file -diff --git a/src/functions/graphic/plotbox b/src/functions/graphic/plotbox -index 23622f3..f697015 100644 ---- a/src/functions/graphic/plotbox -+++ b/src/functions/graphic/plotbox -@@ -1,5 +1,4 @@ - Function: plotbox --Class: highlevel - Section: graphic - C-Name: rectbox - Prototype: vLGG -diff --git a/src/functions/graphic/plotclip b/src/functions/graphic/plotclip -index 367f25f..f0943e2 100644 ---- a/src/functions/graphic/plotclip -+++ b/src/functions/graphic/plotclip -@@ -1,5 +1,4 @@ - Function: plotclip --Class: highlevel - Section: graphic - C-Name: rectclip - Prototype: vL -diff --git a/src/functions/graphic/plotcolor b/src/functions/graphic/plotcolor -index 3754445..2350170 100644 ---- a/src/functions/graphic/plotcolor -+++ b/src/functions/graphic/plotcolor -@@ -1,5 +1,4 @@ - Function: plotcolor --Class: highlevel - Section: graphic - C-Name: rectcolor - Prototype: vLL -diff --git a/src/functions/graphic/plotcopy b/src/functions/graphic/plotcopy -index 2f32c64..2796f61 100644 ---- a/src/functions/graphic/plotcopy -+++ b/src/functions/graphic/plotcopy -@@ -1,5 +1,4 @@ - Function: plotcopy --Class: highlevel - Section: graphic - C-Name: rectcopy_gen - Prototype: vLLGGD0,L, -diff --git a/src/functions/graphic/plotcursor b/src/functions/graphic/plotcursor -index b685729..153527b 100644 ---- a/src/functions/graphic/plotcursor -+++ b/src/functions/graphic/plotcursor -@@ -1,5 +1,4 @@ - Function: plotcursor --Class: highlevel - Section: graphic - C-Name: rectcursor - Prototype: L -diff --git a/src/functions/graphic/plotdraw b/src/functions/graphic/plotdraw -index 0026d33..ced478c 100644 ---- a/src/functions/graphic/plotdraw -+++ b/src/functions/graphic/plotdraw -@@ -1,5 +1,4 @@ - Function: plotdraw --Class: highlevel - Section: graphic - C-Name: rectdraw_flag - Prototype: vGD0,L, -diff --git a/src/functions/graphic/ploth b/src/functions/graphic/ploth -index 63d4eca..28d2bca 100644 ---- a/src/functions/graphic/ploth -+++ b/src/functions/graphic/ploth -@@ -1,5 +1,4 @@ - Function: ploth --Class: highlevel - Section: graphic - C-Name: ploth - Prototype: V=GGEpD0,M,D0,L,\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 -@@ -112,3 +111,4 @@ Doc: high precision plot of the function $y=f(x)$ represented by the expression - ploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") - @eprog\noindent will draw respectively a circle and a circle cut by the line - $y=x$. -+ %\syn{NO} -diff --git a/src/functions/graphic/plothraw b/src/functions/graphic/plothraw -index 03ceccd..79fed03 100644 ---- a/src/functions/graphic/plothraw -+++ b/src/functions/graphic/plothraw -@@ -1,5 +1,4 @@ - Function: plothraw --Class: highlevel - Section: graphic - C-Name: plothraw - Prototype: GGD0,L, -diff --git a/src/functions/graphic/plothsizes b/src/functions/graphic/plothsizes -index 8d96047..cc247d8 100644 ---- a/src/functions/graphic/plothsizes -+++ b/src/functions/graphic/plothsizes -@@ -1,5 +1,4 @@ - Function: plothsizes --Class: highlevel - Section: graphic - C-Name: plothsizes_flag - Prototype: D0,L, -diff --git a/src/functions/graphic/plotinit b/src/functions/graphic/plotinit -index 0c6c709..4d66be6 100644 ---- a/src/functions/graphic/plotinit -+++ b/src/functions/graphic/plotinit -@@ -1,5 +1,4 @@ - Function: plotinit --Class: highlevel - Section: graphic - C-Name: initrect_gen - Prototype: vLDGDGD0,L, -diff --git a/src/functions/graphic/plotkill b/src/functions/graphic/plotkill -index 182b53b..77699bd 100644 ---- a/src/functions/graphic/plotkill -+++ b/src/functions/graphic/plotkill -@@ -1,5 +1,4 @@ - Function: plotkill --Class: highlevel - Section: graphic - C-Name: killrect - Prototype: vL -diff --git a/src/functions/graphic/plotlines b/src/functions/graphic/plotlines -index 903b50c..d1ed9f6 100644 ---- a/src/functions/graphic/plotlines -+++ b/src/functions/graphic/plotlines -@@ -1,5 +1,4 @@ - Function: plotlines --Class: highlevel - Section: graphic - C-Name: rectlines - Prototype: vLGGD0,L, -diff --git a/src/functions/graphic/plotlinetype b/src/functions/graphic/plotlinetype -index 7f96cba..bc23419 100644 ---- a/src/functions/graphic/plotlinetype -+++ b/src/functions/graphic/plotlinetype -@@ -1,5 +1,4 @@ - Function: plotlinetype --Class: highlevel - Section: graphic - C-Name: rectlinetype - Prototype: vLL -diff --git a/src/functions/graphic/plotmove b/src/functions/graphic/plotmove -index 6bdd6a6..a689794 100644 ---- a/src/functions/graphic/plotmove -+++ b/src/functions/graphic/plotmove -@@ -1,5 +1,4 @@ - Function: plotmove --Class: highlevel - Section: graphic - C-Name: rectmove - Prototype: vLGG -diff --git a/src/functions/graphic/plotpoints b/src/functions/graphic/plotpoints -index cc6f01d..14e7ee2 100644 ---- a/src/functions/graphic/plotpoints -+++ b/src/functions/graphic/plotpoints -@@ -1,5 +1,4 @@ - Function: plotpoints --Class: highlevel - Section: graphic - C-Name: rectpoints - Prototype: vLGG -diff --git a/src/functions/graphic/plotpointsize b/src/functions/graphic/plotpointsize -index d8ae632..1cc8a2e 100644 ---- a/src/functions/graphic/plotpointsize -+++ b/src/functions/graphic/plotpointsize -@@ -1,5 +1,4 @@ - Function: plotpointsize --Class: highlevel - Section: graphic - C-Name: rectpointsize - Prototype: vLG -diff --git a/src/functions/graphic/plotpointtype b/src/functions/graphic/plotpointtype -index e0b4c39..1dc06de 100644 ---- a/src/functions/graphic/plotpointtype -+++ b/src/functions/graphic/plotpointtype -@@ -1,5 +1,4 @@ - Function: plotpointtype --Class: highlevel - Section: graphic - C-Name: rectpointtype - Prototype: vLL -diff --git a/src/functions/graphic/plotrbox b/src/functions/graphic/plotrbox -index 503695e..b55d149 100644 ---- a/src/functions/graphic/plotrbox -+++ b/src/functions/graphic/plotrbox -@@ -1,5 +1,4 @@ - Function: plotrbox --Class: highlevel - Section: graphic - C-Name: rectrbox - Prototype: vLGG -diff --git a/src/functions/graphic/plotrecth b/src/functions/graphic/plotrecth -index dcb1528..7f6c66d 100644 ---- a/src/functions/graphic/plotrecth -+++ b/src/functions/graphic/plotrecth -@@ -1,5 +1,4 @@ - Function: plotrecth --Class: highlevel - Section: graphic - C-Name: rectploth - Prototype: LV=GGEpD0,M,D0,L,\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 -@@ -8,3 +7,4 @@ Help: plotrecth(w,X=a,b,expr,{flag=0},{n=0}): - ploth(w,X=a,b,expr,flag,n). Returns a vector for the bounding box. - Doc: writes to rectwindow $w$ the curve output of - \kbd{ploth}$(w,X=a,b,\var{expr},\fl,n)$. Returns a vector for the bounding box. -+ %\syn{NO} -diff --git a/src/functions/graphic/plotrecthraw b/src/functions/graphic/plotrecthraw -index 305456c..cef2f48 100644 ---- a/src/functions/graphic/plotrecthraw -+++ b/src/functions/graphic/plotrecthraw -@@ -1,5 +1,4 @@ - Function: plotrecthraw --Class: highlevel - Section: graphic - C-Name: rectplothraw - Prototype: LGD0,L, -diff --git a/src/functions/graphic/plotrline b/src/functions/graphic/plotrline -index 0720718..86d5b77 100644 ---- a/src/functions/graphic/plotrline -+++ b/src/functions/graphic/plotrline -@@ -1,5 +1,4 @@ - Function: plotrline --Class: highlevel - Section: graphic - C-Name: rectrline - Prototype: vLGG -diff --git a/src/functions/graphic/plotrmove b/src/functions/graphic/plotrmove -index b83c493..6d4afbc 100644 ---- a/src/functions/graphic/plotrmove -+++ b/src/functions/graphic/plotrmove -@@ -1,5 +1,4 @@ - Function: plotrmove --Class: highlevel - Section: graphic - C-Name: rectrmove - Prototype: vLGG -diff --git a/src/functions/graphic/plotrpoint b/src/functions/graphic/plotrpoint -index 37648ff..707335a 100644 ---- a/src/functions/graphic/plotrpoint -+++ b/src/functions/graphic/plotrpoint -@@ -1,5 +1,4 @@ - Function: plotrpoint --Class: highlevel - Section: graphic - C-Name: rectrpoint - Prototype: vLGG -diff --git a/src/functions/graphic/plotscale b/src/functions/graphic/plotscale -index 3c81e3d..a8524c9 100644 ---- a/src/functions/graphic/plotscale -+++ b/src/functions/graphic/plotscale -@@ -1,5 +1,4 @@ - Function: plotscale --Class: highlevel - Section: graphic - C-Name: rectscale - Prototype: vLGGGG -diff --git a/src/functions/graphic/plotstring b/src/functions/graphic/plotstring -index 54792dd..ca79084 100644 ---- a/src/functions/graphic/plotstring -+++ b/src/functions/graphic/plotstring -@@ -1,5 +1,4 @@ - Function: plotstring --Class: highlevel - Section: graphic - C-Name: rectstring3 - Prototype: vLsD0,L, -diff --git a/src/functions/graphic/psdraw b/src/functions/graphic/psdraw -index 5d3f937..d2757db 100644 ---- a/src/functions/graphic/psdraw -+++ b/src/functions/graphic/psdraw -@@ -1,5 +1,4 @@ - Function: psdraw --Class: highlevel - Section: graphic - C-Name: postdraw_flag - Prototype: vGD0,L, -diff --git a/src/functions/graphic/psploth b/src/functions/graphic/psploth -index 0911e26..f6c1ffe 100644 ---- a/src/functions/graphic/psploth -+++ b/src/functions/graphic/psploth -@@ -1,5 +1,4 @@ - Function: psploth --Class: highlevel - Section: graphic - C-Name: postploth - Prototype: V=GGEpD0,L,D0,L, -diff --git a/src/functions/graphic/psplothraw b/src/functions/graphic/psplothraw -index e9b153d..4d99fe7 100644 ---- a/src/functions/graphic/psplothraw -+++ b/src/functions/graphic/psplothraw -@@ -1,5 +1,4 @@ - Function: psplothraw --Class: highlevel - Section: graphic - C-Name: postplothraw - Prototype: GGD0,L, -diff --git a/src/gp/gp.c b/src/gp/gp.c -index deaeec7..9f00381 100644 ---- a/src/gp/gp.c -+++ b/src/gp/gp.c -@@ -540,6 +540,26 @@ cyg_environment(int argc, char ** argv) - } - #endif - -+/* It's OK if none of the ENABLE_ macros are defined. This will give -+ * an error whenever ploth() is called. */ -+static void -+set_graphic_engine() -+{ -+#if defined(ENABLE_PLOT_X) -+ PARI_get_plot_X(); -+#elif defined(ENABLE_PLOT_FLTK) -+ PARI_get_plot_fltk(); -+#elif defined(ENABLE_PLOT_QT4) -+ PARI_get_plot_Qt4(); -+#elif defined(ENABLE_PLOT_QT) -+ PARI_get_plot_Qt(); -+#elif defined(ENABLE_PLOT_WIN32) -+ PARI_get_plot_Win32(); -+#elif defined(ENABLE_PLOT_PS) -+ PARI_get_plot_ps(); -+#endif -+} -+ - int - main(int argc, char **argv) - { -@@ -562,7 +582,7 @@ main(int argc, char **argv) - pari_init_defaults(); - pari_library_path = DL_DFLT_NAME; - pari_stack_init(&s_A,sizeof(*A),(void**)&A); -- pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm); -+ pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm | INIT_GRAPHm); - cb_pari_err_recover = gp_err_recover; - cb_pari_pre_recover = gp_pre_recover; - cb_pari_break_loop = break_loop; -@@ -576,7 +596,7 @@ main(int argc, char **argv) - pari_add_module(functions_gp); - pari_add_module(functions_highlevel); - -- init_graph(); -+ set_graphic_engine(); - cb_pari_quit = gp_quit; - cb_pari_whatnow = whatnow; - cb_pari_sigint = gp_sigint_fun; -@@ -643,8 +663,7 @@ dbg_up(long k) - void - gp_quit(long code) - { -- free_graph(); -- pari_close(); -+ pari_close_opts(INIT_JMPm | INIT_SIGm | INIT_DFTm | INIT_GRAPHm); - kill_buffers_upto(NULL); - if (!(GP_DATA->flags & gpd_QUIET)) pari_puts("Goodbye!\n"); - if (cb_pari_end_output) cb_pari_end_output(); -diff --git a/src/gp/gp.h b/src/gp/gp.h -index d89fdc9..6ee391f 100644 ---- a/src/gp/gp.h -+++ b/src/gp/gp.h -@@ -33,4 +33,14 @@ extern void (*cb_gp_output)(GEN z); - extern void (*cb_pari_end_output)(void); - - extern entree functions_highlevel[], functions_gp[]; -+ -+/* Architecture-dependent plot files (src/graph/plotX.c ...). -+ * Note that not all these might be compiled! */ -+void PARI_get_plot_X(void); -+void PARI_get_plot_fltk(void); -+void PARI_get_plot_Qt4(void); -+void PARI_get_plot_Qt(void); -+void PARI_get_plot_Win32(void); -+void PARI_get_plot_ps(void); -+ - ENDEXTERN -diff --git a/src/graph/plotQt.c b/src/graph/plotQt.c -index 9aa3a81..d8adebf 100644 ---- a/src/graph/plotQt.c -+++ b/src/graph/plotQt.c -@@ -566,20 +566,13 @@ void PlotWindow::save( int id) { - #endif // __FANCY_WIN__ - - -- --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// -- -- --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - // launch Qt window - int argc = 1; char *argv[] = { "gp", "-qws"}; // set argc = 2 for cross -@@ -606,10 +599,9 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Qt(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - #ifdef __QPE__ - pari_plot.width = 240; // width and - pari_plot.height = 320; // height of plot window -@@ -621,5 +613,6 @@ PARI_get_plot(void) - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotQt4.c b/src/graph/plotQt4.c -index 1ef7c40..13c8905 100644 ---- a/src/graph/plotQt4.c -+++ b/src/graph/plotQt4.c -@@ -553,20 +553,13 @@ void PlotWindow::save( int id) - #endif // __FANCY_WIN__ - - -- --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// -- -- --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - // launch Qt window - int argc = 1; // set argc = 2 for cross -@@ -593,10 +586,9 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Qt4(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - #ifdef __QPE__ - pari_plot.width = 240; // width and - pari_plot.height = 320; // height of plot window -@@ -608,5 +600,6 @@ PARI_get_plot(void) - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotWin32.c b/src/graph/plotWin32.c -index 8af4d66..6ca8b9b 100644 ---- a/src/graph/plotWin32.c -+++ b/src/graph/plotWin32.c -@@ -68,7 +68,10 @@ static void DrawString(void *data, long x, long y, char *text, long numtext) - TextOut((HDC)data, x, y, text, numtext); - } - --void rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - char tmppath[MAX_PATH], fname[MAX_PATH]; - struct plot_eng plotWin32; -@@ -102,13 +105,11 @@ void rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Win32(void) - { - HDC hdc; - TEXTMETRIC tm; -- if (pari_plot.init) return; /* pari_plot is already set */ - -- pari_plot.init = 1; - pari_plot.width = GetSystemMetrics(SM_CXSCREEN)/2; - pari_plot.height = GetSystemMetrics(SM_CYSCREEN)/2; - pari_plot.hunit = pari_plot.width/100; -@@ -121,4 +122,6 @@ PARI_get_plot(void) - - pari_plot.fwidth = tm.tmAveCharWidth; - pari_plot.fheight = tm.tmHeight; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - } -diff --git a/src/graph/plotX.c b/src/graph/plotX.c -index 13bf839..b0b6e4e 100644 ---- a/src/graph/plotX.c -+++ b/src/graph/plotX.c -@@ -154,8 +154,10 @@ PARI_ColorSetUp(Display *display, GEN colors) - } - } - --void --rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - long oldwidth,oldheight; - struct plot_eng plotX; -@@ -173,7 +175,6 @@ rectdraw0(long *w, long *x, long *y, long lw) - - if (pari_daemon()) return; /* parent process returns */ - -- PARI_get_plot(); - pari_close(); - - display = XOpenDisplay(NULL); -@@ -279,13 +280,12 @@ EXIT: - } - - void --PARI_get_plot(void) -+PARI_get_plot_X(void) - { - Display *display; - int screen; - -- if (pari_plot.init) return; -- if (!(display = XOpenDisplay(NULL))) pari_err(e_MISC, "no X server"); -+ if (!(display = XOpenDisplay(NULL))) {pari_warn(warner, "no X server"); return;} - screen = DefaultScreen(display); - pari_plot.width = DisplayWidth(display, screen) - 40; - pari_plot.height = DisplayHeight(display, screen) - 60; -@@ -293,6 +293,7 @@ PARI_get_plot(void) - pari_plot.fwidth = 9; - pari_plot.hunit = 5; - pari_plot.vunit = 5; -- pari_plot.init = 1; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - XCloseDisplay(display); - } -diff --git a/src/graph/plotfltk.c b/src/graph/plotfltk.c -index 3879728..92abcbd 100644 ---- a/src/graph/plotfltk.c -+++ b/src/graph/plotfltk.c -@@ -189,20 +189,16 @@ int Plotter::handle(int event) - } - } - --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// - --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+fltk_draw(long *w, long *x, long *y, long lw) - { - Plotter *win; - - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - Fl::visual(FL_DOUBLE|FL_INDEX); - win = new Plotter( w, x, y, lw); -@@ -215,15 +211,15 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_fltk(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - pari_plot.width = 400; // width and - pari_plot.height = 300; // height of plot window - pari_plot.hunit = 3; // - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &fltk_draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotnull.c b/src/graph/plotnull.c -deleted file mode 100644 -index fdf26e3..0000000 ---- a/src/graph/plotnull.c -+++ /dev/null -@@ -1,28 +0,0 @@ --/* Copyright (C) 2000 The PARI group. -- --This file is part of the PARI/GP package. -- --PARI/GP 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. It is distributed in the hope that it will be useful, but WITHOUT --ANY WARRANTY WHATSOEVER. -- --Check the License for details. You should have received a copy of it, along --with the package; see the file 'COPYING'. If not, write to the Free Software --Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -- --#include "pari.h" --#include "rect.h" -- --void --rectdraw0(long *w, long *x, long *y, long lw) --{ -- (void)w; -- (void)x; -- (void)y; -- (void)lw; --} -- --void --PARI_get_plot(void) --{ pari_err(e_MISC,"high resolution graphics disabled"); } -diff --git a/src/graph/plotport.c b/src/graph/plotport.c -index c6de38f..71eba71 100644 ---- a/src/graph/plotport.c -+++ b/src/graph/plotport.c -@@ -54,6 +54,13 @@ READ_EXPR(GEN code, GEN x) { - /** **/ - /********************************************************************/ - void -+PARI_get_plot(void) -+{ -+ if (!pari_plot.init) -+ pari_err(e_MISC, "high resolution graphics disabled"); -+} -+ -+void - init_graph(void) - { - long n; -@@ -1565,7 +1572,7 @@ rectplothrawin(long grect, dblPointList *data, long flags) - if (W) - { - if (W == &pari_plot) -- rectdraw0(w,wx,wy,2); -+ W->draw(w,wx,wy,2); - else - postdraw0(w,wx,wy,2, 0); - killrect(w[1]); -@@ -1704,6 +1711,7 @@ PARI_get_psplot(void) - pari_psplot.fwidth = 6; - pari_psplot.hunit = 5; - pari_psplot.vunit = 5; -+ pari_psplot.draw = NULL; /* Currently unused for ps plotting */ - } - - static void -@@ -1736,7 +1744,13 @@ gendraw(GEN list, long ps, long flag) - ne = itos(win); check_rect(ne); - w[i] = ne; - } -- if (ps) postdraw0(w,x,y,n,flag); else rectdraw0(w,x,y,n); -+ if (ps) -+ postdraw0(w,x,y,n,flag); -+ else -+ { -+ PARI_get_plot(); -+ pari_plot.draw(w,x,y,n); -+ } - pari_free(x); pari_free(y); pari_free(w); - } - -diff --git a/src/graph/plotps.c b/src/graph/plotps.c -index dcdecc1..bee35bf 100644 ---- a/src/graph/plotps.c -+++ b/src/graph/plotps.c -@@ -19,8 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "paripriv.h" - #include "rect.h" - --void --rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - struct plot_eng plot; - FILE *file; -@@ -44,14 +46,14 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_ps(void) - { -- if (pari_plot.init) return; - pari_plot.width = 400; - pari_plot.height = 300; - pari_plot.fheight = 9; - pari_plot.fwidth = 6; - pari_plot.hunit = 3; - pari_plot.vunit = 3; -- pari_plot.init = 1; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - } -diff --git a/src/graph/rect.h b/src/graph/rect.h -index b8a3476..acc78a1 100644 ---- a/src/graph/rect.h -+++ b/src/graph/rect.h -@@ -23,6 +23,7 @@ typedef struct PARI_plot { - long fheight; - long init; - char name[PLOT_NAME_LEN+1]; -+ void (*draw)(long *w, long *x, long *y, long lw); - } PARI_plot; - - extern PARI_plot pari_plot, pari_psplot; -@@ -233,54 +234,12 @@ extern long rectline_itype; - /* plotport.c */ - typedef long (*col_counter)[ROt_MAX]; - --void color_to_rgb(GEN c, int *r, int *g, int *b); --void initrect(long ne, long x, long y); --void initrect_gen(long ne, GEN x, GEN y, long flag); --void killrect(long ne); - void plot_count(long *w, long lw, col_counter rcolcnt); --GEN ploth(GEN a, GEN b, GEN code, long prec, long flag, long numpoints); --GEN ploth2(GEN a, GEN b, GEN code, long prec); --GEN plothmult(GEN a, GEN b, GEN code, long prec); --GEN plothraw(GEN listx, GEN listy, long flag); --GEN plothsizes(void); --GEN plothsizes_flag(long flag); --void postdraw(GEN list); --void postdraw_flag(GEN list, long flag); --GEN postploth(GEN a,GEN b,GEN code,long prec,long flag,long numpoints); --GEN postploth2(GEN a,GEN b,GEN code,long prec,long numpoints); --GEN postplothraw(GEN listx, GEN listy, long flag); --void psplot_init(struct plot_eng *S, FILE *f, double xscale, double yscale, long fontsize); - void Printx(dblPointList *f); --void rectbox(long ne, GEN gx2, GEN gy2); --void rectcolor(long ne, long color); --void rectcopy(long source, long dest, long xoff, long yoff); --void rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag); --GEN rectcursor(long ne); --void rectdraw(GEN list); --void rectdraw_flag(GEN list, long flag); --void rectline(long ne, GEN gx2, GEN gy2); --void rectlines(long ne, GEN listx, GEN listy, long flag); --void rectlinetype(long ne, long t); --void rectmove(long ne, GEN x, GEN y); --GEN rectploth(long drawrect,GEN a, GEN b, GEN code, long prec, ulong flags, long testpoints); --GEN rectplothraw(long drawrect, GEN data, long flags); --void rectpoint(long ne, GEN x, GEN y); --void rectpoints(long ne, GEN listx, GEN listy); --void rectpointtype(long ne, long t); --void rectpointsize(long ne, GEN size); --void rectrbox(long ne, GEN gx2, GEN gy2); --void rectrline(long ne, GEN gx2, GEN gy2); --void rectrmove(long ne, GEN x, GEN y); --void rectrpoint(long ne, GEN x, GEN y); --void rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2); --void rectstring(long ne, char *x); --void rectstring3(long ne, char *x, long dir); --void rectclip(long rect); -- --void gen_rectdraw0(struct plot_eng *eng, long *w, long *x, long *y, long lw, double xs, double ys); -- --/* architecture-dependent plot file (plotX.c ...) */ -+void psplot_init(struct plot_eng *S, FILE *f, double xscale, double yscale, long fontsize); -+ -+void gen_rectdraw0(struct plot_eng *eng, long *w, long *x, long *y, long lw, double xs, double ys); -+ - void PARI_get_plot(void); --void rectdraw0(long *w, long *x, long *y, long lw); - - ENDEXTERN -diff --git a/src/headers/paricom.h b/src/headers/paricom.h -index 356ce51..85765c9 100644 ---- a/src/headers/paricom.h -+++ b/src/headers/paricom.h -@@ -99,7 +99,8 @@ enum { - INIT_DFTm = 4, - INIT_noPRIMEm = 8, - INIT_noIMTm = 16, -- INIT_noINTGMPm = 32 -+ INIT_noINTGMPm = 32, -+ INIT_GRAPHm = 64 - }; - - #ifndef HAS_EXP2 -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 5565efe..98ee286 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -4054,6 +4054,53 @@ GEN polmodular(long L, long inv, GEN x, long yvar, long compute_derivs); - GEN polmodular_ZM(long L, long inv); - GEN polmodular_ZXX(long L, long inv, long xvar, long yvar); - -+/* plotport.c */ -+ -+void color_to_rgb(GEN c, int *r, int *g, int *b); -+void initrect(long ne, long x, long y); -+void initrect_gen(long ne, GEN x, GEN y, long flag); -+void killrect(long ne); -+GEN ploth(GEN a, GEN b, GEN code, long prec, long flag, long numpoints); -+GEN ploth2(GEN a, GEN b, GEN code, long prec); -+GEN plothmult(GEN a, GEN b, GEN code, long prec); -+GEN plothraw(GEN listx, GEN listy, long flag); -+GEN plothsizes(void); -+GEN plothsizes_flag(long flag); -+void postdraw(GEN list); -+void postdraw_flag(GEN list, long flag); -+GEN postploth(GEN a,GEN b,GEN code,long prec,long flag,long numpoints); -+GEN postploth2(GEN a,GEN b,GEN code,long prec,long numpoints); -+GEN postplothraw(GEN listx, GEN listy, long flag); -+void rectbox(long ne, GEN gx2, GEN gy2); -+void rectcolor(long ne, long color); -+void rectcopy(long source, long dest, long xoff, long yoff); -+void rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag); -+GEN rectcursor(long ne); -+void rectdraw(GEN list); -+void rectdraw_flag(GEN list, long flag); -+void rectline(long ne, GEN gx2, GEN gy2); -+void rectlines(long ne, GEN listx, GEN listy, long flag); -+void rectlinetype(long ne, long t); -+void rectmove(long ne, GEN x, GEN y); -+GEN rectploth(long drawrect,GEN a, GEN b, GEN code, long prec, ulong flags, long testpoints); -+GEN rectplothraw(long drawrect, GEN data, long flags); -+void rectpoint(long ne, GEN x, GEN y); -+void rectpoints(long ne, GEN listx, GEN listy); -+void rectpointtype(long ne, long t); -+void rectpointsize(long ne, GEN size); -+void rectrbox(long ne, GEN gx2, GEN gy2); -+void rectrline(long ne, GEN gx2, GEN gy2); -+void rectrmove(long ne, GEN x, GEN y); -+void rectrpoint(long ne, GEN x, GEN y); -+void rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2); -+void rectstring(long ne, char *x); -+void rectstring3(long ne, char *x, long dir); -+void rectclip(long rect); -+ -+/* plottty.c */ -+ -+void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); -+ - /* prime.c */ - - long BPSW_isprime(GEN x); -@@ -4161,7 +4208,6 @@ GEN derivfunk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long - int forvec_init(forvec_t *T, GEN x, long flag); - GEN forvec_next(forvec_t *T); - GEN limitnum(void *E, GEN (*f)(void *,GEN,long), long muli, GEN alpha, long prec); --void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); - GEN polzag(long n, long m); - GEN prodeuler(void *E, GEN (*eval)(void *, GEN), GEN ga, GEN gb, long prec); - GEN prodinf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); -diff --git a/src/language/init.c b/src/language/init.c -index 1524531..7c8e7de 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -883,6 +883,7 @@ pari_init_opts(size_t parisize, ulong maxprime, ulong init_opts) - try_to_recover = 1; - if (!(init_opts&INIT_noIMTm)) pari_mt_init(); - if ((init_opts&INIT_SIGm)) pari_sig_init(pari_sighandler); -+ if ((init_opts&INIT_GRAPHm)) init_graph(); - } - - void -@@ -936,6 +937,7 @@ pari_close_opts(ulong init_opts) - free((void*)GP_DATA->prompt_cont); - free((void*)GP_DATA->histfile); - } -+ if (init_opts&INIT_GRAPHm) free_graph(); - BLOCK_SIGINT_END; - } - diff --git a/build/pkgs/pari/patches/plot_svg.patch b/build/pkgs/pari/patches/plot_svg.patch deleted file mode 100644 index 0d640051cd5..00000000000 --- a/build/pkgs/pari/patches/plot_svg.patch +++ /dev/null @@ -1,228 +0,0 @@ -commit 6ce728df0719490910a3f73cd075704af9e7b0e8 -Author: Jeroen Demeyer -Date: Wed Jan 11 09:56:02 2017 +0100 - - Implement SVG plotting - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index a28f9b9..c50024e 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -106,7 +106,7 @@ win32) - echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." - exit 1;; - esac --libgraph="plotport plottty" -+libgraph="plotport plottty plotsvg" - - KERNOBJS= - for f in $kernel; do -@@ -756,7 +756,7 @@ for dir in basemath modules language gp graph systems mt; do - depend="$RECT_H" - compile="\$(CXX)" - ;; -- plotport|plottty) -+ plotport|plotsvg|plottty) - depend="$RECT_H" - cflags="$cflags \$(DLCFLAGS)" - ;; -diff --git a/src/graph/plotsvg.c b/src/graph/plotsvg.c -new file mode 100644 -index 0000000..844ef2e ---- /dev/null -+++ b/src/graph/plotsvg.c -@@ -0,0 +1,177 @@ -+/* Copyright (C) 2017 The PARI group. -+ -+This file is part of the PARI/GP package. -+ -+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. -+ -+This program is distributed in the hope that it will be useful, -+but WITHOUT ANY WARRANTY; without even the implied warranty of -+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+GNU General Public License for more details. -+ -+You should have received a copy of the GNU General Public License along -+with this program; if not, write to the Free Software Foundation, Inc., -+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+*/ -+ -+#include "pari.h" -+#include "paripriv.h" -+#include "rect.h" -+ -+/* Callback function to be called whenever an SVG plot is produced. -+ * The callback takes one argument, a const char* containing the text of -+ * the SVG file. */ -+cb_plot_svg_t cb_plot_svg = pari_puts; -+ -+struct svg_data { -+ pari_str str; -+ char hexcolor[8]; /* "#rrggbb\0" */ -+}; -+#define data_str(d) (&((struct svg_data*)(d))->str) -+#define data_hexcolor(d) (((struct svg_data*)(d))->hexcolor) -+ -+static const char hexdigit[16] = "0123456789abcdef"; -+ -+/* Work with precision 1/scale */ -+static const float scale = 1024.0; -+#define rescale(x) ((float)(x) / scale) -+ -+ -+static void -+svg_point(void *data, long x, long y) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_line(void *data, long x1, long y1, long x2, long y2) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_rect(void *data, long x, long y, long w, long h) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_points(void *data, long nb, struct plot_points *p) -+{ -+ long i; -+ for (i = 0; i < nb; i++) -+ svg_point(data, p[i].x, p[i].y); -+} -+ -+static void -+svg_color(void *data, long col) -+{ -+ int r, g, b; -+ char *hexcolor = data_hexcolor(data); -+ color_to_rgb(gel(GP_DATA->colormap, col+1), &r, &g, &b); -+ hexcolor[0] = '#'; -+ hexcolor[1] = hexdigit[r / 16]; -+ hexcolor[2] = hexdigit[r & 15]; -+ hexcolor[3] = hexdigit[g / 16]; -+ hexcolor[4] = hexdigit[g & 15]; -+ hexcolor[5] = hexdigit[b / 16]; -+ hexcolor[6] = hexdigit[b & 15]; -+ hexcolor[7] = '\0'; -+} -+ -+static void -+svg_lines(void *data, long nb, struct plot_points *p) -+{ -+ long i; -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_text(void *data, long x, long y, char *text, long numtext) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "%s\n", -+ rescale(x), rescale(y), pari_plot.fheight, data_hexcolor(data), text); -+} -+ -+static void -+svg_head(pari_str *S) -+{ -+ str_printf(S, "\n", -+ pari_plot.width, pari_plot.height); -+} -+ -+static void -+svg_tail(pari_str *S) -+{ -+ str_printf(S, "\n"); -+} -+ -+ -+/* Interface to PARI's plotting functions */ -+static void -+svg_draw(long *w, long *x, long *y, long lw) -+{ -+ struct plot_eng pl; -+ struct svg_data data; -+ -+ /* Initialize data */ -+ str_init(&data.str, 0); -+ svg_color(&data, 0); -+ -+ /* Initialize pl */ -+ pl.data = &data; -+ pl.sc = &svg_color; -+ pl.pt = &svg_point; -+ pl.ln = &svg_line; -+ pl.bx = &svg_rect; -+ pl.mp = &svg_points; -+ pl.ml = &svg_lines; -+ pl.st = &svg_text; -+ pl.pl = &pari_plot; -+ -+ svg_head(&data.str); -+ gen_rectdraw0(&pl, w, x, y, lw, scale, scale); -+ svg_tail(&data.str); -+ -+ cb_plot_svg(data.str.string); -+ pari_free(data.str.string); -+} -+ -+void -+PARI_get_plot_svg() -+/* This function initialises the structure rect.h: pari_plot */ -+{ -+ pari_plot.width = 480; // width and -+ pari_plot.height = 320; // height of plot window -+ pari_plot.hunit = 3; // -+ pari_plot.vunit = 3; // -+ pari_plot.fwidth = 9; // font width -+ pari_plot.fheight = 12; // and height -+ pari_plot.draw = &svg_draw; -+ pari_plot.init = 1; // flag: pari_plot is set now! -+} -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 98ee286..293732f 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -4097,6 +4097,12 @@ void rectstring(long ne, char *x); - void rectstring3(long ne, char *x, long dir); - void rectclip(long rect); - -+/* plotsvg.c */ -+ -+typedef void (*cb_plot_svg_t)(const char *svg); -+void PARI_get_plot_svg(); -+extern cb_plot_svg_t cb_plot_svg; -+ - /* plottty.c */ - - void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); diff --git a/build/pkgs/pari/patches/prot_none_1.patch b/build/pkgs/pari/patches/prot_none_1.patch deleted file mode 100644 index 45d338f426e..00000000000 --- a/build/pkgs/pari/patches/prot_none_1.patch +++ /dev/null @@ -1,237 +0,0 @@ -commit f7d82845952ec92a5c3fa6f1b8b42236f9d80c21 -Author: Jeroen Demeyer -Date: Tue Nov 22 13:39:20 2016 +0100 - - Use PROT_NONE for unused virtual stack memory - -diff --git a/config/has_mmap.c b/config/has_mmap.c -index 87d93cf..fa79053 100644 ---- a/config/has_mmap.c -+++ b/config/has_mmap.c -@@ -3,15 +3,12 @@ - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif --#ifndef MAP_NORESERVE --#define MAP_NORESERVE 0 --#endif - int main(void) - { - size_t size = sysconf(_SC_PAGE_SIZE)*1000; - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, -- MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,-1,0); -- madvise(b, size, MADV_DONTNEED); -+ MAP_PRIVATE|MAP_ANONYMOUS,-1,0); -+ mmap(b, size, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,-1,0); - munmap(b, size); - return 0; - } -diff --git a/src/language/init.c b/src/language/init.c -index 1524531..c7a90f0 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -579,14 +579,11 @@ pari_add_defaults_module(entree *ep) - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif --#ifndef MAP_NORESERVE --#define MAP_NORESERVE 0 --#endif - static void * - pari_mainstack_malloc(size_t size) - { - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, -- MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,-1,0); -+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - return (b == MAP_FAILED) ? NULL: b; - } - -@@ -596,10 +593,58 @@ pari_mainstack_mfree(void *s, size_t size) - munmap(s, size); - } - -+/* Completely discard the memory mapped between the addresses "from" -+ * and "to" (which must be page-aligned). -+ * -+ * We use mmap() with PROT_NONE, which means that the underlying memory -+ * is freed and that the kernel should not commit memory for it. We -+ * still keep the mapping such that we can change the flags to -+ * PROT_READ|PROT_WRITE later. -+ * -+ * NOTE: remapping with MAP_FIXED and PROT_NONE is not the same as -+ * calling mprotect(..., PROT_NONE) because the latter will keep the -+ * memory committed (this is in particular relevant on Linux with -+ * vm.overcommit = 2). This remains true even when calling -+ * madvise(..., MADV_DONTNEED). */ - static void --pari_mainstack_mreset(void *s, size_t size) -+pari_mainstack_mreset(pari_sp from, pari_sp to) - { -- madvise(s, size, MADV_DONTNEED); -+ size_t s = to - from; -+ mmap((void*)from, s, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -+} -+ -+/* Commit (make available) the virtual memory mapped between the -+ * addresses "from" and "to" (which must be page-aligned). -+ * Return 0 if successful, -1 if failed. */ -+static int -+pari_mainstack_mextend(pari_sp from, pari_sp to) -+{ -+ size_t s = to - from; -+ return mprotect((void*)from, s, PROT_READ|PROT_WRITE); -+} -+ -+/* Set actual stack size to the given size. This sets st->size and -+ * st->bot. If not enough system memory is available, this can fail. -+ * Return 1 if successful, 0 if failed (in that case, st->size is not -+ * changed) */ -+static int -+pari_mainstack_setsize(struct pari_mainstack *st, size_t size) -+{ -+ pari_sp newbot = st->top - size; -+ /* Align newbot to pagesize */ -+ pari_sp alignbot = newbot & ~(pari_sp)(PARI_STACK_ALIGN - 1); -+ if (pari_mainstack_mextend(alignbot, st->top)) -+ { -+ /* Making the memory available did not work: limit vsize to the -+ * current actual stack size. */ -+ st->vsize = st->size; -+ pari_warn(warnstack, st->vsize); -+ return 0; -+ } -+ pari_mainstack_mreset(st->vbot, alignbot); -+ st->bot = newbot; -+ st->size = size; -+ return 1; - } - - #else -@@ -614,7 +659,18 @@ static void - pari_mainstack_mfree(void *s, size_t size) { (void) size; free(s); } - - static void --pari_mainstack_mreset(void *s, size_t size) { (void) s; (void) size; } -+pari_mainstack_mreset(pari_sp from, pari_sp to) { (void) from; (void) to; } -+ -+static int -+pari_mainstack_mextend(pari_sp from, pari_sp to) { (void) from; (void) to; return 0; } -+ -+static int -+pari_mainstack_setsize(struct pari_mainstack *st, size_t size) -+{ -+ st->bot = st->top - size; -+ st->size = size; -+ return 1; -+} - - #endif - -@@ -643,9 +699,12 @@ pari_mainstack_alloc(struct pari_mainstack *st, size_t rsize, size_t vsize) - } - st->vsize = vsize ? s: 0; - st->rsize = minuu(rsize, s); -- st->size = st->rsize; - st->top = st->vbot+s; -- st->bot = st->top - st->size; -+ if (!pari_mainstack_setsize(st, st->rsize)) -+ { -+ /* This should never happen since we only decrease the allocated space */ -+ pari_err(e_MEM); -+ } - st->memused = 0; - } - -@@ -654,7 +713,7 @@ pari_mainstack_free(struct pari_mainstack *st) - { - pari_mainstack_mfree((void*)st->vbot, st->vsize ? st->vsize : fix_size(st->rsize)); - st->top = st->bot = st->vbot = 0; -- st->size = st->vsize =0; -+ st->size = st->vsize = 0; - } - - static void -@@ -719,31 +778,47 @@ paristack_newrsize(ulong newsize) - void - paristack_resize(ulong newsize) - { -- size_t vsize = pari_mainstack->vsize; - if (!newsize) -- newsize = pari_mainstack->size << 1; -- newsize = maxuu(minuu(newsize, vsize), pari_mainstack->size); -- pari_mainstack->size = newsize; -- pari_mainstack->bot = pari_mainstack->top - pari_mainstack->size; -- pari_warn(warner,"increasing stack size to %lu",newsize); -+ newsize = 2 * pari_mainstack->size; -+ newsize = minuu(newsize, pari_mainstack->vsize); -+ if (newsize <= pari_mainstack->size) return; -+ if (pari_mainstack_setsize(pari_mainstack, newsize)) -+ { -+ pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); -+ } - } - - void - parivstack_reset(void) - { -- pari_mainstack->size = pari_mainstack->rsize; -- pari_mainstack->bot = pari_mainstack->top - pari_mainstack->size; -- pari_mainstack_mreset((void *)pari_mainstack->vbot, -- pari_mainstack->bot-pari_mainstack->vbot); -+ pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize); - } - -+/* Enlarge the stack if needed such that the unused portion of the stack -+ * (between bot and avma) is large enough to contain x longs. */ - void - new_chunk_resize(size_t x) - { -- if (pari_mainstack->vsize==0 -- || x > (avma-pari_mainstack->vbot) / sizeof(long)) pari_err(e_STACK); -- while (x > (avma-pari_mainstack->bot) / sizeof(long)) -- paristack_resize(0); -+ ulong size, newsize, avail; -+ avail = (avma - pari_mainstack->bot) / sizeof(long); -+ if (avail >= x) return; -+ -+ /* We need to enlarge the stack. We try to at least double the -+ * stack, to avoid increasing the stack a lot of times by a small -+ * amount. */ -+ size = pari_mainstack->size; -+ newsize = size + maxuu((x - avail) * sizeof(long), size); -+ paristack_resize(newsize); -+ -+ /* Verify that we have enough space. Using a division here instead -+ * of a multiplication is safe against overflow. */ -+ avail = (avma - pari_mainstack->bot) / sizeof(long); -+ if (avail < x) -+ { -+ /* Restore old size and error out */ -+ pari_mainstack_setsize(pari_mainstack, size); -+ pari_err(e_STACK); -+ } - } - - /*********************************************************************/ -diff --git a/src/test/32/memory b/src/test/32/memory -new file mode 100644 -index 0000000..e865a17 ---- /dev/null -+++ b/src/test/32/memory -@@ -0,0 +1,8 @@ -+ *** Warning: new stack size = 1048576 (1.000 Mbytes). -+ *** at top-level: vector(100000,k,k) -+ *** ^-- -+ *** the PARI stack overflows ! -+ current stack size: 1048576 (1.000 Mbytes) -+ [hint] set 'parisizemax' to a non-zero value in your GPRC -+ -+Total time spent: 10 -diff --git a/src/test/in/memory b/src/test/in/memory -new file mode 100644 -index 0000000..2a36a9b ---- /dev/null -+++ b/src/test/in/memory -@@ -0,0 +1,2 @@ -+default(parisize, 2^20); -+vector(100000, k, k); \\ #1881 diff --git a/build/pkgs/pari/patches/prot_none_2.patch b/build/pkgs/pari/patches/prot_none_2.patch deleted file mode 100644 index 6eb3a1b829e..00000000000 --- a/build/pkgs/pari/patches/prot_none_2.patch +++ /dev/null @@ -1,25 +0,0 @@ -commit 6942fab48aeb5aa5f4ea283b04951240a3139728 -Author: Karim Belabas -Date: Mon Jan 16 16:00:37 2017 +0100 - - remove useless definitions when ! HAS_MMAP - - pari_mainstack_mreset + pari_mainstack_mextend - -diff --git a/src/language/init.c b/src/language/init.c -index c7a90f0..64783be 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -658,12 +658,6 @@ pari_mainstack_malloc(size_t s) - static void - pari_mainstack_mfree(void *s, size_t size) { (void) size; free(s); } - --static void --pari_mainstack_mreset(pari_sp from, pari_sp to) { (void) from; (void) to; } -- --static int --pari_mainstack_mextend(pari_sp from, pari_sp to) { (void) from; (void) to; return 0; } -- - static int - pari_mainstack_setsize(struct pari_mainstack *st, size_t size) - { diff --git a/build/pkgs/pari/patches/prot_none_3.patch b/build/pkgs/pari/patches/prot_none_3.patch deleted file mode 100644 index 941dbf5edc2..00000000000 --- a/build/pkgs/pari/patches/prot_none_3.patch +++ /dev/null @@ -1,59 +0,0 @@ -commit 845c0adf2be189702825a60304b79f21831cc7e0 -Author: Jeroen Demeyer -Date: Wed Jan 18 13:45:39 2017 +0000 - - Reset avma before calling parivstack_reset - -diff --git a/doc/usersch5.tex b/doc/usersch5.tex -index 58c7d04..6dc868c 100644 ---- a/doc/usersch5.tex -+++ b/doc/usersch5.tex -@@ -193,9 +193,12 @@ at most \kbd{parisizemax}. The stack content is not affected - by this operation. - - \fun{void}{parivstack_reset}{void} --resets the current stack to its default size \kbd{parisize}, --destroying its content. Used to recover memory after a --computation that enlarged the stack. -+resets the current stack to its default size \kbd{parisize}. This is -+used to recover memory after a computation that enlarged the stack. -+This function destroys the content of the enlarged stack (between -+the old and the new bottom of the stack). -+Before calling this function, you must ensure that \kbd{avma} lies -+within the new smaller stack. - - \fun{void}{paristack_newrsize}{ulong newsize} - \emph{(does not return)}. Library version of -diff --git a/src/gp/gp.c b/src/gp/gp.c -index deaeec7..3463a2d 100644 ---- a/src/gp/gp.c -+++ b/src/gp/gp.c -@@ -360,7 +360,6 @@ gp_main_loop(long ismain) - if (ismain) continue; - pop_buffer(); return z; - } -- avma = av; - if (ismain) - { - reset_ctrlc(); -@@ -384,6 +383,7 @@ gp_main_loop(long ismain) - if (GP_DATA->simplify) z = simplify_shallow(z); - pari_add_hist(z, t); - if (z != gnil && ! is_silent(b->buf) ) gp_output(z); -+ avma = av; - parivstack_reset(); - } - } -diff --git a/src/language/init.c b/src/language/init.c -index 64783be..6c69c8e 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -786,6 +786,8 @@ void - parivstack_reset(void) - { - pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize); -+ if (avma < pari_mainstack->bot) -+ pari_err_BUG("parivstack_reset [avma < bot]"); - } - - /* Enlarge the stack if needed such that the unused portion of the stack diff --git a/build/pkgs/pari/patches/prot_none_4.patch b/build/pkgs/pari/patches/prot_none_4.patch deleted file mode 100644 index 36e952855a2..00000000000 --- a/build/pkgs/pari/patches/prot_none_4.patch +++ /dev/null @@ -1,53 +0,0 @@ -commit c3dc1546580eda3bff6243cf563801c8a26ec67f -Author: Jeroen Demeyer -Date: Mon Apr 3 16:11:54 2017 +0200 - - mmap the PARI stack with MAP_NORESERVE - -diff --git a/src/language/init.c b/src/language/init.c -index 34cce31..acebe2f 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -597,12 +597,26 @@ pari_add_defaults_module(entree *ep) - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif -+#ifndef MAP_NORESERVE -+#define MAP_NORESERVE 0 -+#endif - static void * - pari_mainstack_malloc(size_t size) - { -+ /* Check that the system allows reserving "size" bytes. This is just -+ * a check, we immediately free the memory. */ - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -- return (b == MAP_FAILED) ? NULL: b; -+ if (b == MAP_FAILED) return NULL; -+ munmap(b, size); -+ -+ /* Map again, this time with MAP_NORESERVE. On some operating systems -+ * like Cygwin, this is needed because remapping with PROT_NONE and -+ * MAP_NORESERVE does not work as expected. */ -+ b = mmap(NULL, size, PROT_READ|PROT_WRITE, -+ MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); -+ if (b == MAP_FAILED) return NULL; -+ return b; - } - - static void -@@ -628,7 +642,13 @@ static void - pari_mainstack_mreset(pari_sp from, pari_sp to) - { - size_t s = to - from; -- mmap((void*)from, s, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -+ void *addr, *res; -+ if (!s) return; -+ -+ addr = (void*)from; -+ res = mmap(addr, s, PROT_NONE, -+ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); -+ if (res != addr) pari_err(e_MEM); - } - - /* Commit (make available) the virtual memory mapped between the diff --git a/build/pkgs/pari/patches/stackwarn.patch b/build/pkgs/pari/patches/stackwarn.patch index 718592bd205..c3df5f81566 100644 --- a/build/pkgs/pari/patches/stackwarn.patch +++ b/build/pkgs/pari/patches/stackwarn.patch @@ -4,10 +4,10 @@ Date: Fri Nov 4 12:37:38 2016 +0100 Use DEBUGMEM for stack size warnings -diff -ru src/src/gp/gp.c b/src/gp/gp.c ---- src/src/gp/gp.c 2017-01-30 17:36:54.045921458 +0100 -+++ b/src/gp/gp.c 2017-01-30 17:37:07.225921164 +0100 -@@ -559,6 +559,7 @@ +diff -ru a/src/gp/gp.c b/src/gp/gp.c +--- a/src/gp/gp.c 2017-07-27 12:12:00.636618453 +0200 ++++ b/src/gp/gp.c 2017-07-27 12:12:09.913617857 +0200 +@@ -553,6 +553,7 @@ #endif stdin_isatty = pari_stdin_isatty(); pari_init_defaults(); @@ -15,10 +15,10 @@ diff -ru src/src/gp/gp.c b/src/gp/gp.c pari_library_path = DL_DFLT_NAME; pari_stack_init(&s_A,sizeof(*A),(void**)&A); pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm); -diff -ru src/src/language/init.c b/src/language/init.c ---- src/src/language/init.c 2017-01-30 17:36:54.046921458 +0100 -+++ b/src/language/init.c 2017-01-30 17:37:07.227921164 +0100 -@@ -793,7 +793,8 @@ +diff -ru a/src/language/init.c b/src/language/init.c +--- a/src/language/init.c 2017-07-27 12:12:00.637618452 +0200 ++++ b/src/language/init.c 2017-07-27 12:12:57.035614831 +0200 +@@ -797,7 +797,8 @@ evalstate_reset(); paristack_setsize(pari_mainstack->rsize, newsize); s = pari_mainstack->vsize ? pari_mainstack->vsize : pari_mainstack->rsize; @@ -28,7 +28,7 @@ diff -ru src/src/language/init.c b/src/language/init.c pari_init_errcatch(); cb_pari_err_recover(-1); } -@@ -807,7 +808,8 @@ +@@ -811,7 +812,8 @@ pari_mainstack_resize(pari_mainstack, newsize, vsize); evalstate_reset(); s = pari_mainstack->rsize; @@ -38,13 +38,15 @@ diff -ru src/src/language/init.c b/src/language/init.c pari_init_errcatch(); cb_pari_err_recover(-1); } -@@ -821,7 +823,8 @@ +@@ -825,7 +827,10 @@ + newsize = minuu(newsize, pari_mainstack->vsize); if (newsize <= pari_mainstack->size) return; if (pari_mainstack_setsize(pari_mainstack, newsize)) - { - pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); ++ { + if (DEBUGMEM > 0) + pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); - } - } - ++ } + else + { + pari_mainstack_setsize(pari_mainstack, size); From 6896cc7f0e5d41822a6a4480d0f108434b02caee Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 6 Sep 2017 14:42:17 +0200 Subject: [PATCH 132/218] Fix doctests for PARI upgrade --- src/sage/groups/generic.py | 4 +-- src/sage/libs/pari/tests.py | 6 ++-- src/sage/modular/cusps_nf.py | 2 +- src/sage/modular/local_comp/smoothchar.py | 4 +-- src/sage/modular/modsym/p1list_nf.py | 4 +-- src/sage/rings/number_field/number_field.py | 10 +++--- .../rings/number_field/number_field_ideal.py | 2 +- .../rings/number_field/number_field_rel.py | 4 +-- src/sage/rings/number_field/unit_group.py | 36 +++++++++---------- .../padics/padic_capped_absolute_element.pyx | 2 +- .../padics/padic_capped_relative_element.pyx | 2 +- .../rings/padics/padic_fixed_mod_element.pyx | 2 +- src/sage/rings/qqbar.py | 4 +-- .../elliptic_curves/ell_number_field.py | 4 +-- .../schemes/projective/projective_morphism.py | 7 ++-- .../judson-abstract-algebra/fields-sage.py | 10 +++--- 16 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 32bafe93dfd..bb4d308b1e7 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -426,7 +426,7 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): sage: F. = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P - (a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) + (a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) This will return a multiple of the order of P:: @@ -860,7 +860,7 @@ def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): sage: F. = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P - (a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) + (a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) This will return a multiple of the order of P:: diff --git a/src/sage/libs/pari/tests.py b/src/sage/libs/pari/tests.py index 1f56bd2c264..cd336d2f5be 100644 --- a/src/sage/libs/pari/tests.py +++ b/src/sage/libs/pari/tests.py @@ -948,7 +948,7 @@ sage: pari('[1,2,3;4,5,6;7,8,9]').matker() [1; -2; 1] sage: pari('[1,2,3;4,5,6;7,8,9]').matker(1) - [3; -6; 3] + [1; -2; 1] sage: pari('matrix(3,3,i,j,i)').matker() [-1, -1; 1, 0; 0, 1] sage: pari('[1,2,3;4,5,6;7,8,9]*Mod(1,2)').matker() @@ -1601,7 +1601,7 @@ sage: nf = F.__pari__() sage: I = pari('[1, -1, 2]~') sage: nf.idealstar(I) - [[[43, 9, 5; 0, 1, 0; 0, 0, 1], [0]], [42, [42]], Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1]), [[[[[42], [3], [3], [Vecsmall([])], 1, [43, 9, 5; 0, 1, 0; 0, 0, 1]]]], [[], [], [], Vecsmall([])], Vecsmall([0])], Mat(1)] + [[[43, 9, 5; 0, 1, 0; 0, 0, 1], [0]], [42, [42]], [Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1]), Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1])], [[[[42], [3], [43, 9, 5; 0, 1, 0; 0, 0, 1], [[[-14, -8, 20]~, [1, 34, 38], [43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]]]~, 3, [42, [2, 1; 3, 1; 7, 1]]]]], [[], Vecsmall([])]], [Mat(1)]] sage: x = polygen(QQ) sage: K. = NumberField(x^3 - 17) @@ -1675,7 +1675,7 @@ [[1, [7605, 4]~, [5610, 5]~, [7913, -6]~; 0, 1, 0, -1; 0, 0, 1, 0; 0, 0, 0, 1], [[19320, 13720; 0, 56], [2, 1; 0, 1], 1, 1]] sage: pari('x^3 - 17').nfinit() - [x^3 - 17, [1, 1], -867, 3, [[1, 1.68006914259990, 2.57128159065824; 1, -0.340034571299952 - 2.65083754153991*I, -1.28564079532912 + 2.22679517779329*I], [1, 1.68006914259990, 2.57128159065824; 1, -2.99087211283986, 0.941154382464174; 1, 2.31080297023995, -3.51243597312241], [1, 2, 3; 1, -3, 1; 1, 2, -4], [3, 1, 0; 1, -11, 17; 0, 17, 0], [51, 0, 16; 0, 17, 3; 0, 0, 1], [17, 0, -1; 0, 0, 3; -1, 3, 2], [51, [-17, 6, -1; 0, -18, 3; 1, 0, -16]], [3, 17]], [2.57128159065824, -1.28564079532912 + 2.22679517779329*I], [1, 1/3*x^2 - 1/3*x + 1/3, x], [1, 0, -1; 0, 0, 3; 0, 1, 1], [1, 0, 0, 0, -4, 6, 0, 6, -1; 0, 1, 0, 1, 1, -1, 0, -1, 3; 0, 0, 1, 0, 2, 0, 1, 0, 1]] + [x^3 - 17, [1, 1], -867, 3, [[1, 1.68006914259990, 2.57128159065824; 1, -0.340034571299952 - 2.65083754153991*I, -1.28564079532912 + 2.22679517779329*I], [1, 1.68006914259990, 2.57128159065824; 1, -2.99087211283986, 0.941154382464174; 1, 2.31080297023995, -3.51243597312241], [1, 2, 3; 1, -3, 1; 1, 2, -4], [3, 1, 0; 1, -11, 17; 0, 17, 0], [51, 0, 16; 0, 17, 3; 0, 0, 1], [17, 0, -1; 0, 0, 3; -1, 3, 2], [51, [-17, 6, -1; 0, -18, 3; 1, 0, -16]], [3, 17]], [2.57128159065824, -1.28564079532912 + 2.22679517779329*I], [3, x^2 - x + 1, 3*x], [1, 0, -1; 0, 0, 3; 0, 1, 1], [1, 0, 0, 0, -4, 6, 0, 6, -1; 0, 1, 0, 1, 1, -1, 0, -1, 3; 0, 0, 1, 0, 2, 0, 1, 0, 1]] sage: pari('x^2 + 10^100 + 1').nfinit() [...] sage: pari('1.0').nfinit() diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 0c40a6ed2b6..baf29afced1 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -41,7 +41,7 @@ sage: alpha.ideal() Fractional ideal (7, a + 3) sage: alpha.ABmatrix() - [a + 10, -3*a + 1, 7, -2*a] + [a + 10, 2*a + 6, 7, a + 5] sage: alpha.apply([0, 1, -1,0]) Cusp [7: -a - 10] of Number Field in a with defining polynomial x^2 + 5 diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index a37c7362640..b59ee45d971 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -1601,8 +1601,8 @@ def discrete_log(self, level, x): sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ) sage: s = G.number_field().gen() sage: G.discrete_log(4, 3 + 2*s) - [5, 2, 1, 1] - sage: gs = G.unit_gens(4); gs[0]^5 * gs[1]^2 * gs[2] * gs[3] - (3 + 2*s) in G.ideal(4) + [5, 1, 1, 1] + sage: gs = G.unit_gens(4); gs[0]^5 * gs[1] * gs[2] * gs[3] - (3 + 2*s) in G.ideal(4) True """ x = self.number_field().coerce(x) diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 1b310deb9ac..f3e119c8988 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -58,7 +58,7 @@ sage: alpha = MSymbol(N, a + 2, 3*a^2) sage: alpha.lift_to_sl2_Ok() - [1, -4*a^2 + 9*a - 21, a + 2, a^2 - 3*a + 3] + [-3*a^2 + a + 12, 25*a^2 - 50*a + 100, a + 2, a^2 - 3*a + 3] sage: Ok = k.ring_of_integers() sage: M = Matrix(Ok, 2, alpha.lift_to_sl2_Ok()) sage: det(M) @@ -804,7 +804,7 @@ def lift_to_sl2_Ok(self, i): sage: P[5] M-symbol (1/2*a + 1/2: -a) of level Fractional ideal (3) sage: P.lift_to_sl2_Ok(5) - [1, -2, 1/2*a + 1/2, -a] + [-a, 2*a - 2, 1/2*a + 1/2, -a] :: diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index ca61cb3e1e0..5aeb373deb2 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -3771,7 +3771,7 @@ def pari_nf(self, important=True): sage: k. = NumberField(x^4 - 3/2*x + 5/3); k Number Field in a with defining polynomial x^4 - 3/2*x + 5/3 sage: k.pari_nf() - [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ..., [1, y, 1/36*y^3 + 1/6*y^2 - 7, 1/6*y^2], [1, 0, 0, 252; 0, 1, 0, 0; 0, 0, 0, 36; 0, 0, 6, -36], [1, 0, 0, 0, 0, 0, -18, 42, 0, -18, -46, -60, 0, 42, -60, -60; 0, 1, 0, 0, 1, 0, 2, 0, 0, 2, -11, -1, 0, 0, -1, 9; 0, 0, 1, 0, 0, 0, 6, 6, 1, 6, -5, 0, 0, 6, 0, 0; 0, 0, 0, 1, 0, 6, -6, -6, 0, -6, -1, 2, 1, -6, 2, 0]] + [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ..., [36, 36*y, y^3 + 6*y^2 - 252, 6*y^2], [1, 0, 0, 252; 0, 1, 0, 0; 0, 0, 0, 36; 0, 0, 6, -36], [1, 0, 0, 0, 0, 0, -18, 42, 0, -18, -46, -60, 0, 42, -60, -60; 0, 1, 0, 0, 1, 0, 2, 0, 0, 2, -11, -1, 0, 0, -1, 9; 0, 0, 1, 0, 0, 0, 6, 6, 1, 6, -5, 0, 0, 6, 0, 0; 0, 0, 0, 1, 0, 6, -6, -6, 0, -6, -1, 2, 1, -6, 2, 0]] sage: pari(k) [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ...] sage: gp(k) @@ -7352,7 +7352,7 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): Number Field in b with defining polynomial x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 sage: L = K.optimized_subfields(name='b') sage: L[0][0] - Number Field in b0 with defining polynomial x - 1 + Number Field in b0 with defining polynomial x sage: L[1][0] Number Field in b1 with defining polynomial x^2 - 3*x + 3 sage: [z[0] for z in L] # random -- since algorithm is random @@ -7396,10 +7396,10 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): sage: K. = NumberField(2*x^4 + 6*x^2 + 1/2) sage: K.optimized_subfields() [ - (Number Field in a0 with defining polynomial x - 1, Ring morphism: - From: Number Field in a0 with defining polynomial x - 1 + (Number Field in a0 with defining polynomial x, Ring morphism: + From: Number Field in a0 with defining polynomial x To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: 1 |--> 1, None), + Defn: 0 |--> 0, None), (Number Field in a1 with defining polynomial x^2 - 2*x + 2, Ring morphism: From: Number Field in a1 with defining polynomial x^2 - 2*x + 2 To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 099203edba3..5b30b21869a 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -2726,7 +2726,7 @@ def element_1_mod(self, other): Fractional ideal (a^2 - 4*a + 2) 68 sage: r = A.element_1_mod(B); r - -a^2 + 4*a - 1 + -33 sage: r in A True sage: 1-r in B diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index add48ce6c2d..510daf89533 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -1568,7 +1568,7 @@ def _pari_relative_structure(self): sage: L._pari_relative_structure() (x^2 + Mod(-y, y^2 + 1), Mod(Mod(1/2*y - 1/2, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)), - Mod(Mod(-y - 1, y^2 + 1)*x, x^2 + Mod(-1/2, y^2 + 1))) + Mod(Mod(-y - 1, y^2 + 1)*x, Mod(1, y^2 + 1)*x^2 + Mod(-1/2, y^2 + 1))) An example where both fields are defined by non-integral or non-monic polynomials:: @@ -1578,7 +1578,7 @@ def _pari_relative_structure(self): sage: L._pari_relative_structure() (x^2 + Mod(y, y^2 + 2)*x + 1, Mod(Mod(-1/3*y, y^2 + 2)*x + Mod(1/3, y^2 + 2), x^2 + Mod(y, y^2 + 2)*x + 1), - Mod(Mod(3/2*y, y^2 + 2)*x + Mod(-1/2*y, y^2 + 2), x^2 + Mod(-1/3, y^2 + 2))) + Mod(Mod(3/2*y, y^2 + 2)*x + Mod(-1/2*y, y^2 + 2), Mod(1, y^2 + 2)*x^2 + Mod(-1/3, y^2 + 2))) Note that in the last example, the *absolute* defining polynomials is the same for Sage and PARI, even though this is diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index 69b527bf80b..616a0d639ca 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -100,29 +100,29 @@ sage: UL.zeta_order() 24 sage: UL.roots_of_unity() - [b*a + b, - b^2*a, - -b^3, + [-b^3*a - b^3, + -b^2*a, + b, a + 1, - b*a, - -b^2, - -b^3*a - b^3, - a, - -b, - -b^2*a - b^2, -b^3*a, - -1, - -b*a - b, - -b^2*a, - b^3, - -a - 1, - -b*a, b^2, - b^3*a + b^3, - -a, - b, + b*a + b, + a, + b^3, b^2*a + b^2, + b*a, + -1, + b^3*a + b^3, + b^2*a, + -b, + -a - 1, b^3*a, + -b^2, + -b*a - b, + -a, + -b^3, + -b^2*a - b^2, + -b*a, 1] A relative extension example, which worked thanks to the code review by F.W.Clarke:: diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index b39a2e98a99..6fb1710eea7 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -138,7 +138,7 @@ cdef class pAdicCappedAbsoluteElement(CAElement): [&=...] PADIC(lg=5):... (precp=0,valp=5):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 """ cdef long val # Let val be the valuation of self, holder (defined in the diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index ac9567e52c2..9ed0f4f45f7 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -226,7 +226,7 @@ cdef class pAdicCappedRelativeElement(CRElement): [&=...] PADIC(lg=5):... (precp=0,valp=5):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 """ if exactzero(self.ordp): return pari.zero() diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index 7516e45ea17..5fce3545e05 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -204,7 +204,7 @@ cdef class pAdicFixedModElement(FMElement): [&=...] PADIC(lg=5):... (precp=0,valp=10):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 This checks that :trac:`15653` is fixed:: diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 49d2bcf178b..888d05b9bcc 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -285,7 +285,7 @@ sage: lhs - rhs 0 sage: lhs._exact_value() - 10648699402510886229334132989629606002223831*a^9 + 23174560249100286133718183712802529035435800*a^8 + 27259790692625442252605558473646959458901265*a^7 + 21416469499004652376912957054411004410158065*a^6 + 14543082864016871805545108986578337637140321*a^5 + 6458050008796664339372667222902512216589785*a^4 - 3052219053800078449122081871454923124998263*a^3 - 14238966128623353681821644902045640915516176*a^2 - 16749022728952328254673732618939204392161001*a - 9052854758155114957837247156588012516273410 where a^10 + a^9 - a^7 - a^6 - a^5 - a^4 - a^3 + a + 1 = 0 and a in 1.176280818259918? + -10648699402510886229334132989629606002223831*a^9 + 23174560249100286133718183712802529035435800*a^8 - 27259790692625442252605558473646959458901265*a^7 + 21416469499004652376912957054411004410158065*a^6 - 14543082864016871805545108986578337637140321*a^5 + 6458050008796664339372667222902512216589785*a^4 + 3052219053800078449122081871454923124998263*a^3 - 14238966128623353681821644902045640915516176*a^2 + 16749022728952328254673732618939204392161001*a - 9052854758155114957837247156588012516273410 where a^10 - a^9 + a^7 - a^6 + a^5 - a^4 + a^3 - a + 1 = 0 and a in -1.176280818259918? Given an algebraic number, we can produce a string that will reproduce that algebraic number if you type the string into Sage. We can see @@ -1752,7 +1752,7 @@ def do_polred(poly): sage: do_polred(x^2 - x - 11) (1/3*x + 1/3, 3*x - 1, x^2 - x - 1) sage: do_polred(x^3 + 123456) - (1/4*x, 4*x, x^3 + 1929) + (-1/4*x, -4*x, x^3 - 1929) This shows that :trac:`13054` has been fixed:: diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 5ff13e175f7..e550571b001 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -246,11 +246,11 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, C = Mod(y, y^2 + 7) Computing L(S,2) - L(S,2) = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(-1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(x^2 + 2, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y - 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + L(S,2) = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(-1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(x^2 + 2, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y - 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] Computing the Selmer group #LS2gen = 2 - LS2gen = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x - 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + LS2gen = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] Search for trivial points on the curve Trivial points on the curve = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7)], [1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] zc = Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index f4bb46ccd9d..2519f1a92eb 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -2072,12 +2072,9 @@ def _number_field_from_algebraics(self): sage: H = End(P) sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))*y^2, y^2]) sage: f._number_field_from_algebraics() - Scheme endomorphism of Projective Space of dimension 1 over Number Field - in a with defining polynomial y^6 + 6*y^4 + 6*y^3 + 12*y^2 - 36*y + 17 + Scheme endomorphism of Projective Space of dimension 1 over Number Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 Defn: Defined on coordinates by sending (z0 : z1) to - ((48/269*a^5 + 27/269*a^4 + 320/269*a^3 + 468/269*a^2 + 772/269*a - - 1092/269)*z0^2 + (48/269*a^5 + 27/269*a^4 + 320/269*a^3 + 468/269*a^2 - + 1041/269*a - 1092/269)*z1^2 : z1^2) + ((-48/269*a^5 + 27/269*a^4 - 320/269*a^3 + 468/269*a^2 - 772/269*a - 1092/269)*z0^2 + (48/269*a^5 - 27/269*a^4 + 320/269*a^3 - 468/269*a^2 + 1041/269*a + 1092/269)*z1^2 : z1^2) :: diff --git a/src/sage/tests/books/judson-abstract-algebra/fields-sage.py b/src/sage/tests/books/judson-abstract-algebra/fields-sage.py index e9f2ea3309d..529d6e823bb 100644 --- a/src/sage/tests/books/judson-abstract-algebra/fields-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/fields-sage.py @@ -274,10 +274,12 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: r1.as_number_field_element() - (Number Field in a with defining polynomial y^4 + y^2 - 1, a, Ring morphism: - From: Number Field in a with defining polynomial y^4 + y^2 - 1 - To: Algebraic Real Field - Defn: a |--> -0.7861513777574233?) + (Number Field in a with defining polynomial y^4 - y^2 - 1, + a^3 - a, + Ring morphism: + From: Number Field in a with defining polynomial y^4 - y^2 - 1 + To: Algebraic Real Field + Defn: a |--> -1.272019649514069?) ~~~~~~~~~~~~~~~~~~~~~~ :: From e6316470ea75a388c89e2f63c274c0c265d82641 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 16:56:16 +0000 Subject: [PATCH 133/218] Initial version of Q/Z with no documentation --- src/sage/groups/abelian_gps/qmodnz.py | 49 +++++++++++ src/sage/groups/abelian_gps/qmodnz_element.py | 81 +++++++++++++++++++ src/sage/rings/rational_field.py | 21 +++++ 3 files changed, 151 insertions(+) create mode 100644 src/sage/groups/abelian_gps/qmodnz.py create mode 100644 src/sage/groups/abelian_gps/qmodnz_element.py diff --git a/src/sage/groups/abelian_gps/qmodnz.py b/src/sage/groups/abelian_gps/qmodnz.py new file mode 100644 index 00000000000..51b6c407259 --- /dev/null +++ b/src/sage/groups/abelian_gps/qmodnz.py @@ -0,0 +1,49 @@ +from sage.groups.group import AbelianGroup +from sage.rings.all import ZZ, QQ +from sage.groups.abelian_gps.qmodnz_element import QmodnZ_Element +from sage.categories.groups import Groups +from sage.arith import srange + +class QmodnZ(AbelianGroup): + Element = QmodnZ_Element + def __init__(self, n=1): + self.n = QQ(n).abs() + category = Groups().Commutative().Topological().Infinite() + AbelianGroup.__init__(self, base=ZZ, category=category) + self._populate_coercion_lists_(coerce_list=[QQ]) + + def _repr_(self): + if self.n == 1: + return "Q/Z" + elif self.n in ZZ: + return "Q/%sZ"%(self.n) + else: + return "Q/(%s)Z"%(self.n) + + def __eq__(self, other): + if type(self) == type(other): + return self.n == other.n + return NotImplemented + + def __ne__(self, other): + if type(self) == type(other): + return self.n != other.n + return NotImplemented + + def _element_constructor_(self, x): + return self.element_class(self, QQ(x)) + + def random_element(self, *args, **kwds): + return self(QQ.random_element(*args, **kwds)) + + def __iter__(self): + if self.n == 0: + for x in QQ: + yield self(x) + else: + yield self(0) + d = ZZ(1) + while True: + for a in d.coprime_integers((d*self.n).floor()): + yield self(a/d) + d += 1 diff --git a/src/sage/groups/abelian_gps/qmodnz_element.py b/src/sage/groups/abelian_gps/qmodnz_element.py new file mode 100644 index 00000000000..93b627fb5fa --- /dev/null +++ b/src/sage/groups/abelian_gps/qmodnz_element.py @@ -0,0 +1,81 @@ + +from sage.structure.element import AdditiveGroupElement +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity +from sage.structure.richcmp import richcmp, op_EQ, op_NE + +class QmodnZ_Element(AdditiveGroupElement): + def __init__(self, parent, x, construct=False): + AdditiveGroupElement.__init__(self, parent) + # x = (a/b) = q(n/m) + r/mb + # am = q(nb) + r + # r < nb so r/mb < n/m + if construct: + self._x = x + return + n = parent.n.numerator() + if n == 0: + self._x = x + else: + m = parent.n.denominator() + a = x.numerator() + b = x.denominator() + q, r = (a*m).quo_rem(n*b) + self._x = r/(m*b) + + def lift(self): + return self._x + + def __neg__(self): + if self._x == 0: + return self + else: + QZ = self.parent() + return QZ.element_class(QZ, QZ.n - self._x, True) + + def _add_(self, other): + QZ = self.parent() + ans = self._x + other._x + if ans > QZ.n: + ans -= QZ.n + return QZ.element_class(QZ, ans, True) + + def _sub_(self, other): + QZ = self.parent() + ans = self._x - other._x + if ans < 0: + ans += QZ.n + return QZ.element_class(QZ, ans, True) + + def _rmul_(self, c): + QZ = self.parent() + return QZ.element_class(QZ, self._x * c) + + def _lmul_(self, c): + return self._rmul_(c) + + def __truediv__(self, other): + QZ = self.parent() + other = ZZ(Other) + return QZ.element_class(QZ, self._x / other, True) + + def _repr_(self): + return repr(self._x) + + def __hash__(self): + return hash(self._x) + + def _richcmp_(self, right, op): + if op == op_EQ or op == op_NE: + return richcmp(self._x, right._x, op) + else: + return NotImplemented + + def additive_order(self): + # a/b * k = n/m * r + QZ = self.parent() + if QZ.n == 0: + if self._x == 0: + return ZZ(1) + return infinity + return (self._x / QZ.n).denominator() diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 661a3d393fe..42b2f7f3592 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -426,6 +426,27 @@ def __iter__(self): yield self(height/other) yield self(-height/other) + def __truediv__(self, I): + """ + Dividing one ring by another is not supported because there is no good + way to specify generator names. + + EXAMPLES:: + + sage: QQ / ZZ + Traceback (most recent call last): + ... + TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. + """ + from sage.rings.ideal import Ideal_generic + from sage.groups.abelian_gps.qmodnz import QmodnZ + if I is ZZ: + return QmodnZ(1) + elif isinstance(I, Ideal_generic) and I.base_ring() is ZZ: + return QmodnZ(I.gen()) + else: + return super(RationalField, self).__truediv__(I) + def range_by_height(self, start, end=None): r""" Range function for rational numbers, ordered by height. From caf4da68f040bea3c0fed2bcb04cd5a3ea84994f Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sat, 30 Sep 2017 19:17:21 +0200 Subject: [PATCH 134/218] trac #18395: try abs tol 0.03 for problematic doctests --- src/sage/graphs/generic_graph_pyx.pyx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 69243471569..2bf6b2a0714 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -108,12 +108,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G) - {0: [0.00..., 0.03...], # 32-bit - ... # 32-bit - 902: [-0.48..., -0.10...]} # 32-bit - {0: [0.00..., 0.04...], # 64-bit - ... # 64-bit - 902: [-0.47..., -0.10...]} # 64-bit + {0: [0.00..., 0.04...], # abs tol 0.03 + ... # abs tol 0.03 + 902: [-0.47..., -0.10...]} # abs tol 0.03 With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -129,12 +126,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: spring_layout_fast(G, by_component = True) - {0: [2.22..., -0.00...], # 32-bit - ... # 32-bit - 902: [3.07..., 0.86...]} # 32-bit - {0: [2.21..., -0.00...], # 64-bit - ... # 64-bit - 902: [3.07..., 0.86...]} # 64-bit + {0: [2.21..., -0.00...], # abs tol 0.03 + ... # abs tol 0.03 + 902: [3.07..., 0.86...]} # abs tol 0.03 """ if by_component: From 24a5b0bcc3f31e1dcf08ce88c0c709578a8bbf7c Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 30 Sep 2017 19:27:57 +0200 Subject: [PATCH 135/218] Doctest formatting. --- src/sage/quadratic_forms/genera/genus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 47fd7c301fe..5399d98bcd2 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -1609,6 +1609,7 @@ def __eq__(self, other): True TESTS:: + sage: D4=QuadraticForm(Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2])) sage: G=D4.global_genus_symbol() sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) From 2b7ba4bf53c15d3c9a31aa9beb0db71d79808bed Mon Sep 17 00:00:00 2001 From: Amy Feaver Date: Sat, 30 Sep 2017 11:48:54 -0600 Subject: [PATCH 136/218] change annihilator when cardinality is 1 --- src/sage/modules/fg_pid/fgp_module.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 483daf15ba7..d3c01d007b1 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1592,6 +1592,8 @@ def annihilator(self): """ if not self.is_finite(): g = 0 + elif self.cardinality()==0: + g=1 else: g = reduce(lcm, self.invariants()) return self.base_ring().ideal(g) From 1013f565c676972b1c04abeb50326cf6772bf379 Mon Sep 17 00:00:00 2001 From: Amy Feaver Date: Sat, 30 Sep 2017 18:08:43 +0000 Subject: [PATCH 137/218] fixed 0 to 1 --- src/sage/modules/fg_pid/fgp_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index d3c01d007b1..2164e55ef1f 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1592,7 +1592,7 @@ def annihilator(self): """ if not self.is_finite(): g = 0 - elif self.cardinality()==0: + elif self.cardinality()==1: g=1 else: g = reduce(lcm, self.invariants()) From e58f4cefcb860b93a8a50a644f46c196254709d3 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sat, 30 Sep 2017 21:29:27 +0200 Subject: [PATCH 138/218] Doctest formatting. --- .../free_quadratic_module_symmetric.py | 469 ++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 src/sage/modules/free_quadratic_module_symmetric.py diff --git a/src/sage/modules/free_quadratic_module_symmetric.py b/src/sage/modules/free_quadratic_module_symmetric.py new file mode 100644 index 00000000000..9104132a4ae --- /dev/null +++ b/src/sage/modules/free_quadratic_module_symmetric.py @@ -0,0 +1,469 @@ +#***************************************************************************** +# Copyright (C) 2017 Simon Brandhorst +# +# 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/ +#***************************************************************************** +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule +from sage.matrix.constructor import matrix +from sage.arith.misc import prime_to_m_part,gcd +#from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup_fixed_gens + + +############################################################################### +# +# Constructor functions +# +############################################################################### + +def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): + + """ + Return the integral lattice spanned by basis in the ambient space. + + A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. + Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis + + INPUT: + + - ``ambient`` - a free quadratic module + + - ``basis`` - a list of elements of ambient or a matrix + + - ``inner_product_matrix`` - a symmetric matrix over the rationals + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [0 1] + [1 0] + + We can specify a basis as well + + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + + + """ + if basis==None: + basis = matrix.identity(QQ,inner_product_matrix.ncols()) + if inner_product_matrix!=inner_product_matrix.transpose(): + raise ValueError("Argument inner_product_matrix (= %s) must be symmetric" % inner_product_matrix) + + return(FreeQuadraticModule_symmetric_integral(ambient=FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix),basis=basis,inner_product_matrix=inner_product_matrix,already_echelonized=False)) + + + +############################################################################### +# +# Base class for Lattices +# +############################################################################### + +class FreeQuadraticModule_symmetric(FreeQuadraticModule_submodule_with_basis_pid): + """ + This class represents free quadratic ZZ-modules with a symmetric and non-degenerate inner product. + """ + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): + """ + Create the symmetric quadratic module spanned by basis in the ambient space. + + INPUT: + + - ``ambient`` - a free quadratic module + + - ``basis`` - a list of elements of ambient or a matrix + + - ``inner_product_matrix`` - a symmetric matrix over the base ring + + """ + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) + if self.inner_product_matrix()!=self.inner_product_matrix().transpose(): + raise ValueError("The inner product matrix \n %r \n must be symmetric." %self.inner_product_matrix()) + + def _repr_(self): + """ + The printing representation of self. + + Examples:: + + """ + if self.is_sparse(): + s = "Sparse symmetric free quadratic module of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%r\n" % self.basis_matrix() + \ + "Inner product matrix:\n%r" % self.inner_product_matrix() + else: + s = "Symmetric free quadratic module of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%r\n" % self.basis_matrix() + \ + "Inner product matrix:\n%r" % self.inner_product_matrix() + return s + + def is_integral(self): + """ + Return True if the Gram matrix of self has coefficients over the base ring. + """ + denom = self.gram_matrix().denominator() + denom = self.base_ring()(denom) + return(denom.is_unit()) + + def is_even(self): + """ + Return True if the diagonal entries of the Gram matrix of self are even. + + An element is considered even if it is divisible by 2 over the base ring. + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) + sage: L.is_even() + False + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: L.is_even() + True + """ + if self.is_integral(): + d = gcd(self.gram_matrix().diagonal()) + return(self.base_ring()(2).divides(d)) + else: + return(False) + + def is_primitive(self,M): + """ + Return True if M is a primitive submodule of self + + A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L1 = U.span([vector([1,1])]) + sage: L2 = U.span([vector([1,-1])]) + sage: U.is_primitive(L1) + True + sage: U.is_primitive(L2) + True + sage: U.is_primitive(2*L1) + False + sage: U.is_primitive(L1+L2) + False + + We can also compute the index + sage: (L1+L2).index_in(U) + 2 + + """ + return(0==gcd((self/M).invariants())) + + def signature(self): + """ + Returns the signature of self defined as + + number of positive eigenvalues - number of negative eigenvalues + of the Gram matrix of self. + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: U.signature() + 0 + + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return(QuadraticForm(QQ,self.gram_matrix()).signature()) + + def signature_vector(self): + """ + Returns the triple (p, n, z) of integers where + + * p = number of positive eigenvalues + + * n = number of negative eigenvalues + + * z = number of zero eigenvalues + + for the Gram matrix associated to Q. + + INPUT: + + (none) + + OUTPUT: + + a triple of integers >= 0 + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2.signature_pair() + (2, 0, 0) + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()) + + def span_of_basis(self, basis, check=True, already_echelonized=False): + r""" + Return the symmetric free Quadratic R-module with the given basis, + where R is the base ring of self. Note that this R-module need not + be a submodule of self, nor even of the ambient space. It + must, however, be contained in the ambient vector space, i.e., + the ambient space tensored with the fraction field of R. + + """ + return FreeQuadraticModule_symmetric( + self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), + check=check, already_echelonized=already_echelonized) + +class FreeQuadraticModule_symmetric_integral(FreeQuadraticModule_symmetric): + """ + This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules + """ + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): + """ + Create the integral lattice spanned by basis in the ambient space. + + INPUT: + + - ``ambient`` - a free quadratic module + + - ``basis`` - a list of elements of ambient or a matrix + + - ``inner_product_matrix`` - a symmetric matrix over the rationals + + """ + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) + if self.determinant()==0: + raise ValueError("Lattices must be nondegenerate.") + if self.gram_matrix().base_ring()!=ZZ: + if self.gram_matrix().denominator()!=1: + raise ValueError("Lattices must be integral.") + + def _repr_(self): + """ + The printing representation of self. + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2 + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [ 2 -1] + [-1 2] + """ + if self.is_sparse(): + s = "Sparse lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + else: + s = "Lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + return s + + def dual(self): + """ + Return the dual lattice of self as a FreeQuadraticModule + + Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: Ldual=L.dual() + sage: Ldual + Free module of degree 2 and rank 2 over Integer Ring + Echelon basis matrix: + [1/3 2/3] + [ 0 1] + + Since lattices are integral, they are contained in their dual:: + + sage: Ldual.is_submodule(L) + True + """ + return(self.span_of_basis(self.gram_matrix().inverse()*self.basis_matrix())) + + def discriminant_group(self,s=0): + """ + Return the discriminant group $L^\vee / L$ of self. + + + Input: + s - an integer + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants (2, 10) + sage: L.discriminant_group(2) + Finitely generated module V/W over Integer Ring with invariants (2, 2) + sage: L.discriminant_group(5) + Finitely generated module V/W over Integer Ring with invariants (5) + + Tests:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants () + """ + + D=self.dual_lattice()/self + #This is a workaround + if D.cardinality()==1: + d = 1 + else: + d = D.annihilator().gen() + a = prime_to_m_part(d,s) + Dp_gens = [a*g for g in D.gens()] + return(D.submodule(Dp_gens)) + + def direct_sum(self,M): + """ + Return the direct sum lattice of self with M + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A = IntegralLattice(matrix([1])) + sage: A.direct_sum(A) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [1|0] + [-+-] + [0|1] + """ + + ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) + basis = self.basis_matrix().augment(matrix.zero(self.rank(),M.degree())).stack(matrix.zero(M.rank(),self.degree()).augment(M.basis_matrix())) + return(FreeQuadraticModule_symmetric_integral(ambient=ambient,basis=basis,inner_product_matrix=ambient.inner_product_matrix(),already_echelonized=False)) + + def orthogonal_complement(self,M): + """ + Return the orthogonal complement of M in self. + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) + sage: S = L.span([vector([1,1])]) + sage: L.orthogonal_complement(S) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 3] + Inner product matrix: + [ 2 1] + [ 1 -2] + + """ + K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() + K.base_extend(QQ) + return(self.sublattice(self.intersection(K).basis())) + + def sublattice(self,basis): + """ + Return the sublattice of self spanned by basis + + Input: + gens - a list of elements of self or a rational matrix + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: S = U.sublattice([vector([1,1])]) + sage: S + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + sage: U.sublattice([vector([1,-1])/2]) + Traceback (most recent call last): + ... + ValueError: Lattices must be integral. Use FreeQuadraticModule instead + sage: S.sublattice([vector([1,-1])]) + Traceback (most recent call last): + ... + ValueError: Argument basis (= [(1, -1)]) does not span a submodule of self + """ + M = FreeQuadraticModule_symmetric_integral(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) + if not M.is_submodule(self): + raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) + return(M) + + def overlattice(self,gens): + """ + Return the lattice spanned by self and gens + + Input: + gens - a list of elements of self or a rational matrix + + Examples:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) + sage: M = L.overlattice([vector([1,1])/2]) + sage: M.gram_matrix() + [1 1] + [1 2] + """ + basis = (self+self.span(gens)).basis() + L = FreeQuadraticModule_symmetric_integral(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) + + return(L) + + def genus(self): + """ + Return the genus of self + + Tests: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.genus() + Genus of [0 1] + [1 0] + """ + from sage.quadratic_forms.genera.genus import Genus + return(Genus(self.gram_matrix())) + + def orthogonal_group(): + """ + Return the isometry group of this lattice embedded in the ambient module. + """ + raise NotImplementedError + + From 360ce18f8e3483e4af3fdd40ab33273a820f091b Mon Sep 17 00:00:00 2001 From: Amy Feaver Date: Sat, 30 Sep 2017 19:38:10 +0000 Subject: [PATCH 139/218] added documentation --- src/sage/modules/fg_pid/fgp_module.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 2164e55ef1f..9805af98e08 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1589,11 +1589,17 @@ def annihilator(self): Finitely generated module V/W over Integer Ring with invariants (0, 0) sage: Q.annihilator() Principal ideal (0) of Integer Ring + + We check that :trac:`22720` is resolved:: + + sage: H=AdditiveAbelianGroup([]) + sage: H.annihilator() + Principal ideal (1) of Integer Ring """ if not self.is_finite(): g = 0 - elif self.cardinality()==1: - g=1 + elif self.cardinality() == 1: + g = 1 else: g = reduce(lcm, self.invariants()) return self.base_ring().ideal(g) From 54db16f4ccd91ac819b8a48a12a8b86fc92e082c Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 19:57:28 +0000 Subject: [PATCH 140/218] Remove free_quadratic_module_symmetric.py that was unintentionally added --- .../free_quadratic_module_symmetric.py | 469 ------------------ 1 file changed, 469 deletions(-) delete mode 100644 src/sage/modules/free_quadratic_module_symmetric.py diff --git a/src/sage/modules/free_quadratic_module_symmetric.py b/src/sage/modules/free_quadratic_module_symmetric.py deleted file mode 100644 index 9104132a4ae..00000000000 --- a/src/sage/modules/free_quadratic_module_symmetric.py +++ /dev/null @@ -1,469 +0,0 @@ -#***************************************************************************** -# Copyright (C) 2017 Simon Brandhorst -# -# 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/ -#***************************************************************************** -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule -from sage.matrix.constructor import matrix -from sage.arith.misc import prime_to_m_part,gcd -#from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup_fixed_gens - - -############################################################################### -# -# Constructor functions -# -############################################################################### - -def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): - - """ - Return the integral lattice spanned by basis in the ambient space. - - A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. - Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis - - INPUT: - - - ``ambient`` - a free quadratic module - - - ``basis`` - a list of elements of ambient or a matrix - - - ``inner_product_matrix`` - a symmetric matrix over the rationals - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - Lattice of degree 2 and rank 2 over Integer Ring - Basis matrix: - [1 0] - [0 1] - Inner product matrix: - [0 1] - [1 0] - - We can specify a basis as well - - sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) - Lattice of degree 2 and rank 1 over Integer Ring - Basis matrix: - [1 1] - Inner product matrix: - [0 1] - [1 0] - - - """ - if basis==None: - basis = matrix.identity(QQ,inner_product_matrix.ncols()) - if inner_product_matrix!=inner_product_matrix.transpose(): - raise ValueError("Argument inner_product_matrix (= %s) must be symmetric" % inner_product_matrix) - - return(FreeQuadraticModule_symmetric_integral(ambient=FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix),basis=basis,inner_product_matrix=inner_product_matrix,already_echelonized=False)) - - - -############################################################################### -# -# Base class for Lattices -# -############################################################################### - -class FreeQuadraticModule_symmetric(FreeQuadraticModule_submodule_with_basis_pid): - """ - This class represents free quadratic ZZ-modules with a symmetric and non-degenerate inner product. - """ - def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): - """ - Create the symmetric quadratic module spanned by basis in the ambient space. - - INPUT: - - - ``ambient`` - a free quadratic module - - - ``basis`` - a list of elements of ambient or a matrix - - - ``inner_product_matrix`` - a symmetric matrix over the base ring - - """ - FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) - if self.inner_product_matrix()!=self.inner_product_matrix().transpose(): - raise ValueError("The inner product matrix \n %r \n must be symmetric." %self.inner_product_matrix()) - - def _repr_(self): - """ - The printing representation of self. - - Examples:: - - """ - if self.is_sparse(): - s = "Sparse symmetric free quadratic module of degree %s and rank %s over %s\n"%( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - else: - s = "Symmetric free quadratic module of degree %s and rank %s over %s\n"%( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - return s - - def is_integral(self): - """ - Return True if the Gram matrix of self has coefficients over the base ring. - """ - denom = self.gram_matrix().denominator() - denom = self.base_ring()(denom) - return(denom.is_unit()) - - def is_even(self): - """ - Return True if the diagonal entries of the Gram matrix of self are even. - - An element is considered even if it is divisible by 2 over the base ring. - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) - sage: L.is_even() - False - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) - sage: L.is_even() - True - """ - if self.is_integral(): - d = gcd(self.gram_matrix().diagonal()) - return(self.base_ring()(2).divides(d)) - else: - return(False) - - def is_primitive(self,M): - """ - Return True if M is a primitive submodule of self - - A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - sage: L1 = U.span([vector([1,1])]) - sage: L2 = U.span([vector([1,-1])]) - sage: U.is_primitive(L1) - True - sage: U.is_primitive(L2) - True - sage: U.is_primitive(2*L1) - False - sage: U.is_primitive(L1+L2) - False - - We can also compute the index - sage: (L1+L2).index_in(U) - 2 - - """ - return(0==gcd((self/M).invariants())) - - def signature(self): - """ - Returns the signature of self defined as - - number of positive eigenvalues - number of negative eigenvalues - of the Gram matrix of self. - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - sage: U.signature() - 0 - - """ - from sage.quadratic_forms.quadratic_form import QuadraticForm - return(QuadraticForm(QQ,self.gram_matrix()).signature()) - - def signature_vector(self): - """ - Returns the triple (p, n, z) of integers where - - * p = number of positive eigenvalues - - * n = number of negative eigenvalues - - * z = number of zero eigenvalues - - for the Gram matrix associated to Q. - - INPUT: - - (none) - - OUTPUT: - - a triple of integers >= 0 - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) - sage: A2.signature_pair() - (2, 0, 0) - """ - from sage.quadratic_forms.quadratic_form import QuadraticForm - return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()) - - def span_of_basis(self, basis, check=True, already_echelonized=False): - r""" - Return the symmetric free Quadratic R-module with the given basis, - where R is the base ring of self. Note that this R-module need not - be a submodule of self, nor even of the ambient space. It - must, however, be contained in the ambient vector space, i.e., - the ambient space tensored with the fraction field of R. - - """ - return FreeQuadraticModule_symmetric( - self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), - check=check, already_echelonized=already_echelonized) - -class FreeQuadraticModule_symmetric_integral(FreeQuadraticModule_symmetric): - """ - This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules - """ - def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): - """ - Create the integral lattice spanned by basis in the ambient space. - - INPUT: - - - ``ambient`` - a free quadratic module - - - ``basis`` - a list of elements of ambient or a matrix - - - ``inner_product_matrix`` - a symmetric matrix over the rationals - - """ - FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) - if self.determinant()==0: - raise ValueError("Lattices must be nondegenerate.") - if self.gram_matrix().base_ring()!=ZZ: - if self.gram_matrix().denominator()!=1: - raise ValueError("Lattices must be integral.") - - def _repr_(self): - """ - The printing representation of self. - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) - sage: A2 - Lattice of degree 2 and rank 2 over Integer Ring - Basis matrix: - [1 0] - [0 1] - Inner product matrix: - [ 2 -1] - [-1 2] - """ - if self.is_sparse(): - s = "Sparse lattice of degree %s and rank %s over %s\n"%( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%s\n" % self.basis_matrix() + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - else: - s = "Lattice of degree %s and rank %s over %s\n"%( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%s\n" % self.basis_matrix() + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - return s - - def dual(self): - """ - Return the dual lattice of self as a FreeQuadraticModule - - Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) - sage: Ldual=L.dual() - sage: Ldual - Free module of degree 2 and rank 2 over Integer Ring - Echelon basis matrix: - [1/3 2/3] - [ 0 1] - - Since lattices are integral, they are contained in their dual:: - - sage: Ldual.is_submodule(L) - True - """ - return(self.span_of_basis(self.gram_matrix().inverse()*self.basis_matrix())) - - def discriminant_group(self,s=0): - """ - Return the discriminant group $L^\vee / L$ of self. - - - Input: - s - an integer - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) - sage: L.discriminant_group() - Finitely generated module V/W over Integer Ring with invariants (2, 10) - sage: L.discriminant_group(2) - Finitely generated module V/W over Integer Ring with invariants (2, 2) - sage: L.discriminant_group(5) - Finitely generated module V/W over Integer Ring with invariants (5) - - Tests:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - sage: L.discriminant_group() - Finitely generated module V/W over Integer Ring with invariants () - """ - - D=self.dual_lattice()/self - #This is a workaround - if D.cardinality()==1: - d = 1 - else: - d = D.annihilator().gen() - a = prime_to_m_part(d,s) - Dp_gens = [a*g for g in D.gens()] - return(D.submodule(Dp_gens)) - - def direct_sum(self,M): - """ - Return the direct sum lattice of self with M - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: A = IntegralLattice(matrix([1])) - sage: A.direct_sum(A) - Lattice of degree 2 and rank 2 over Integer Ring - Basis matrix: - [1 0] - [0 1] - Inner product matrix: - [1|0] - [-+-] - [0|1] - """ - - ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) - basis = self.basis_matrix().augment(matrix.zero(self.rank(),M.degree())).stack(matrix.zero(M.rank(),self.degree()).augment(M.basis_matrix())) - return(FreeQuadraticModule_symmetric_integral(ambient=ambient,basis=basis,inner_product_matrix=ambient.inner_product_matrix(),already_echelonized=False)) - - def orthogonal_complement(self,M): - """ - Return the orthogonal complement of M in self. - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) - sage: S = L.span([vector([1,1])]) - sage: L.orthogonal_complement(S) - Lattice of degree 2 and rank 1 over Integer Ring - Basis matrix: - [1 3] - Inner product matrix: - [ 2 1] - [ 1 -2] - - """ - K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() - K.base_extend(QQ) - return(self.sublattice(self.intersection(K).basis())) - - def sublattice(self,basis): - """ - Return the sublattice of self spanned by basis - - Input: - gens - a list of elements of self or a rational matrix - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - sage: S = U.sublattice([vector([1,1])]) - sage: S - Lattice of degree 2 and rank 1 over Integer Ring - Basis matrix: - [1 1] - Inner product matrix: - [0 1] - [1 0] - sage: U.sublattice([vector([1,-1])/2]) - Traceback (most recent call last): - ... - ValueError: Lattices must be integral. Use FreeQuadraticModule instead - sage: S.sublattice([vector([1,-1])]) - Traceback (most recent call last): - ... - ValueError: Argument basis (= [(1, -1)]) does not span a submodule of self - """ - M = FreeQuadraticModule_symmetric_integral(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) - if not M.is_submodule(self): - raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) - return(M) - - def overlattice(self,gens): - """ - Return the lattice spanned by self and gens - - Input: - gens - a list of elements of self or a rational matrix - - Examples:: - - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) - sage: M = L.overlattice([vector([1,1])/2]) - sage: M.gram_matrix() - [1 1] - [1 2] - """ - basis = (self+self.span(gens)).basis() - L = FreeQuadraticModule_symmetric_integral(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) - - return(L) - - def genus(self): - """ - Return the genus of self - - Tests: - sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice - sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) - sage: L.genus() - Genus of [0 1] - [1 0] - """ - from sage.quadratic_forms.genera.genus import Genus - return(Genus(self.gram_matrix())) - - def orthogonal_group(): - """ - Return the isometry group of this lattice embedded in the ambient module. - """ - raise NotImplementedError - - From 44f8d4738d0a14273c87a0b8f82d9904d7860968 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 20:16:17 +0000 Subject: [PATCH 141/218] Remove trailing whitespace --- ...free_quadratic_module_integer_symmetric.py | 119 ++++++++---------- 1 file changed, 54 insertions(+), 65 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index d7967a6c407..7dea977a57a 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -22,21 +22,20 @@ ############################################################################### def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): - """ Return the integral lattice spanned by basis in the ambient space. - - A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. - Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis + + A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. + Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis INPUT: - ``ambient`` - a free quadratic module - ``basis`` - a list of elements of ambient or a matrix - + - ``inner_product_matrix`` - a symmetric matrix over the rationals - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) @@ -47,9 +46,9 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch Inner product matrix: [0 1] [1 0] - + We can specify a basis as well - + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: @@ -57,14 +56,12 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch Inner product matrix: [0 1] [1 0] - - - """ + """ if basis==None: basis = matrix.identity(QQ,inner_product_matrix.ncols()) if inner_product_matrix!=inner_product_matrix.transpose(): raise ValueError("Argument inner_product_matrix (= %s) must be symmetric" % inner_product_matrix) - + return(FreeQuadraticModule_integer_symmetric(ambient=FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix),basis=basis,inner_product_matrix=inner_product_matrix,already_echelonized=False)) @@ -77,7 +74,7 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): """ - This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules + This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules """ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): """ @@ -88,21 +85,21 @@ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_ech - ``ambient`` - a free quadratic module - ``basis`` - a list of elements of ambient or a matrix - + - ``inner_product_matrix`` - a symmetric matrix over the rationals - """ + """ FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) if self.determinant()==0: raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") if self.gram_matrix().base_ring()!=ZZ: if self.gram_matrix().denominator()!=1: - raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") - + raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") + def _repr_(self): """ The printing representation of self. - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) @@ -126,13 +123,11 @@ def _repr_(self): "Basis matrix:\n%s\n" % self.basis_matrix() + \ "Inner product matrix:\n%s" % self.inner_product_matrix() return s - - + def is_even(self): """ Return True if the diagonal entries of the Gram matrix of self are even. - - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) @@ -140,19 +135,19 @@ def is_even(self): False sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) sage: L.is_even() - True + True """ for d in self.gram_matrix().diagonal(): if d % 2 !=0: return(False) return(True) - + def dual_lattice(self): """ Return the dual lattice of self as a FreeQuadraticModule - + Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) @@ -162,22 +157,21 @@ def dual_lattice(self): Echelon basis matrix: [1/3 2/3] [ 0 1] - + Since our lattices are always integral, a lattice is contained in its dual - + sage: Ldual.is_submodule(L) - True + True """ return(self.span(self.gram_matrix().inverse()*self.basis_matrix())) - + def discriminant_group(self,s=0): """ Return the discriminant group $L^\vee / L$ of self. - - + Input: s - an integer - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) @@ -196,7 +190,7 @@ def discriminant_group(self,s=0): """ D=self.dual_lattice()/self - #This is a workaround + #This is a workaround if D.cardinality()==1: d = 1 else: @@ -204,14 +198,14 @@ def discriminant_group(self,s=0): a = prime_to_m_part(d,s) Dp_gens = [a*g for g in D.gens()] return(D.submodule(Dp_gens)) - + def signature(self): """ Returns the signature of self defined as number of positive eigenvalues - number of negative eigenvalues of the Gram matrix of self. - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) @@ -221,13 +215,13 @@ def signature(self): """ from sage.quadratic_forms.quadratic_form import QuadraticForm return(QuadraticForm(QQ,self.gram_matrix()).signature()) - + def signature_pair(self): """ Returns the signature tuple $(n_+,n_-)$ of self. - Here $n_+$ (resp. $n_-$) is the number of positive (resp. negative) eigenvalues of the gram_matrix of self - + Here $n_+$ (resp. $n_-$) is the number of positive (resp. negative) eigenvalues of the gram_matrix of self + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) @@ -236,12 +230,11 @@ def signature_pair(self): """ from sage.quadratic_forms.quadratic_form import QuadraticForm return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()[:2]) - def direct_sum(self,M): """ Return the direct sum lattice of self with M - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A = IntegralLattice(matrix([1])) @@ -255,7 +248,6 @@ def direct_sum(self,M): [-+-] [0|1] """ - ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) basis = self.basis_matrix().augment(matrix.zero(self.rank(),M.degree())).stack(matrix.zero(M.rank(),self.degree()).augment(M.basis_matrix())) return(FreeQuadraticModule_integer_symmetric(ambient=ambient,basis=basis,inner_product_matrix=ambient.inner_product_matrix(),already_echelonized=False)) @@ -263,9 +255,9 @@ def direct_sum(self,M): def is_primitive(self,M): """ Return True if M is a primitive submodule of self - - A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. - + + A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) @@ -277,22 +269,21 @@ def is_primitive(self,M): True sage: U.is_primitive(L1+L2) False - - We can also compute the index + + We can also compute the index sage: (L1+L2).index_in(U) 2 - """ return(0==gcd((self/M).invariants())) - + def orthogonal_complement(self,M): """ Return the orthogonal complement of M in self. - + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) sage: S = L.span([vector([1,1])]) - sage: L.orthogonal_complement(S) + sage: L.orthogonal_complement(S) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 3] @@ -304,14 +295,14 @@ def orthogonal_complement(self,M): K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() K.base_extend(QQ) return(self.sublattice(self.intersection(K).basis())) - + def sublattice(self,basis): """ Return the sublattice of self spanned by basis - + Input: gens - a list of elements of self or a rational matrix - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) @@ -336,31 +327,31 @@ def sublattice(self,basis): if not M.is_submodule(self): raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) return(M) - + def overlattice(self,gens): """ Return the lattice spanned by self and gens - + Input: gens - a list of elements of self or a rational matrix - + Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) sage: M = L.overlattice([vector([1,1])/2]) - sage: M.gram_matrix() + sage: M.gram_matrix() [1 1] [1 2] """ basis = (self+self.span(gens)).basis() L = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) - + return(L) - + def genus(self): """ Return the genus of self - + Tests: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) @@ -370,11 +361,9 @@ def genus(self): """ from sage.quadratic_forms.genera.genus import Genus return(Genus(self.gram_matrix())) - + def orthogonal_group(): """ - Return the isometry group of this lattice embedded in the ambient module. + Return the isometry group of this lattice embedded in the ambient module. """ raise NotImplementedError - - From ef07c252697b5abc769bfa888dd22c39ae1add09 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 20:56:20 +0000 Subject: [PATCH 142/218] Style changes to docstrings and spacing changes to code --- ...free_quadratic_module_integer_symmetric.py | 258 ++++++++++-------- 1 file changed, 147 insertions(+), 111 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 7dea977a57a..2276e0fc584 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -7,13 +7,12 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** + from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule from sage.matrix.constructor import matrix from sage.arith.misc import prime_to_m_part,gcd -#from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup_fixed_gens - ############################################################################### # @@ -21,22 +20,24 @@ # ############################################################################### -def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,check=True): - """ - Return the integral lattice spanned by basis in the ambient space. +def IntegralLattice(inner_product_matrix, basis=None, already_echelonized=False, check=True): + r""" + Return the integral lattice spanned by ``basis`` in the ambient space. - A lattice is a finitely generated free abelian group $L \cong \ZZ^r$ equipped with a non-degenerate, symmetric bilinear form $L \times L \colon \rightarrow \ZZ$. - Here lattices have an ambient quadratic space $\QQ^n$ and a distinguished basis + A lattice is a finitely generated free abelian group `L \cong \Z^r` equipped + with a non-degenerate, symmetric bilinear form `L \times L \colon \rightarrow \Z`. + Here, lattices have an ambient quadratic space `\Q^n` and a distinguished basis. INPUT: - - ``ambient`` - a free quadratic module + - ``ambient`` -- a free quadratic module + + - ``basis`` -- a list of elements of ambient or a matrix - - ``basis`` - a list of elements of ambient or a matrix + - ``inner_product_matrix`` -- a symmetric matrix over the rationals - - ``inner_product_matrix`` - a symmetric matrix over the rationals + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) Lattice of degree 2 and rank 2 over Integer Ring @@ -47,7 +48,7 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch [0 1] [1 0] - We can specify a basis as well + We can specify a basis as well:: sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) Lattice of degree 2 and rank 1 over Integer Ring @@ -57,14 +58,16 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch [0 1] [1 0] """ - if basis==None: - basis = matrix.identity(QQ,inner_product_matrix.ncols()) - if inner_product_matrix!=inner_product_matrix.transpose(): - raise ValueError("Argument inner_product_matrix (= %s) must be symmetric" % inner_product_matrix) - - return(FreeQuadraticModule_integer_symmetric(ambient=FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix),basis=basis,inner_product_matrix=inner_product_matrix,already_echelonized=False)) - + if basis is None: + basis = matrix.identity(QQ, inner_product_matrix.ncols()) + if inner_product_matrix != inner_product_matrix.transpose(): + raise ValueError("Argument inner_product_matrix must be symmetric\n%s" % inner_product_matrix) + A = FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), + inner_product_matrix=inner_product_matrix) + return FreeQuadraticModule_integer_symmetric(ambient=A, basis=basis, + inner_product_matrix=inner_product_matrix, + already_echelonized=False) ############################################################################### # @@ -73,34 +76,44 @@ def IntegralLattice(inner_product_matrix,basis=None,already_echelonized=False,ch ############################################################################### class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): - """ - This class represents non-degenerate, integral, symmetric free quadratic ZZ-modules - """ - def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): - """ - Create the integral lattice spanned by basis in the ambient space. + r""" + This class represents non-degenerate, integral, symmetric free quadratic `\Z`-modules. - INPUT: + INPUT: - - ``ambient`` - a free quadratic module + - ``ambient`` -- a free quadratic module - - ``basis`` - a list of elements of ambient or a matrix + - ``basis`` -- a list of elements of ``ambient``, or a matrix - - ``inner_product_matrix`` - a symmetric matrix over the rationals + - ``inner_product_matrix`` -- a symmetric matrix over the rationals + EXAMPLES:: + + sage: + """ + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): + r""" + Create the integral lattice spanned by ``basis`` in the ambient space. + + TESTS:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: TestSuite(L).run() """ FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) - if self.determinant()==0: + if self.determinant() == 0: raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") - if self.gram_matrix().base_ring()!=ZZ: - if self.gram_matrix().denominator()!=1: + if self.gram_matrix().base_ring() != ZZ: + if self.gram_matrix().denominator() != 1: raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") def _repr_(self): - """ - The printing representation of self. + r""" + The print representation of this lattice. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) sage: A2 @@ -125,10 +138,11 @@ def _repr_(self): return s def is_even(self): - """ - Return True if the diagonal entries of the Gram matrix of self are even. + r""" + Return whether the diagonal entries of the Gram matrix are even. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) sage: L.is_even() @@ -139,16 +153,21 @@ def is_even(self): """ for d in self.gram_matrix().diagonal(): if d % 2 !=0: - return(False) - return(True) + return False + return True def dual_lattice(self): - """ - Return the dual lattice of self as a FreeQuadraticModule + r""" + Return the dual lattice as a :class:`FreeQuadraticModule` + + Let `L` be a lattice. Its dual lattice is + + .. math:: - Let $L$ be a lattice. Its dual lattice is $L^\vee=\{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}$. + L^\vee = \{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) sage: Ldual=L.dual_lattice() @@ -158,21 +177,23 @@ def dual_lattice(self): [1/3 2/3] [ 0 1] - Since our lattices are always integral, a lattice is contained in its dual + Since our lattices are always integral, a lattice is contained in its dual:: sage: Ldual.is_submodule(L) True """ - return(self.span(self.gram_matrix().inverse()*self.basis_matrix())) + return self.span(self.gram_matrix().inverse()*self.basis_matrix()) def discriminant_group(self,s=0): - """ - Return the discriminant group $L^\vee / L$ of self. + r""" + Return the discriminant group `L^\vee / L` of this lattice. + + INPUT: + + - ``s`` -- an integer - Input: - s - an integer + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) sage: L.discriminant_group() @@ -182,60 +203,63 @@ def discriminant_group(self,s=0): sage: L.discriminant_group(5) Finitely generated module V/W over Integer Ring with invariants (5) - Tests:: + TESTS:: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: L.discriminant_group() Finitely generated module V/W over Integer Ring with invariants () """ - D=self.dual_lattice()/self + D = self.dual_lattice() / self #This is a workaround - if D.cardinality()==1: + if D.cardinality() == 1: d = 1 else: d = D.annihilator().gen() - a = prime_to_m_part(d,s) + a = prime_to_m_part(d, s) Dp_gens = [a*g for g in D.gens()] - return(D.submodule(Dp_gens)) + return D.submodule(Dp_gens) def signature(self): - """ - Returns the signature of self defined as + r""" + Return the signature of this lattice, which is defined as + the difference between the number of positive eigenvalues and + the number of negative eigenvalues in the Gram matrix. - number of positive eigenvalues - number of negative eigenvalues - of the Gram matrix of self. + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: U.signature() 0 - """ from sage.quadratic_forms.quadratic_form import QuadraticForm - return(QuadraticForm(QQ,self.gram_matrix()).signature()) + return QuadraticForm(QQ, self.gram_matrix()).signature() def signature_pair(self): - """ - Returns the signature tuple $(n_+,n_-)$ of self. + r""" + Returns the signature tuple `(n_+,n_-)` of this lattice. - Here $n_+$ (resp. $n_-$) is the number of positive (resp. negative) eigenvalues of the gram_matrix of self + Here `n_+` (resp. `n_-`) is the number of positive (resp. negative) + eigenvalues of the Gram matrix. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) sage: A2.signature_pair() (2, 0) """ from sage.quadratic_forms.quadratic_form import QuadraticForm - return(QuadraticForm(QQ,self.gram_matrix()).signature_vector()[:2]) + return QuadraticForm(QQ, self.gram_matrix()).signature_vector()[:2] - def direct_sum(self,M): - """ - Return the direct sum lattice of self with M + def direct_sum(self, M): + r""" + Return the direct sum of this lattice with ``M``. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: A = IntegralLattice(matrix([1])) sage: A.direct_sum(A) @@ -248,17 +272,24 @@ def direct_sum(self,M): [-+-] [0|1] """ - ambient = FreeQuadraticModule(ZZ, self.degree()+M.degree(),inner_product_matrix=matrix.block_diagonal([self.inner_product_matrix(),M.inner_product_matrix()])) - basis = self.basis_matrix().augment(matrix.zero(self.rank(),M.degree())).stack(matrix.zero(M.rank(),self.degree()).augment(M.basis_matrix())) - return(FreeQuadraticModule_integer_symmetric(ambient=ambient,basis=basis,inner_product_matrix=ambient.inner_product_matrix(),already_echelonized=False)) + IM = matrix.block_diagonal([self.inner_product_matrix(), M.inner_product_matrix()]) + ambient = FreeQuadraticModule(ZZ, self.degree() + M.degree(), inner_product_matrix=IM) + smzero = matrix.zero(self.rank(), M.degree()) + mszero = matrix.zero(M.rank(), self.degree()) + basis = self.basis_matrix().augment(smzero).stack(mszero.augment(M.basis_matrix())) + ipm = ambient.inner_product_matrix() + return FreeQuadraticModule_integer_symmetric( + ambient=ambient, basis=basis, inner_product_matrix=ipm, already_echelonized=False) def is_primitive(self,M): - """ - Return True if M is a primitive submodule of self + r""" + Return whether ``M`` is a primitive submodule of this lattice. - A ZZ-submodule M of a ZZ-module L is called primitive if the quotient L/M is torsion free. + A `\Z`-submodule ``M`` of a `\Z`-module `L` is called primitive if + the quotient ``L/M`` is torsion free. + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: L1 = U.span([vector([1,1])]) @@ -270,15 +301,18 @@ def is_primitive(self,M): sage: U.is_primitive(L1+L2) False - We can also compute the index + We can also compute the index:: + sage: (L1+L2).index_in(U) 2 """ return(0==gcd((self/M).invariants())) def orthogonal_complement(self,M): - """ - Return the orthogonal complement of M in self. + r""" + Return the orthogonal complement of ``M`` in this lattice. + + EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) @@ -290,20 +324,21 @@ def orthogonal_complement(self,M): Inner product matrix: [ 2 1] [ 1 -2] - """ K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() K.base_extend(QQ) return(self.sublattice(self.intersection(K).basis())) def sublattice(self,basis): - """ - Return the sublattice of self spanned by basis + r""" + Return the sublattice spanned by ``basis``. + + INPUT: + + - ``gens`` -- a list of elements of this lattice, or a rational matrix. - Input: - gens - a list of elements of self or a rational matrix + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: S = U.sublattice([vector([1,1])]) @@ -323,19 +358,24 @@ def sublattice(self,basis): ... ValueError: Argument basis (= [(1, -1)]) does not span a submodule of self """ - M = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) + M = FreeQuadraticModule_integer_symmetric( + ambient=self.ambient_module(), basis=basis, + inner_product_matrix=self.inner_product_matrix(), + already_echelonized=False) if not M.is_submodule(self): - raise ValueError("Argument basis (= %s) does not span a submodule of self" % basis) - return(M) + raise ValueError("Argument basis (= %s) does not span a submodule of this lattice" % basis) + return M - def overlattice(self,gens): - """ - Return the lattice spanned by self and gens + def overlattice(self, gens): + r""" + Return the lattice spanned by this lattice and ``gens`` + + INPUT: - Input: - gens - a list of elements of self or a rational matrix + - ``gens`` -- a list of elements of this lattice, or a rational matrix + + EXAMPLES:: - Examples:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) sage: M = L.overlattice([vector([1,1])/2]) @@ -343,16 +383,18 @@ def overlattice(self,gens): [1 1] [1 2] """ - basis = (self+self.span(gens)).basis() - L = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(),basis=basis,inner_product_matrix=self.inner_product_matrix(),already_echelonized=False) - - return(L) + basis = (self + self.span(gens)).basis() + return FreeQuadraticModule_integer_symmetric( + ambient=self.ambient_module(), basis=basis, + inner_product_matrix=self.inner_product_matrix(), + already_echelonized=False) def genus(self): - """ - Return the genus of self + r""" + Return the genus of this lattice. + + EXAMPLES:: - Tests: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: L.genus() @@ -360,10 +402,4 @@ def genus(self): [1 0] """ from sage.quadratic_forms.genera.genus import Genus - return(Genus(self.gram_matrix())) - - def orthogonal_group(): - """ - Return the isometry group of this lattice embedded in the ambient module. - """ - raise NotImplementedError + return Genus(self.gram_matrix()) From add19cac2ce6a5f8e2cff177b9269c040a250a46 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 22:08:38 +0000 Subject: [PATCH 143/218] A few more small changes --- ...free_quadratic_module_integer_symmetric.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 2276e0fc584..92edaa53476 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -89,7 +89,14 @@ class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_b EXAMPLES:: - sage: + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] """ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): r""" @@ -210,14 +217,9 @@ def discriminant_group(self,s=0): sage: L.discriminant_group() Finitely generated module V/W over Integer Ring with invariants () """ - D = self.dual_lattice() / self - #This is a workaround - if D.cardinality() == 1: - d = 1 - else: - d = D.annihilator().gen() - a = prime_to_m_part(d, s) + d = D.annihilator().gen() + a = d.prime_to_m_part(s) Dp_gens = [a*g for g in D.gens()] return D.submodule(Dp_gens) @@ -281,7 +283,7 @@ def direct_sum(self, M): return FreeQuadraticModule_integer_symmetric( ambient=ambient, basis=basis, inner_product_matrix=ipm, already_echelonized=False) - def is_primitive(self,M): + def is_primitive(self, M): r""" Return whether ``M`` is a primitive submodule of this lattice. @@ -306,7 +308,7 @@ def is_primitive(self,M): sage: (L1+L2).index_in(U) 2 """ - return(0==gcd((self/M).invariants())) + return (gcd((self/M).invariants()) == 0) def orthogonal_complement(self,M): r""" @@ -327,7 +329,7 @@ def orthogonal_complement(self,M): """ K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() K.base_extend(QQ) - return(self.sublattice(self.intersection(K).basis())) + return self.sublattice(self.intersection(K).basis()) def sublattice(self,basis): r""" @@ -368,7 +370,7 @@ def sublattice(self,basis): def overlattice(self, gens): r""" - Return the lattice spanned by this lattice and ``gens`` + Return the lattice spanned by this lattice and ``gens``. INPUT: From 57800c7f0a03da284d7f6a0b74348170169ebcfa Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 00:21:34 +0200 Subject: [PATCH 144/218] Included the inner_product_matrix for comparison --- src/sage/modules/free_module.py | 10 +++++++++- src/sage/modules/free_quadratic_module.py | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 05bb3729b37..7c74b3c61cc 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -4408,7 +4408,15 @@ def __richcmp__(self, other, op): lx = self.base_ring() rx = other.base_ring() if lx == rx: - return rich_to_bool(op, 0) + #We do not want to create an inner product matrix in memory if + #self and other use the dot product + if self._inner_product_is_dot_product()==True and other._inner_product_is_dot_product()==True: + return rich_to_bool(op, 0) + else: + #this only affects free_quadratic_modules + lx = self.inner_product_matrix() + rx = other.inner_product_matrix() + return richcmp_not_equal(lx,rx,op) try: if self.base_ring().is_subring(other.base_ring()): return rich_to_bool(op, -1) diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index bbf31f7db31..074547747f2 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -803,6 +803,15 @@ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): sage: FreeModule(ZZ, 4) Ambient free module of rank 4 over the principal ideal domain Integer Ring + + TESTS:: + + We test that :trac:`23915` is fixed:: + + sage: M1 = FreeQuadraticModule(ZZ,1,matrix.identity(1)) + sage: M2 = FreeQuadraticModule(ZZ,1,matrix.identity(1)*2) + sage: M1 == M2 + False """ free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix From b3fa0517a59c360a990a8f6c66d415b882760c92 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 00:26:54 +0200 Subject: [PATCH 145/218] Moved doctest --- src/sage/modules/free_quadratic_module.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index 074547747f2..6f5aa673b1e 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -284,11 +284,18 @@ class FreeQuadraticModule_generic(free_module.FreeModule_generic): sage: Q3 < V False - Beware: currently, the inner_product_matrix is not part of the comparison:: + The inner_product_matrix is part of the comparison:: sage: Q3zero = FreeQuadraticModule(QQ,3,matrix.zero(3)) sage: Q3zero == Q3 - True + False + + We test that :trac:`23915` is fixed:: + + sage: M1 = FreeQuadraticModule(ZZ,1,matrix.identity(1)) + sage: M2 = FreeQuadraticModule(ZZ,1,matrix.identity(1)*2) + sage: M1 == M2 + False """ def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False): """ @@ -804,14 +811,6 @@ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): sage: FreeModule(ZZ, 4) Ambient free module of rank 4 over the principal ideal domain Integer Ring - TESTS:: - - We test that :trac:`23915` is fixed:: - - sage: M1 = FreeQuadraticModule(ZZ,1,matrix.identity(1)) - sage: M2 = FreeQuadraticModule(ZZ,1,matrix.identity(1)*2) - sage: M1 == M2 - False """ free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix From 09a7e7debacf409eb618a1fa8f7e5b0142901edf Mon Sep 17 00:00:00 2001 From: David Roe Date: Sat, 30 Sep 2017 22:44:32 +0000 Subject: [PATCH 146/218] Remove prime_to_m_part import --- src/sage/modules/free_quadratic_module_integer_symmetric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 92edaa53476..10ffda0c17d 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -12,7 +12,7 @@ from sage.rings.rational_field import QQ from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule from sage.matrix.constructor import matrix -from sage.arith.misc import prime_to_m_part,gcd +from sage.arith.misc import gcd ############################################################################### # From b59dffe8539db248ce71c730184ef8c5f43d1544 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Sat, 30 Sep 2017 22:57:43 +0000 Subject: [PATCH 147/218] Implement reciprocal transform, inverse reciprocal transform --- .../rings/polynomial/polynomial_element.pyx | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2772e87114a..86aecd511d5 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7845,6 +7845,96 @@ cdef class Polynomial(CommutativeAlgebraElement): """ return self.all_roots_in_interval() + def reciprocal_transform(self, R=1, q=1): + r""" + Transform a general polynomial into a self-reciprocal polynomial. + + The input `Q` and output `P` satisfy the relation + `P(x) = Q(x + q/x) x^{\deg(Q)} R(x)`. + + In this relation, `Q` has all roots in the real interval + `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the + circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + + INPUT: + - ``R`` -- polynomial + - ``q`` -- scalar (default: `1`) + + EXAMPLES:: + + sage: pol. = PolynomialRing(Rationals()) + sage: u = x^2+x-1 + sage: u.reciprocal_transform() + x^4 + x^3 + x^2 + x + 1 + sage: u.reciprocal_transform(R=x-1) + x^5 - 1 + sage: u.reciprocal_transform(q=3) + x^4 + x^3 + 5*x^2 + 3*x + 9 + + .. SEEALSO:: + + :meth:`inverse_reciprocal_transform` + """ + S = self.parent() + x = S.gen() + return S(x**(self.degree()) * self(x + q/x)) * R + + def inverse_reciprocal_transform(self): + r""" + Undo the reciprocal transform. + + The input `P` and output `Q` satisfy the relation + `P(x) = Q(x + q/x) x^{\deg(Q)} R(x)`. + + In this relation, `Q` has all roots in the real interval + `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the + circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + + OUTPUT: + - ``Q`` -- polynomial + - ``R`` -- polynomial + - ``q`` -- nonzero scalar + + EXAMPLES:: + + sage: pol. = PolynomialRing(Rationals()) + sage: u = x^5 - 1; u.inverse_reciprocal_transform() + (x^2 + x - 1, x - 1, 1) + sage: u = x^4 + x^3 + 5*x^2 + 3*x + 9 + sage: u.inverse_reciprocal_transform() + (x^2 + x - 1, 1, 3) + + .. SEEALSO:: + + :meth:`reciprocal_transform` + """ + S = self.parent() + x = S.gen() + if self[0] == 0: + raise ValueError, "Polynomial not self-reciprocal" + d = self.degree() + sg = (self[0]/self[d]).sign() + q = abs(self[0]/self[d])**(2/d) + if not q in S.base_ring(): + raise ValueError, "Polynomial not self-reciprocal" + for i in range(d+1): + if self[d-i] != sg*self[i]/q**(d/2-i): + raise ValueError, "Polynomial not self-reciprocal" + cofactor = S(1) + Q = self + if sg == -1: + cofactor *= x-q + Q //= x-q + if Q.degree() %2 == 1: + cofactor *= x+q + Q //= x+q + coeffs = [] + m = Q.degree() // 2 + for i in reversed(range(m+1)): + coeffs.insert(0, Q.leading_coefficient()) + Q = (Q % (x**2 + q)**i) // x + return S(coeffs), cofactor, q + def variable_name(self): """ Return name of variable used in this polynomial as a string. From 69955c7fa3c2d348b87cd7f0c803a45d453a8312 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 02:43:56 +0000 Subject: [PATCH 148/218] Fix case for math directive --- src/sage/modules/free_quadratic_module_integer_symmetric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 10ffda0c17d..fefa21f922f 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -169,7 +169,7 @@ def dual_lattice(self): Let `L` be a lattice. Its dual lattice is - .. math:: + .. MATH:: L^\vee = \{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}. From abef20e14cbf24e882704d84dcc950439301544a Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 07:00:02 +0200 Subject: [PATCH 149/218] Doctests. --- src/sage/modules/free_quadratic_module_integer_symmetric.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index fefa21f922f..49315a66fb6 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -186,7 +186,7 @@ def dual_lattice(self): Since our lattices are always integral, a lattice is contained in its dual:: - sage: Ldual.is_submodule(L) + sage: L.is_submodule(Ldual) True """ return self.span(self.gram_matrix().inverse()*self.basis_matrix()) @@ -355,10 +355,12 @@ def sublattice(self,basis): Traceback (most recent call last): ... ValueError: Lattices must be integral. Use FreeQuadraticModule instead + sage: S.sublattice([vector([1,-1])]) Traceback (most recent call last): ... - ValueError: Argument basis (= [(1, -1)]) does not span a submodule of self + ValueError: Argument basis (= [(1, -1)]) does not span a submodule of this lattice + """ M = FreeQuadraticModule_integer_symmetric( ambient=self.ambient_module(), basis=basis, From de3f9cbac730e7031a4cc53aa291415660a2c841 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 05:19:29 +0000 Subject: [PATCH 150/218] Reviewer changes to 23671 --- src/doc/en/reference/references/index.rst | 3 + src/sage/modular/hypergeometric_motive.py | 87 +++++++++++++---------- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index b619a89f585..4c45894ee31 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1246,6 +1246,9 @@ REFERENCES: .. [Kan1958] \D. M. Kan, *A combinatorial definition of homotopy groups*, Ann. Math. (2) 67 (1958), 282-312. +.. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*, + Princeton University Press, Princeton NJ, 1991. + .. [Kaw2009] Kawahira, Tomoki. *An algorithm to draw external rays of the Mandelbrot set*, Nagoya University, 23 Apr. 2009. math.titech.ac.jp/~kawahira/programs/mandel-exray.pdf diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 52b9be3858b..ae0476b4194 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -33,6 +33,8 @@ - [Benasque2009]_ +- [Kat1991]_ + - [MagmaHGM]_ - [Fedorov2015]_ @@ -146,6 +148,8 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign): """ if len(traces) < d // 2: raise ValueError('not enough traces were given') + if i % 2 and d % 2: + raise ValueError('i and d may not both be odd') t = PowerSeriesRing(QQ, 't').gen() ring = PolynomialRing(ZZ, 'T') @@ -235,9 +239,8 @@ def cyclotomic_to_alpha(cyclo): if d == 1: alpha.append(QQ.zero()) else: - for k in range(1, d): - if gcd(k, d) == 1: - alpha.append(QQ((k, d))) + for k in ZZ(d).coprime_integers(d): + alpha.append(QQ((k, d))) return sorted(alpha) @@ -248,7 +251,7 @@ def alpha_to_cyclotomic(alpha): The input represents arguments of some roots of unity. The output represent a product of cyclotomic polynomials with exactly - the given roots. Note that the multiplicity of `r/s` in the list + the given roots. Note that the multiplicity of `r/s` in the list must be independent of `r`; otherwise, a ValueError will be raised. This is the inverse of :func:`cyclotomic_to_alpha`. @@ -271,9 +274,10 @@ def alpha_to_cyclotomic(alpha): Alpha = list(alpha) while Alpha: q = QQ(Alpha.pop()) + n = q.numerator() d = q.denominator() - for k in range(1, d): - if gcd(k, d) == 1 and QQ((k, d)) != q: + for k in d.coprime_integers(d): + if k != n: try: Alpha.remove(QQ((k, d))) except ValueError: @@ -311,8 +315,8 @@ def cyclotomic_to_gamma(cyclo_up, cyclo_down): INPUT: - - ``cyclo_up`` -- list of indices of cyclotomic polynomials - - ``cyclo_down`` -- list of indices of cyclotomic polynomials + - ``cyclo_up`` -- list of indices of cyclotomic polynomials in the numerator + - ``cyclo_down`` -- list of indices of cyclotomic polynomials in the denominator OUTPUT: @@ -325,13 +329,13 @@ def cyclotomic_to_gamma(cyclo_up, cyclo_down): sage: cyclotomic_to_gamma([6], [1]) {2: -1, 3: -1, 6: 1} """ - dico = defaultdict(lambda: 0) + dico = defaultdict(int) for d in cyclo_up: dico[d] += 1 for d in cyclo_down: dico[d] -= 1 - resu = defaultdict(lambda: 0) + resu = defaultdict(int) for n in dico: for d in divisors(n): resu[d] += moebius(n / d) * dico[n] @@ -369,7 +373,7 @@ def gamma_list_to_cyclotomic(galist): sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1]) ([2, 2, 8], [3, 3, 6]) """ - resu = defaultdict(lambda: 0) + resu = defaultdict(int) for n in galist: eps = sgn(n) for d in divisors(abs(n)): @@ -386,7 +390,8 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): INPUT: - three possibilities are offered: + three possibilities are offered, each describing a quotient + of products of cyclotomic polynomials. - ``cyclotomic`` -- a pair of lists of nonnegative integers, each integer `k` represents a cyclotomic polynomial `\Phi_k` @@ -394,7 +399,7 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): - ``alpha_beta`` -- a pair of lists of rationals, each rational represents a root of unity - - ``gamma_list`` -- a pair of list of nonnegative integers, + - ``gamma_list`` -- a pair of lists of nonnegative integers, each integer `n` represents a polynomial `x^n - 1` In the last case, it is also allowed to send just one list of signed @@ -404,17 +409,17 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([2],[1])) - Hypergeometric motive for [1/2] and [0] + Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/2],[0])) - Hypergeometric motive for [1/2] and [0] + Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) - Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5],[1,1,1,1,1])) - Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) - Hypergeometric motive for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] """ if gamma_list is not None: if isinstance(gamma_list[0], (list, tuple)): @@ -469,14 +474,14 @@ def __repr__(self): sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(alpha_beta=([1/2],[0])) - Hypergeometric motive for [1/2] and [0] + Hypergeometric data for [1/2] and [0] """ - txt = "Hypergeometric motive for {} and {}" + txt = "Hypergeometric data for {} and {}" return txt.format(self._alpha, self._beta) def twist(self): r""" - Return the twist of ``self``. + Return the twist of this data. This is defined by adding `1/2` to each rational in `\alpha` and `\beta`. @@ -488,7 +493,7 @@ def twist(self): sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2],[0])) sage: H.twist() - Hypergeometric motive for [0] and [1/2] + Hypergeometric data for [0] and [1/2] sage: Hyp(cyclotomic=([6],[1,2])).twist().cyclotomic_data() ([3], [1, 2]) @@ -499,14 +504,14 @@ def twist(self): def swap_alpha_beta(self): """ - Return the hypergeometric motive with ``alpha`` and ``beta`` exchanged. + Return the hypergeometric data with ``alpha`` and ``beta`` exchanged. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2],[0])) sage: H.swap_alpha_beta() - Hypergeometric motive for [0] and [1/2] + Hypergeometric data for [0] and [1/2] """ alpha, beta = self.alpha_beta() return HypergeometricData(alpha_beta=(beta, alpha)) @@ -533,7 +538,7 @@ def primitive_data(self): def zigzag(self, x, flip_beta=False): """ - Count ``alpha``'s up to ``x`` minus ``beta``'s up to ``x``. + Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. This function is used to compute the weight and the Hodge numbers. With `flip_beta` set to True, replace each `b` in `\beta` with `1-b`. @@ -564,7 +569,7 @@ def zigzag(self, x, flip_beta=False): def weight(self): """ - Return the motivic weight of ``self``. + Return the motivic weight of this motivic data. EXAMPLES: @@ -735,13 +740,13 @@ def gamma_list(self): """ gamma = self.gamma_array() resu = [] - for v in gamma: - resu += [sgn(gamma[v]) * v] * abs(gamma[v]) + for v, n in gamma.items(): + resu += [sgn(n) * v] * abs(n) return resu def __eq__(self, other): """ - Return whether ``self`` is equal to ``other``. + Return whether two data are equal. EXAMPLES:: @@ -758,7 +763,7 @@ def __eq__(self, other): def __ne__(self, other): """ - Return whether ``self`` is not equal to ``other``. + Return whether two data are unequal. EXAMPLES:: @@ -774,7 +779,7 @@ def __ne__(self, other): def is_primitive(self): """ - Return whether ``self`` is primitive. + Return whether this data is primitive. .. SEEALSO:: @@ -790,7 +795,7 @@ def is_primitive(self): sage: Hyp(gamma_list=[-3, 6, 9, -12]).is_primitive() False """ - return self.primitive_index() == 1 # ? + return self.primitive_index() == 1 def primitive_index(self): """ @@ -874,7 +879,7 @@ def hodge_numbers(self): alpha = [(x, 'a') for x in self._alpha] beta = [(x, 'b') for x in self._beta] height = 0 - hodge = defaultdict(lambda: 0) + hodge = defaultdict(int) for x, letter in sorted(alpha + beta): if letter == 'a': hodge[height] += 1 @@ -968,7 +973,7 @@ def padic_H_value(self, p, f, t, prec=20): m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) -# D = (self.weight() + 1 - m[0]) // 2 + # also: D = (self.weight() + 1 - m[0]) // 2 gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] @@ -1053,7 +1058,7 @@ def H_value(self, p, f, t, ring=None): m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) -# D = (self.weight() + 1 - m[0]) // 2 + # also: D = (self.weight() + 1 - m[0]) // 2 M = self.M_value() Fq = GF(q) @@ -1086,7 +1091,7 @@ def euler_factor(self, t, p, degree=0): - `t` -- rational number, not 0 or 1 - - `p` -- prime number + - `p` -- prime number of good reduction - ``degree`` -- optional integer (default 0) @@ -1168,9 +1173,9 @@ def euler_factor(self, t, p, degree=0): if not is_prime(p): raise ValueError('p not prime') if not all(x.denominator() % p for x in self._alpha + self._beta): - raise ValueError('p is wild') + raise NotImplementedError('p is wild') if (t.valuation(p) or (t - 1).valuation(p) > 0): - raise ValueError('p is tame') + raise NotImplementedError('p is tame') # now p is good if degree == 0: d = self.degree() @@ -1192,6 +1197,8 @@ def canonical_scheme(self, t=None): """ Return the canonical scheme. + This is a scheme that contains this hypergeometric motive in its cohomology. + EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp @@ -1210,6 +1217,10 @@ def canonical_scheme(self, t=None): in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring in t over Rational Field by the ideal (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^3*X1^4 + 1728/3125*Y0^2*Y1^5) + + REFERENCES: + + [Kat1991]_, section 5.4 """ if t is None: t = FractionField(QQ['t']).gen() From 8b5c9b17bd4c7d1fdf3d6c6e30d43cbced213e79 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 1 Oct 2017 10:59:40 +0200 Subject: [PATCH 151/218] trac #18395: correct use of rel tol in doctest --- src/sage/graphs/generic_graph_pyx.pyx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 2bf6b2a0714..f0001e10b4d 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -107,10 +107,11 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: G = graphs.DodecahedralGraph() sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast - sage: spring_layout_fast(G) - {0: [0.00..., 0.04...], # abs tol 0.03 - ... # abs tol 0.03 - 902: [-0.47..., -0.10...]} # abs tol 0.03 + sage: pos = spring_layout_fast(G) + sage: pos[0] # abs tol 0.03 + [0.00..., 0.03...] + sage: pos[902] # abs tol 0.03 + [-0.48..., -0.10...] With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -125,10 +126,11 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: G = graphs.DodecahedralGraph() sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast - sage: spring_layout_fast(G, by_component = True) - {0: [2.21..., -0.00...], # abs tol 0.03 - ... # abs tol 0.03 - 902: [3.07..., 0.86...]} # abs tol 0.03 + sage: pos = spring_layout_fast(G, by_component = True) + sage: pos[0] # abs tol 0.03 + [2.21..., -0.00...] + sage: pos[902] # abs tol 0.03 + [3.07..., 0.86...] """ if by_component: From 18df6e6efdeb307b3c7abdb15fbccfe191dd5901 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sun, 1 Oct 2017 14:20:19 +0200 Subject: [PATCH 152/218] Use Python's set instead of Sage's Set in the Schouten-Nijenhuis bracket --- .../manifolds/differentiable/multivectorfield.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index ec01d6e99df..84446569caa 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -1381,7 +1381,7 @@ def bracket(self, other): True """ - from sage.sets.set import Set + from itertools import combinations from sage.combinat.permutation import Permutation from sage.tensor.modules.comp import (Components, CompWithSym, CompFullyAntiSym) @@ -1454,16 +1454,14 @@ def bracket(self, other): dbb[[ind+(k,)]] = val.coord_function(chart).diff(k) # Computation for ind in resuc.non_redundant_index_generator(): - sind = Set(ind) # {i_1, i_2, ..., i_{p+q-1}} + sind = set(ind) # {i_1, i_2, ..., i_{p+q-1}} # Term a^{l j_2 ... j_p} \partial_l b^{k_1 ... k_q} # with (j_2,...,j_p,k_1,...,k_q) spanning all permutations of # (i_1, i_2, ..., i_{p+q-1}) - sub_sind_p = sind.subsets(pp-1) - for sind_a in sub_sind_p: + for sind_a in combinations(sind, pp-1): sind_b = sind.difference(sind_a) ind_a = tuple(sorted(sind_a)) ind_b = tuple(sorted(sind_b)) - ## print 'ind, ind_a, ind_b:', ind, ind_a, ind_b sum = 0 for l in fmodule.irange(): sum += aa[[(l,) + ind_a]] * dbb[[ind_b + (l,)]] @@ -1476,12 +1474,10 @@ def bracket(self, other): # Term b^{l k_2 ... k_q} \partial_l a^{j_1 ... j_p} # with (j_1,...,j_p,k_2,...,k_q) spanning all permutations of # (i_1, i_2, ..., i_{p+q-1}) - sub_sind_q = sind.subsets(qq-1) - for sind_b in sub_sind_q: + for sind_b in combinations(sind, qq-1): sind_a = sind.difference(sind_b) ind_a = tuple(sorted(sind_a)) ind_b = tuple(sorted(sind_b)) - ## print 'ind, ind_a, ind_b:', ind, ind_a, ind_b sum = 0 for l in fmodule.irange(): sum += bb[[(l,) + ind_b]] * daa[[ind_a + (l,)]] From ac55d864d5ec5dd8121a89b6771f7abbb5e46397 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 1 Oct 2017 16:32:17 +0200 Subject: [PATCH 153/218] fix mistakes in definition of GrowthDiagram.rotate and GrowthDiagram.conjugate --- src/sage/combinat/growth.py | 49 +++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 208d00051c8..6f9e2d75557 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -705,9 +705,24 @@ def conjugate(self): sage: Gc = G.conjugate() sage: (Gc.P_symbol(), Gc.Q_symbol()) == (G.Q_symbol(), G.P_symbol()) True + + TESTS: + + Check that labels and shape are handled correctly:: + + sage: o = [[2,1],[2,2],[3,2],[4,2],[4,1],[4,1,1],[3,1,1],[3,1],[3,2],[3,1],[2,1]] + sage: l = [o[i//2] if is_even(i) else min(o[(i-1)//2],o[(i+1)//2]) + ....: for i in range(2*len(o)-1)] + sage: la = list(range(len(o)-2, 0, -1)) + sage: G = RuleRSK(labels=l[1:-1], shape=la) + sage: G.out_labels() == G.conjugate().out_labels()[::-1] + True """ F = {(j,i): v for (i,j),v in self._filling.items()} - return GrowthDiagram(self.rule, filling=F) + return GrowthDiagram(self.rule, + filling=F, + shape=self.shape().conjugate(), + labels=self.in_labels()[::-1]) def rotate(self): r""" @@ -729,11 +744,35 @@ def rotate(self): ....: for t in [G.P_symbol(), G.Q_symbol()]]) [ 1 1 1 1 1 2 ] [ 2 , 3 ] + + TESTS: + + Check that shape is handled correctly:: + + sage: RuleRSK = GrowthDiagram.rules.RSK() + sage: G = GrowthDiagram(RuleRSK, + ....: filling={(0,2):1, (3,1):2, (2,1):3}, + ....: shape=SkewPartition([[5,5,5,3],[3,1]])) + sage: G + . . . 0 0 + . 0 3 2 0 + 1 0 0 0 0 + 0 0 0 + sage: G.rotate() + . . 0 0 0 + 0 0 0 0 1 + 0 2 3 0 + 0 0 """ - max_row = max(i for i, _ in self._filling) - max_col = max(j for _, j in self._filling) - F = {(max_row-i,max_col-j): v for (i,j),v in self._filling.items()} - return GrowthDiagram(self.rule, filling=F) + l = self._lambda[0] + h = len(self._lambda) + shape_lambda = [l-p for p in self._mu] + [l]*(h-len(self._mu)) + shape_mu = [l-p for p in self._lambda] + shape = SkewPartition([shape_lambda[::-1], shape_mu[::-1]]) + F = {(l-i-1, h-j-1): v for (i,j),v in self._filling.items()} + return GrowthDiagram(self.rule, + filling=F, + shape=shape) def half_perimeter(self): r""" From 030d04b2fd06bf9a3757710777013fcd9b6bde74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 29 Sep 2017 22:15:02 +0200 Subject: [PATCH 154/218] some work on richcmp and __cmp__ towards python3 --- src/sage/databases/findstat.py | 9 +++---- src/sage/libs/singular/ring.pyx | 7 +++--- src/sage/modular/hecke/module.py | 7 ------ src/sage/modular/modform/numerical.py | 24 +++++++++---------- .../rings/laurent_series_ring_element.pyx | 4 ++-- src/sage/rings/qqbar.py | 20 +++++++--------- 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index dd23d7b75cf..33bdf51e4ad 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -179,6 +179,7 @@ def increasing_tree_shape(elt, compare=min): from sage.categories.sets_cat import Sets from sage.structure.sage_object import SageObject +from sage.structure.richcmp import richcmp from sage.misc.misc import verbose from sage.rings.integer import Integer @@ -1924,7 +1925,7 @@ def __reduce__(self): """ return (FindStatCollection, (self.id(),)) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ TESTS:: @@ -1950,7 +1951,7 @@ def __cmp__(self, other): sage: sorted(c for c in FindStatCollections())[0] # optional -- internet Cc0001: Permutations """ - return self.id().__cmp__(other.id()) + return richchmp(self.id(), other.id(), op) def is_supported(self): """ @@ -2646,7 +2647,7 @@ def _repr_(self): """ return "%s: %s" %(self.id_str(), self._map[FINDSTAT_MAP_NAME]) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ TESTS:: @@ -2672,7 +2673,7 @@ def __cmp__(self, other): sage: sorted(c for c in FindStatMaps())[0] # optional -- internet Mp00001: to semistandard tableau """ - return self.id().__cmp__(other.id()) + return richcmp(self.id(), other.id(), op) def name(self): r""" diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 87e27f5722b..de6ec294abf 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -454,7 +454,8 @@ cdef class ring_wrapper_Py(object): def __cmp__(ring_wrapper_Py left, ring_wrapper_Py right): """ - Compare ``left`` and ``right`` so that instances can be used as dictionary keys. + Compare ``left`` and ``right`` so that instances can be used + as dictionary keys. INPUT: @@ -469,8 +470,8 @@ cdef class ring_wrapper_Py(object): sage: from sage.libs.singular.ring import ring_wrapper_Py sage: t = ring_wrapper_Py() - sage: t.__cmp__(t) - 0 + sage: t == t + True """ if left._ring < right._ring: return -1 diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 343850db096..039a33d2cca 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -516,13 +516,6 @@ def __init__(self, base_ring, level, weight, category=None): HeckeModule_generic.__init__(self, base_ring, level, category=category) self.__weight = weight -# def __cmp__(self, other): -# if not isinstance(other, HeckeModule_free_module): -# return -1 -# c = HeckeModule_generic.__cmp__(self, other) -# if c: return c -# return cmp(self.__weight, other.__weight) - # def __contains__(self, x): # r""" # Return True if x is an element of self. diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index a269b623775..1370070da37 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -15,6 +15,7 @@ from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence +from sage.structure.richcmp import richcmp_method, richcmp from sage.modular.modsym.all import ModularSymbols from sage.modular.arithgroup.all import Gamma0 from sage.modules.all import vector @@ -27,6 +28,7 @@ # This variable controls importing the SciPy library sparingly scipy=None +@richcmp_method class NumericalEigenforms(SageObject): """ numerical_eigenforms(group, weight=2, eps=1e-20, delta=1e-2, tp=[2,3,5]) @@ -108,24 +110,22 @@ def __init__(self, group, weight=2, eps=1e-20, self._eps = eps self._delta = delta - def __cmp__(self, other): + def __richcmp__(self, other, op): """ - Compare two spaces of numerical eigenforms. Currently - returns 0 if they come from the same space of modular - symbols, and -1 otherwise. + Compare two spaces of numerical eigenforms. + + They are considered equal if and only if they come from the + same space of modular symbols. EXAMPLES:: sage: n = numerical_eigenforms(23) - sage: n.__cmp__(loads(dumps(n))) - 0 + sage: n == loads(dumps(n)) + True """ - if not isinstance( other, NumericalEigenforms ): - raise ValueError("%s is not a space of numerical eigenforms"%other) - if self.modular_symbols() == other.modular_symbols(): - return 0 - else: - return -1 + if not isinstance(other, NumericalEigenforms): + return NotImplemented + return richcmp(self.modular_symbols(), other.modular_symbols(), op) def level(self): """ diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 397e5bc291f..2a167b11312 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -978,7 +978,7 @@ cdef class LaurentSeries(AlgebraElement): cpdef _richcmp_(self, right_r, int op): r""" - Comparison of self and right. + Comparison of ``self`` and ``right``. We say two approximate Laurent series are equal, if they agree for all coefficients up to the *minimum* of the precisions of each. @@ -987,7 +987,7 @@ cdef class LaurentSeries(AlgebraElement): but consistent with the idea that the variable of a Laurent series is considered to be "very small". - See power_series_ring_element.__cmp__() for more + See :meth:`power_series_ring_element._richcmp_` for more information. EXAMPLES:: diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 49d2bcf178b..adf6bdbb25c 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -519,7 +519,7 @@ from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject -from sage.structure.richcmp import (richcmp, +from sage.structure.richcmp import (richcmp, richcmp_method, rich_to_bool, richcmp_not_equal, op_EQ, op_NE, op_LE, op_LT, op_GE, op_GT) @@ -2197,6 +2197,8 @@ def __init__(self, child1, child1_poly, child2, child2_poly, parent): algebraic_generator_counter = 0 + +@richcmp_method class AlgebraicGenerator(SageObject): r""" An ``AlgebraicGenerator`` represents both an algebraic number `\alpha` and @@ -2278,9 +2280,9 @@ def __hash__(self): """ return self._index - def __cmp__(self, other): + def __richcmp__(self, other, op): r""" - Compare self with another AlgebraicGenerator object. + Compare ``self`` with another ``AlgebraicGenerator`` object. EXAMPLES:: @@ -2290,16 +2292,10 @@ def __cmp__(self, other): sage: nf = NumberField(y^2 - y - 1, name='a', check=False) sage: root = ANRoot(x^2 - x - 1, RIF(1, 2)) sage: gen = AlgebraicGenerator(nf, root) - sage: gen.__cmp__(qq_generator) - 1 + sage: gen > qq_generator + True """ - si = self._index - oi = other._index - if si < oi: - return -1 - if si > oi: - return 1 - return 0 + return richcmp(self._index, other._index, op) def is_complex(self): r""" From f958edb6be7b4e12672d9f9dcc4cec5386efa2c2 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 1 Oct 2017 16:54:50 +0200 Subject: [PATCH 155/218] add to explanatory sentences --- src/sage/combinat/growth.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 6f9e2d75557..9c2841d505a 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -695,6 +695,10 @@ def conjugate(self): the growth diagram with the filling reflected over the main diagonal. + The sequence of labels along the boundary on the side of the + origin is the reversal of the corresponding sequence of the + original growth diagram. + When the filling is a permutation, the conjugate filling corresponds to its inverse. @@ -728,6 +732,10 @@ def rotate(self): r""" Return the growth diagram with the filling rotated by 180 degrees. + The rotated growth diagram is initialized with + ``labels=None``, that is, all labels along the boundary on + the side of the origin are set to ``rule.zero``. + For RSK-growth diagrams and rectangular fillings, this corresponds to evacuation of the `P`- and the `Q`-symbol. From 314b45fea06ecce0567d73a18ca2e78e80549e6d Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Sun, 1 Oct 2017 15:32:07 +0000 Subject: [PATCH 156/218] Rename inverse transform as trace polynomial --- .../rings/polynomial/polynomial_element.pyx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 86aecd511d5..bc43317093f 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -24,6 +24,8 @@ AUTHORS: - Edgar Costa (2017-07): Added rational reconstruction. +- Kiran Kedlaya (2017-09): Added reciprocal transform, trace polynomial. + TESTS:: sage: R. = ZZ[] @@ -7856,6 +7858,10 @@ cdef class Polynomial(CommutativeAlgebraElement): `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + .. SEEALSO:: + + The inverse operation is :meth:`trace_polynomial`. + INPUT: - ``R`` -- polynomial - ``q`` -- scalar (default: `1`) @@ -7870,18 +7876,14 @@ cdef class Polynomial(CommutativeAlgebraElement): x^5 - 1 sage: u.reciprocal_transform(q=3) x^4 + x^3 + 5*x^2 + 3*x + 9 - - .. SEEALSO:: - - :meth:`inverse_reciprocal_transform` """ S = self.parent() x = S.gen() return S(x**(self.degree()) * self(x + q/x)) * R - def inverse_reciprocal_transform(self): + def trace_polynomial(self): r""" - Undo the reciprocal transform. + Compute the trace polynomial and cofactor. The input `P` and output `Q` satisfy the relation `P(x) = Q(x + q/x) x^{\deg(Q)} R(x)`. @@ -7890,23 +7892,24 @@ cdef class Polynomial(CommutativeAlgebraElement): `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + .. SEEALSO:: + + The inverse operation is :meth:`reciprocal_transform`. + OUTPUT: - - ``Q`` -- polynomial - - ``R`` -- polynomial - - ``q`` -- nonzero scalar + - ``Q`` -- trace polynomial + - ``R`` -- cofactor + - ``q`` -- scaling factor EXAMPLES:: sage: pol. = PolynomialRing(Rationals()) - sage: u = x^5 - 1; u.inverse_reciprocal_transform() + sage: u = x^5 - 1; u.trace_polynomial() (x^2 + x - 1, x - 1, 1) sage: u = x^4 + x^3 + 5*x^2 + 3*x + 9 - sage: u.inverse_reciprocal_transform() + sage: u.trace_polynomial() (x^2 + x - 1, 1, 3) - .. SEEALSO:: - - :meth:`reciprocal_transform` """ S = self.parent() x = S.gen() From 0c54a659e37c82c1b98d9299d3dc04dc86aedec0 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 15:57:35 +0000 Subject: [PATCH 157/218] Add cached_method to hypergeometric motives --- src/sage/modular/hypergeometric_motive.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index ae0476b4194..f6f756e978e 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -66,6 +66,7 @@ from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.functions.generalized import sgn from sage.functions.other import floor +from sage.misc.cachefunc import cached_method from sage.misc.functional import cyclotomic_polynomial from sage.misc.misc_c import prod from sage.rings.fraction_field import FractionField @@ -916,6 +917,7 @@ def z(x): (T**z(a) - 1) // (T - 1) for a in set(alpha)) + @cached_method def padic_H_value(self, p, f, t, prec=20): """ Return the `p`-adic trace of Frobenius, computed using the @@ -989,6 +991,7 @@ def padic_H_value(self, p, f, t, prec=20): resu = ZZ(-1) ** m[0] / (1 - q) * sigma return IntegerModRing(p**prec)(resu).lift_centered() + @cached_method def H_value(self, p, f, t, ring=None): """ Return the trace of the Frobenius, computed in terms of Gauss sums @@ -1083,6 +1086,7 @@ def H_value(self, p, f, t, ring=None): resu = resu.real_part().round() return resu + @cached_method def euler_factor(self, t, p, degree=0): """ Return the Euler factor of the motive `H_t` at prime `p`. From 12acb67fbaea03e6f9420248d3458b05811fe2b3 Mon Sep 17 00:00:00 2001 From: Amy Feaver Date: Sun, 1 Oct 2017 17:25:34 +0000 Subject: [PATCH 158/218] Update documentation and formatting. Add TODOs --- ...free_quadratic_module_integer_symmetric.py | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 49315a66fb6..9747f32ea13 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -29,12 +29,14 @@ def IntegralLattice(inner_product_matrix, basis=None, already_echelonized=False, Here, lattices have an ambient quadratic space `\Q^n` and a distinguished basis. INPUT: - - - ``ambient`` -- a free quadratic module + + - ``inner_product_matrix`` -- a symmetric matrix over the rationals - ``basis`` -- a list of elements of ambient or a matrix - - - ``inner_product_matrix`` -- a symmetric matrix over the rationals + + TODO: + + - Make sure inner_product_matrix is a matrix EXAMPLES:: @@ -79,14 +81,6 @@ class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_b r""" This class represents non-degenerate, integral, symmetric free quadratic `\Z`-modules. - INPUT: - - - ``ambient`` -- a free quadratic module - - - ``basis`` -- a list of elements of ``ambient``, or a matrix - - - ``inner_product_matrix`` -- a symmetric matrix over the rationals - EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice @@ -101,6 +95,14 @@ class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_b def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): r""" Create the integral lattice spanned by ``basis`` in the ambient space. + + INPUT: + + - ``ambient`` -- + + - ``basis`` -- + + - ``inner_product_matrix`` -- TESTS:: @@ -146,7 +148,7 @@ def _repr_(self): def is_even(self): r""" - Return whether the diagonal entries of the Gram matrix are even. + Returns true if the diagonal entries of the Gram matrix are even. EXAMPLES:: @@ -159,7 +161,7 @@ def is_even(self): True """ for d in self.gram_matrix().diagonal(): - if d % 2 !=0: + if d % 2 != 0: return False return True @@ -191,7 +193,7 @@ def dual_lattice(self): """ return self.span(self.gram_matrix().inverse()*self.basis_matrix()) - def discriminant_group(self,s=0): + def discriminant_group(self, s=0): r""" Return the discriminant group `L^\vee / L` of this lattice. @@ -259,6 +261,10 @@ def signature_pair(self): def direct_sum(self, M): r""" Return the direct sum of this lattice with ``M``. + + INPUT: + + - ``M`` -- a module over `\Z` EXAMPLES:: @@ -289,6 +295,18 @@ def is_primitive(self, M): A `\Z`-submodule ``M`` of a `\Z`-module `L` is called primitive if the quotient ``L/M`` is torsion free. + + INPUT: + + - ``M`` -- a module + + TODO: + + - Check that M is the right type + + - make sure there is the same ambient space + + - describe the input M in more detail EXAMPLES:: @@ -310,9 +328,21 @@ def is_primitive(self, M): """ return (gcd((self/M).invariants()) == 0) - def orthogonal_complement(self,M): + def orthogonal_complement(self, M): r""" Return the orthogonal complement of ``M`` in this lattice. + + INPUT: + + - ``M`` -- + + TODO: + + - make sure the input is a free module + + - make sure there is the same ambient space + + - describe the input M in more detail EXAMPLES:: @@ -327,17 +357,23 @@ def orthogonal_complement(self,M): [ 2 1] [ 1 -2] """ - K = (self.inner_product_matrix()*M.basis_matrix().transpose()).kernel() + K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() K.base_extend(QQ) return self.sublattice(self.intersection(K).basis()) - def sublattice(self,basis): + def sublattice(self, basis): r""" Return the sublattice spanned by ``basis``. INPUT: - - ``gens`` -- a list of elements of this lattice, or a rational matrix. + - ``basis`` -- + + TODO: + + - Check that basis input is of the right type + + - describe the input in more detail EXAMPLES:: @@ -377,6 +413,10 @@ def overlattice(self, gens): INPUT: - ``gens`` -- a list of elements of this lattice, or a rational matrix + + TODO: + + - make sure input ``gens`` is of the right type EXAMPLES:: From 6955600fc2baff0cf8a0fd60977cdda3ebca3ef9 Mon Sep 17 00:00:00 2001 From: Anthony Varilly-Alvarado Date: Sun, 1 Oct 2017 17:30:10 +0000 Subject: [PATCH 159/218] Documented qmodnz.py and qmodnz_element.py --- src/sage/groups/abelian_gps/qmodnz.py | 153 +++++++++++++++ src/sage/groups/abelian_gps/qmodnz_element.py | 185 +++++++++++++++++- 2 files changed, 335 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/abelian_gps/qmodnz.py b/src/sage/groups/abelian_gps/qmodnz.py index 51b6c407259..6dfad3200ab 100644 --- a/src/sage/groups/abelian_gps/qmodnz.py +++ b/src/sage/groups/abelian_gps/qmodnz.py @@ -5,14 +5,73 @@ from sage.arith import srange class QmodnZ(AbelianGroup): + r""" + The ``QmodnZ`` class represents the abelian group Q/nZ. + + INPUT: + + The constructor may be called in any of the following ways. + + #. ``QmodnZ(n)``, where + + - `n` -- a rational number (including 0 or negative rational numbers). + + #. ``QQ/(n*ZZ)``, where + + - `n` -- an integer (including 0 or negative integers). + + + OUTPUT: + + The abelian group Q/nZ. + + EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: QQ/(19*ZZ) + Q/19Z + + sage: QmodnZ(19) + Q/19Z + + sage: QmodnZ(2/3) + Q/(2/3)Z + """ + Element = QmodnZ_Element def __init__(self, n=1): + r""" + EXAMPLES:: + + sage: G = QmodnZ(2) + sage: G + Q/2Z + + TESTS:: + + sage: G = QQ/(19*ZZ) + sage: TestSuite(G).run() + """ self.n = QQ(n).abs() category = Groups().Commutative().Topological().Infinite() AbelianGroup.__init__(self, base=ZZ, category=category) self._populate_coercion_lists_(coerce_list=[QQ]) def _repr_(self): + r""" + Display the group. + + EXAMPLES:: + + sage: G = QmodnZ(1); G + Q/Z + + sage: G = QQ/(3*ZZ); G + Q/3Z + + sage: G = QmodnZ(1/5); G + Q/(1/5)Z + """ if self.n == 1: return "Q/Z" elif self.n in ZZ: @@ -21,22 +80,116 @@ def _repr_(self): return "Q/(%s)Z"%(self.n) def __eq__(self, other): + r""" + Return ``True`` if ``self`` and ``other`` are identical. + + This means they are the same abelian group. + + EXAMPLES:: + + sage: G = QQ/(5*ZZ) + sage: H = QQ/(5*ZZ) + sage: K = QQ/(3*ZZ) + sage: L = QmodnZ(25/5) + sage: G == H #indirect doctest + True + sage: G == K #indirect doctest + False + + TESTS:: + + sage: G == G + True + sage: H == G + True + sage: G == L + True + sage: K == 7 + False + """ if type(self) == type(other): return self.n == other.n return NotImplemented def __ne__(self, other): + r""" + Return ``True`` if ``self`` and ``other`` are not identical. + + This means they are different abelian groups. + + EXAMPLES:: + + sage: G = QQ/(5*ZZ) + sage: H = QQ/(5*ZZ) + sage: K = QQ/(3*ZZ) + sage: L = QmodnZ(25/5) + sage: G != H #indirect doctest + False + sage: G != K #indirect doctest + True + """ + if type(self) == type(other): return self.n != other.n return NotImplemented + #TODO: Disallow order comparisons between different Q/nZ's + # e.g., sage: QmodnZ(10/3) > QmodnZ(5/3) + # returns False. + def _element_constructor_(self, x): + r""" + Construct an element in Q/nZ. + + EXAMPLES:: + + sage: G = QmodnZ(2/3) + sage: G(5/6) + 1/6 + """ return self.element_class(self, QQ(x)) def random_element(self, *args, **kwds): + r""" + Return a random element of Q/nZ. + + EXAMPLES:: + + sage: G = QQ/(6*ZZ) + sage: G.random_element() + 1 + sage: G.random_element() + 35/6 + sage: G.random_element() + 1/4 + + Extra positional or keyword arguments are passed through:: + + sage: G = QmodnZ(4/5) + sage: G.random_element(distribution='1/n') + 1/2 + sage: G.random_element(distribution='1/n') + 3/5 + sage: G.random_element(distribution='1/n') + 11/20 + """ return self(QQ.random_element(*args, **kwds)) def __iter__(self): + r""" + Creates an iterator that generates the elements of Q/nZ without + repetition, organized by increasing denominator; for a fixed denominator + elements are listed by increasing numerator. + + EXAMPLES: + + The first 19 elements of Q/5Z:: + + sage: import itertools + sage: lst = [a for a in itertools.islice(QQ/(5*ZZ),19)]; lst + [0, 1, 2, 3, 4, 1/2, 3/2, 5/2, 7/2, 9/2, 1/3, 2/3, 4/3, 5/3, 7/3, 8/3, 10/3, 11/3, 13/3] + """ + if self.n == 0: for x in QQ: yield self(x) diff --git a/src/sage/groups/abelian_gps/qmodnz_element.py b/src/sage/groups/abelian_gps/qmodnz_element.py index 93b627fb5fa..a0bab2ae057 100644 --- a/src/sage/groups/abelian_gps/qmodnz_element.py +++ b/src/sage/groups/abelian_gps/qmodnz_element.py @@ -5,7 +5,41 @@ from sage.structure.richcmp import richcmp, op_EQ, op_NE class QmodnZ_Element(AdditiveGroupElement): + r""" + The ``QmodnZ_Element`` class represents an element of the abelian group Q/nZ. + + INPUT: + + - ``q`` -- a rational number. + + - ``parent`` -- the parent abelian group Q/nZ + + OUTPUT: + + The element `q` of abelian group Q/nZ, in standard form. + + EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: G = QQ/(19*ZZ) + sage: q = G(400/19) + sage: q + 39/19 + + """ + def __init__(self, parent, x, construct=False): + r""" + Create an element of Q/nZ. + + EXAMPLES:: + + sage: G = QQ/(3*ZZ) + sage: g = G.random_element() + sage: g + 3/8 + """ + AdditiveGroupElement.__init__(self, parent) # x = (a/b) = q(n/m) + r/mb # am = q(nb) + r @@ -24,9 +58,42 @@ def __init__(self, parent, x, construct=False): self._x = r/(m*b) def lift(self): + r""" + Returns the rational number representation of ``self`` + + EXAMPLES:: + sage: G = QQ/(5*ZZ) + sage: g = G(2/4); g + 1/2 + sage: q = lift(g); q + 1/2 + + TESTS:: + sage: q.parent() == QQ + True + """ + return self._x def __neg__(self): + r""" + Returns the additive inverse of ``self`` in Q/nZ. + + EXAMPLES:: + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: -g + 2/21 + + TESTS:: + sage: G = QmodnZ(19/23) + sage: g = G(15/23) + sage: -g + 4/23 + sage: g + -g == G(0) + True + """ + if self._x == 0: return self else: @@ -34,13 +101,47 @@ def __neg__(self): return QZ.element_class(QZ, QZ.n - self._x, True) def _add_(self, other): + r""" + Returns the sum of ``self`` and ``other`` in Q/nZ + + EXAMPLES:: + sage: G = QmodnZ(9/10) + sage: g = G(5) + sage: h = G(1/2) + sage: g + h + 1/10 + sage: g + h == G(1/10) #indirect doctest + True + + TESTS:: + sage: h + g == G(1/10) + True + """ + QZ = self.parent() ans = self._x + other._x - if ans > QZ.n: + if ans >= QZ.n: ans -= QZ.n return QZ.element_class(QZ, ans, True) def _sub_(self, other): + r""" + Returns the difference of ``self`` and ``other`` in Q/nZ + + EXAMPLES:: + sage: G = QmodnZ(9/10) + sage: g = G(4) + sage: h = G(1/2) + sage: g - h + 4/5 + sage: h - g + 1/10 + sage: g - h == G(4/5) #indirect doctest + True + sage: h - g == G(1/10) #indirect doctest + True + """ + QZ = self.parent() ans = self._x - other._x if ans < 0: @@ -48,30 +149,108 @@ def _sub_(self, other): return QZ.element_class(QZ, ans, True) def _rmul_(self, c): + r""" + Returns the (right) scalar product of ``self`` by ``c`` in Q/nZ. + + EXAMPLES:: + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: g*6 + 1/7 + """ QZ = self.parent() return QZ.element_class(QZ, self._x * c) def _lmul_(self, c): + r""" + Returns the (left) scalar product of ``self`` by ``c`` in Q/nZ. + + EXAMPLES:: + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: 6*g + 1/7 + + TESTS:: + sage: 6*g == g*6 + True + sage: 6*g == 5*g + False + """ return self._rmul_(c) - def __truediv__(self, other): + def __div__(self, other): + #TODO: This needs to be implemented. QZ = self.parent() - other = ZZ(Other) + other = ZZ(other) return QZ.element_class(QZ, self._x / other, True) def _repr_(self): + r""" + Display the element + + EXAMPLES:: + + sage: G = QmodnZ(8) + sage: g = G(25/7); g; + 25/7 + + """ + return repr(self._x) def __hash__(self): + r""" + TESTS:: + + sage: G = QmodnZ(4) + sage: g = G(4/5) + sage: hash(g) + -7046029254386353128 + sage: hash(G(3/4)) + 3938850096065010962 + sage: hash(G(1)) + 1 + """ + return hash(self._x) def _richcmp_(self, right, op): + r""" + Compare ``self`` with ``right``. + + OUTPUT: + + boolean + + EXAMPLES:: + + sage: G = QQ/(4*ZZ) + sage: g = G(4/5) + sage: h = G(6/7) + sage: g == h + False + sage: g == g + True + """ if op == op_EQ or op == op_NE: return richcmp(self._x, right._x, op) else: return NotImplemented def additive_order(self): + r""" + Returns the order of ``self`` in the abelian group Q/nZ. + + EXAMPLES:: + sage: G = QmodnZ(12) + sage: g = G(5/3) + sage: g.additive_order() + 36 + sage: (-g).additive_order() # indirect doctest + 36 + """ + # a/b * k = n/m * r QZ = self.parent() if QZ.n == 0: From c5af2d4fe2845b73d47f1ced95fac03eef8aa1af Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 17:35:21 +0000 Subject: [PATCH 160/218] Fix docstring formatting, add doctests, fix error in cofactor of trace_polynomial --- .../rings/polynomial/polynomial_element.pyx | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index bc43317093f..e4acdbe3243 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7852,7 +7852,10 @@ cdef class Polynomial(CommutativeAlgebraElement): Transform a general polynomial into a self-reciprocal polynomial. The input `Q` and output `P` satisfy the relation - `P(x) = Q(x + q/x) x^{\deg(Q)} R(x)`. + + .. MATH:: + + P(x) = Q(x + q/x) x^{\deg(Q)} R(x). In this relation, `Q` has all roots in the real interval `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the @@ -7863,8 +7866,9 @@ cdef class Polynomial(CommutativeAlgebraElement): The inverse operation is :meth:`trace_polynomial`. INPUT: - - ``R`` -- polynomial - - ``q`` -- scalar (default: `1`) + + - ``R`` -- polynomial + - ``q`` -- scalar (default: `1`) EXAMPLES:: @@ -7886,20 +7890,26 @@ cdef class Polynomial(CommutativeAlgebraElement): Compute the trace polynomial and cofactor. The input `P` and output `Q` satisfy the relation - `P(x) = Q(x + q/x) x^{\deg(Q)} R(x)`. - In this relation, `Q` has all roots in the real interval + .. MATH:: + + P(x) = Q(x + q/x) x^{\deg(Q)} R(x). + + In this relation, `Q` has all roots in the real interval `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the - circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. We thus require + that the base ring of this polynomial have a coercion to the real + numbers. .. SEEALSO:: The inverse operation is :meth:`reciprocal_transform`. OUTPUT: - - ``Q`` -- trace polynomial - - ``R`` -- cofactor - - ``q`` -- scaling factor + + - ``Q`` -- trace polynomial + - ``R`` -- cofactor + - ``q`` -- scaling factor EXAMPLES:: @@ -7910,27 +7920,51 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: u.trace_polynomial() (x^2 + x - 1, 1, 3) + We check that this function works for rings + that have a coercion to the reals:: + + sage: K. = NumberField(x^2-2,embedding=1.4) + sage: u = x^4 + a*x^3 + 3*x^2 + 2*a*x + 4 + sage: u.trace_polynomial() + (x^2 + a*x - 1, 1, 2) + sage: (u*(x^2-2)).trace_polynomial() + (x^2 + a*x - 1, x^2 - 2, 2) + sage: (u*(x^2-2)^2).trace_polynomial() + (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, 1, 2) + sage: (u*(x^2-2)^3).trace_polynomial() + (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, x^2 - 2, 2) + sage: u = x^4 + a*x^3 + 3*x^2 + 4*a*x + 16 + sage: u.trace_polynomial() + (x^2 + a*x - 5, 1, 4) + sage: (u*(x-2)).trace_polynomial() + (x^2 + a*x - 5, x - 2, 4) + sage: (u*(x+2)).trace_polynomial() + (x^2 + a*x - 5, x + 2, 4) """ S = self.parent() + A = S.base_ring() x = S.gen() if self[0] == 0: - raise ValueError, "Polynomial not self-reciprocal" + raise ValueError("Polynomial not self-reciprocal") d = self.degree() sg = (self[0]/self[d]).sign() - q = abs(self[0]/self[d])**(2/d) - if not q in S.base_ring(): - raise ValueError, "Polynomial not self-reciprocal" - for i in range(d+1): + try: + q = A(abs(self[0]/self[d])**(2/d)) + except (TypeError, ValueError): + raise ValueError("Polynomial not self-reciprocal") + for i in range(d/2+1): if self[d-i] != sg*self[i]/q**(d/2-i): - raise ValueError, "Polynomial not self-reciprocal" - cofactor = S(1) + raise ValueError("Polynomial not self-reciprocal") Q = self - if sg == -1: - cofactor *= x-q - Q //= x-q - if Q.degree() %2 == 1: - cofactor *= x+q - Q //= x+q + if sg == -1 and Q.degree() % 2 == 0: + cofactor = x**2 - q + elif sg == -1: + cofactor = x - q.sqrt() + elif Q.degree() % 2 == 1: + cofactor = x + q.sqrt() + else: + cofactor = S(1) + Q //= cofactor coeffs = [] m = Q.degree() // 2 for i in reversed(range(m+1)): From a1c728647ff1ee02634691ff2600a4c44565fbd6 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 1 Oct 2017 20:38:20 +0200 Subject: [PATCH 161/218] trac #18395: test that we have as many vertices as computed positions --- src/sage/graphs/generic_graph_pyx.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index f0001e10b4d..451911e270c 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -112,6 +112,8 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True [0.00..., 0.03...] sage: pos[902] # abs tol 0.03 [-0.48..., -0.10...] + sage: len(pos) == G.order() + True With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -131,6 +133,8 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True [2.21..., -0.00...] sage: pos[902] # abs tol 0.03 [3.07..., 0.86...] + sage: len(pos) == G.order() + True """ if by_component: From cc5ad3635d4dfa54438a6168e2956b19d7daf2ca Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 21:41:55 +0200 Subject: [PATCH 162/218] Added some input consistency checks and improved documentation. --- ...free_quadratic_module_integer_symmetric.py | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 9747f32ea13..5963b9d040c 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -20,7 +20,7 @@ # ############################################################################### -def IntegralLattice(inner_product_matrix, basis=None, already_echelonized=False, check=True): +def IntegralLattice(inner_product_matrix, basis=None): r""" Return the integral lattice spanned by ``basis`` in the ambient space. @@ -34,9 +34,11 @@ def IntegralLattice(inner_product_matrix, basis=None, already_echelonized=False, - ``basis`` -- a list of elements of ambient or a matrix - TODO: + Output: + + A lattice in the ambient space defined by the inner_product_matrix. + Unless specified the basis of the lattice is the standard basis. - - Make sure inner_product_matrix is a matrix EXAMPLES:: @@ -61,7 +63,7 @@ def IntegralLattice(inner_product_matrix, basis=None, already_echelonized=False, [1 0] """ if basis is None: - basis = matrix.identity(QQ, inner_product_matrix.ncols()) + basis = matrix.identity(ZZ, inner_product_matrix.ncols()) if inner_product_matrix != inner_product_matrix.transpose(): raise ValueError("Argument inner_product_matrix must be symmetric\n%s" % inner_product_matrix) @@ -298,16 +300,8 @@ def is_primitive(self, M): INPUT: - - ``M`` -- a module - - TODO: - - - Check that M is the right type - - - make sure there is the same ambient space + - ``M`` -- a submodule of this lattice - - describe the input M in more detail - EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice @@ -334,15 +328,8 @@ def orthogonal_complement(self, M): INPUT: - - ``M`` -- - - TODO: - - - make sure the input is a free module - - - make sure there is the same ambient space - - - describe the input M in more detail + - ``M`` -- a Module in the same ambient space or + a list of elements of the ambient space EXAMPLES:: @@ -357,6 +344,12 @@ def orthogonal_complement(self, M): [ 2 1] [ 1 -2] """ + from sage.modules.free_module import FreeModule_generic + if not isinstance(M,FreeModule_generic): + M = self.span(M) + else if M.ambient_vector_space()!=self.ambient_vector_space(): + raise ValueError("M must have the same ambient vector space as this lattice.") + K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() K.base_extend(QQ) return self.sublattice(self.intersection(K).basis()) @@ -367,13 +360,7 @@ def sublattice(self, basis): INPUT: - - ``basis`` -- - - TODO: - - - Check that basis input is of the right type - - - describe the input in more detail + - ``basis`` -- A list of elements of this lattice. EXAMPLES:: @@ -413,10 +400,6 @@ def overlattice(self, gens): INPUT: - ``gens`` -- a list of elements of this lattice, or a rational matrix - - TODO: - - - make sure input ``gens`` is of the right type EXAMPLES:: From ce4c6fcb288d6a03930983ef2e05c0d91e4c8275 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 21:52:15 +0200 Subject: [PATCH 163/218] Moved docstring from __init__ to class and changed docstring of is_even. --- ...free_quadratic_module_integer_symmetric.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 5963b9d040c..6b05515262d 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -82,7 +82,14 @@ def IntegralLattice(inner_product_matrix, basis=None): class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): r""" This class represents non-degenerate, integral, symmetric free quadratic `\Z`-modules. - + + INPUT: + + - ``ambient`` -- + + - ``basis`` -- + + - ``inner_product_matrix`` -- EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice @@ -97,14 +104,6 @@ class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_b def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): r""" Create the integral lattice spanned by ``basis`` in the ambient space. - - INPUT: - - - ``ambient`` -- - - - ``basis`` -- - - - ``inner_product_matrix`` -- TESTS:: @@ -150,7 +149,7 @@ def _repr_(self): def is_even(self): r""" - Returns true if the diagonal entries of the Gram matrix are even. + Return whether the diagonal entries of the Gram matrix are even. EXAMPLES:: From 74a7393c87ceb7f1d6061bc4e1eb9c6efc88ae2d Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 1 Oct 2017 22:00:20 +0200 Subject: [PATCH 164/218] Fixed a syntax error and added a doctest for orthogonal_complement. --- .../free_quadratic_module_integer_symmetric.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 6b05515262d..781c04c53d1 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -342,11 +342,20 @@ def orthogonal_complement(self, M): Inner product matrix: [ 2 1] [ 1 -2] + + sage: L = IntegralLattice(matrix.identity(2)) + sage: L.orthogonal_complement([vector(ZZ,[1,0])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [0 1] + Inner product matrix: + [1 0] + [0 1] """ from sage.modules.free_module import FreeModule_generic if not isinstance(M,FreeModule_generic): M = self.span(M) - else if M.ambient_vector_space()!=self.ambient_vector_space(): + elif M.ambient_vector_space()!=self.ambient_vector_space(): raise ValueError("M must have the same ambient vector space as this lattice.") K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() From c02ff2a3e0675e084941175ddb21b128d4780c10 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 20:21:01 +0000 Subject: [PATCH 165/218] Fixing category, adding UniqueRepresentation, tidying docstrings --- .../categories/commutative_additive_groups.py | 12 ++ src/sage/groups/abelian_gps/qmodnz.py | 164 +++++++++--------- src/sage/groups/abelian_gps/qmodnz_element.py | 118 +++++++++---- 3 files changed, 180 insertions(+), 114 deletions(-) diff --git a/src/sage/categories/commutative_additive_groups.py b/src/sage/categories/commutative_additive_groups.py index cfeddc64b93..fbf0fc24706 100644 --- a/src/sage/categories/commutative_additive_groups.py +++ b/src/sage/categories/commutative_additive_groups.py @@ -13,6 +13,7 @@ from sage.categories.algebra_functor import AlgebrasCategory from sage.categories.cartesian_product import CartesianProductsCategory from sage.categories.additive_groups import AdditiveGroups +from sage.categories.topological_spaces import TopologicalSpacesCategory class CommutativeAdditiveGroups(CategoryWithAxiom, AbelianCategory): """ @@ -96,3 +97,14 @@ def additive_order(self): class Algebras(AlgebrasCategory): pass + class Topological(TopologicalSpacesCategory): + """ + Category of topological additive abelian groups. + + A topological additive group `G` is a group which has a topology such that + addition and negation are continuous functions. + + REFERENCES: + + - :wikipedia:`Topological_group` + """ diff --git a/src/sage/groups/abelian_gps/qmodnz.py b/src/sage/groups/abelian_gps/qmodnz.py index 6dfad3200ab..d9fda7e2a7d 100644 --- a/src/sage/groups/abelian_gps/qmodnz.py +++ b/src/sage/groups/abelian_gps/qmodnz.py @@ -1,12 +1,44 @@ -from sage.groups.group import AbelianGroup +r""" +This module implements `\Q/n\Z` for `n \in \Q`. + +When `n \in \Z`, you can construct these groups as follows:: + + sage: G = QQ/ZZ; G + Q/Z + sage: QQ/(2*ZZ) + Q/2Z + +You can create random elements:: + + sage: [G.random_element() for _ in range(4)] + [15/16, 0, 1/2, 139/190] + +There is an iterator over the (infinitly many) elements:: + + sage: import itertools + sage: list(itertools.islice(G, 10)) + [0, 1/2, 1/3, 2/3, 1/4, 3/4, 1/5, 2/5, 3/5, 4/5] +""" + +#***************************************************************************** +# Copyright (C) 2017 David Roe +# +# 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/ +#***************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation from sage.rings.all import ZZ, QQ from sage.groups.abelian_gps.qmodnz_element import QmodnZ_Element -from sage.categories.groups import Groups +from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from sage.arith import srange -class QmodnZ(AbelianGroup): +class QmodnZ(Parent, UniqueRepresentation): r""" - The ``QmodnZ`` class represents the abelian group Q/nZ. + The ``QmodnZ`` class represents the abelian group `\Q/n\Z`. INPUT: @@ -23,7 +55,7 @@ class QmodnZ(AbelianGroup): OUTPUT: - The abelian group Q/nZ. + The abelian group `\Q/n\Z`. EXAMPLES:: @@ -41,8 +73,11 @@ class QmodnZ(AbelianGroup): Element = QmodnZ_Element def __init__(self, n=1): r""" + Initialization. + EXAMPLES:: + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(2) sage: G Q/2Z @@ -53,8 +88,8 @@ def __init__(self, n=1): sage: TestSuite(G).run() """ self.n = QQ(n).abs() - category = Groups().Commutative().Topological().Infinite() - AbelianGroup.__init__(self, base=ZZ, category=category) + category = CommutativeAdditiveGroups().Topological().Infinite() + Parent.__init__(self, base=ZZ, category=category) self._populate_coercion_lists_(coerce_list=[QQ]) def _repr_(self): @@ -63,6 +98,7 @@ def _repr_(self): EXAMPLES:: + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(1); G Q/Z @@ -79,105 +115,75 @@ def _repr_(self): else: return "Q/(%s)Z"%(self.n) - def __eq__(self, other): - r""" - Return ``True`` if ``self`` and ``other`` are identical. - - This means they are the same abelian group. - - EXAMPLES:: - - sage: G = QQ/(5*ZZ) - sage: H = QQ/(5*ZZ) - sage: K = QQ/(3*ZZ) - sage: L = QmodnZ(25/5) - sage: G == H #indirect doctest - True - sage: G == K #indirect doctest - False - - TESTS:: - - sage: G == G - True - sage: H == G - True - sage: G == L - True - sage: K == 7 - False - """ - if type(self) == type(other): - return self.n == other.n - return NotImplemented - - def __ne__(self, other): - r""" - Return ``True`` if ``self`` and ``other`` are not identical. - - This means they are different abelian groups. - - EXAMPLES:: - - sage: G = QQ/(5*ZZ) - sage: H = QQ/(5*ZZ) - sage: K = QQ/(3*ZZ) - sage: L = QmodnZ(25/5) - sage: G != H #indirect doctest - False - sage: G != K #indirect doctest - True - """ - - if type(self) == type(other): - return self.n != other.n - return NotImplemented - #TODO: Disallow order comparisons between different Q/nZ's # e.g., sage: QmodnZ(10/3) > QmodnZ(5/3) # returns False. def _element_constructor_(self, x): r""" - Construct an element in Q/nZ. + Construct an element in `\Q/n\Z`. EXAMPLES:: + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(2/3) sage: G(5/6) 1/6 """ return self.element_class(self, QQ(x)) - def random_element(self, *args, **kwds): + def an_element(self): + """ + Return an element, for use in coercion system. + + TESTS:: + + sage: (QQ/ZZ).an_element() + 0 + """ + return self(0) + + def some_elements(self): + """ + Return some elements, for use in testing. + + TESTS:: + + sage: L = (QQ/ZZ).some_elements() + sage: len(L) + 92 + """ + return sorted(list(set([self(x) for x in QQ.some_elements()]))) + + def random_element(self): r""" - Return a random element of Q/nZ. + Return a random element of `\Q/n\Z`. The denominator is selected + using the ``1/n`` distribution on integers, modified to return + a positive value. The numerator is then selected uniformly. EXAMPLES:: sage: G = QQ/(6*ZZ) sage: G.random_element() - 1 + 47/16 sage: G.random_element() - 35/6 + 1 sage: G.random_element() - 1/4 - - Extra positional or keyword arguments are passed through:: - - sage: G = QmodnZ(4/5) - sage: G.random_element(distribution='1/n') - 1/2 - sage: G.random_element(distribution='1/n') 3/5 - sage: G.random_element(distribution='1/n') - 11/20 """ - return self(QQ.random_element(*args, **kwds)) + if self.n == 0: + return self(QQ.random_element()) + d = ZZ.random_element() + if d >= 0: + d = 2*d + 1 + else: + d = -2*d + n = ZZ.random_element((self.n * d).ceil()) + return self(n/d) def __iter__(self): r""" - Creates an iterator that generates the elements of Q/nZ without + Creates an iterator that generates the elements of `\Q/n\Z` without repetition, organized by increasing denominator; for a fixed denominator elements are listed by increasing numerator. @@ -186,7 +192,7 @@ def __iter__(self): The first 19 elements of Q/5Z:: sage: import itertools - sage: lst = [a for a in itertools.islice(QQ/(5*ZZ),19)]; lst + sage: list(itertools.islice(QQ/(5*ZZ),19)) [0, 1, 2, 3, 4, 1/2, 3/2, 5/2, 7/2, 9/2, 1/3, 2/3, 4/3, 5/3, 7/3, 8/3, 10/3, 11/3, 13/3] """ diff --git a/src/sage/groups/abelian_gps/qmodnz_element.py b/src/sage/groups/abelian_gps/qmodnz_element.py index a0bab2ae057..febde8bc32a 100644 --- a/src/sage/groups/abelian_gps/qmodnz_element.py +++ b/src/sage/groups/abelian_gps/qmodnz_element.py @@ -1,3 +1,27 @@ +r""" +Elements of `\Q/n\Z`. + +EXAMPLES:: + + sage: A = QQ / (3*ZZ) + sage: x = A(11/3); x + 2/3 + sage: x*14 + 1/3 + sage: x.additive_order() + 9 + sage: x / 3 + 2/9 +""" + +#***************************************************************************** +# Copyright (C) 2017 David Roe +# +# 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/ +#***************************************************************************** from sage.structure.element import AdditiveGroupElement from sage.rings.integer_ring import ZZ @@ -6,38 +30,35 @@ class QmodnZ_Element(AdditiveGroupElement): r""" - The ``QmodnZ_Element`` class represents an element of the abelian group Q/nZ. + The ``QmodnZ_Element`` class represents an element of the abelian group `\Q/n\Z`. INPUT: - ``q`` -- a rational number. - - ``parent`` -- the parent abelian group Q/nZ + - ``parent`` -- the parent abelian group `\Q/n\Z`. OUTPUT: - The element `q` of abelian group Q/nZ, in standard form. + The element `q` of abelian group `\Q/n\Z`, in standard form. EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QQ/(19*ZZ) - sage: q = G(400/19) - sage: q + sage: G(400/19) 39/19 """ def __init__(self, parent, x, construct=False): r""" - Create an element of Q/nZ. + Create an element of `\Q/n\Z`. EXAMPLES:: sage: G = QQ/(3*ZZ) - sage: g = G.random_element() - sage: g - 3/8 + sage: G.random_element() + 47/16 """ AdditiveGroupElement.__init__(self, parent) @@ -59,9 +80,10 @@ def __init__(self, parent, x, construct=False): def lift(self): r""" - Returns the rational number representation of ``self`` + Return the smallest non-negative rational number reducing to this element. EXAMPLES:: + sage: G = QQ/(5*ZZ) sage: g = G(2/4); g 1/2 @@ -69,7 +91,8 @@ def lift(self): 1/2 TESTS:: - sage: q.parent() == QQ + + sage: q.parent() is QQ True """ @@ -77,15 +100,18 @@ def lift(self): def __neg__(self): r""" - Returns the additive inverse of ``self`` in Q/nZ. + Return the additive inverse of this element in `\Q/n\Z`. EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: -g 2/21 TESTS:: + sage: G = QmodnZ(19/23) sage: g = G(15/23) sage: -g @@ -102,18 +128,21 @@ def __neg__(self): def _add_(self, other): r""" - Returns the sum of ``self`` and ``other`` in Q/nZ + Return the sum of two elements in `\Q/n\Z`. EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(9/10) sage: g = G(5) sage: h = G(1/2) sage: g + h 1/10 - sage: g + h == G(1/10) #indirect doctest + sage: g + h == G(1/10) True TESTS:: + sage: h + g == G(1/10) True """ @@ -126,9 +155,11 @@ def _add_(self, other): def _sub_(self, other): r""" - Returns the difference of ``self`` and ``other`` in Q/nZ + Returns the difference of two elements in `\Q/n\Z`. EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(9/10) sage: g = G(4) sage: h = G(1/2) @@ -136,9 +167,9 @@ def _sub_(self, other): 4/5 sage: h - g 1/10 - sage: g - h == G(4/5) #indirect doctest + sage: g - h == G(4/5) True - sage: h - g == G(1/10) #indirect doctest + sage: h - g == G(1/10) True """ @@ -150,9 +181,11 @@ def _sub_(self, other): def _rmul_(self, c): r""" - Returns the (right) scalar product of ``self`` by ``c`` in Q/nZ. + Returns the (right) scalar product of this element by ``c`` in `\Q/n\Z`. EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: g*6 @@ -163,15 +196,18 @@ def _rmul_(self, c): def _lmul_(self, c): r""" - Returns the (left) scalar product of ``self`` by ``c`` in Q/nZ. + Returns the (left) scalar product of this element by ``c`` in `\Q/n\Z`. EXAMPLES:: + + sage: from sage.groups.abelian_gps.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: 6*g 1/7 TESTS:: + sage: 6*g == g*6 True sage: 6*g == 5*g @@ -180,6 +216,23 @@ def _lmul_(self, c): return self._rmul_(c) def __div__(self, other): + r""" + Division. + + .. WARNING:: + + Division of `x` by `m` does not yield a well defined + result, since there are `m` elements `y` of `\Q/n\Z` + with the property that `x = my`. We return the one + with the smallest non-negative lift. + + EXAMPLES:: + + sage: G = QQ/(4*ZZ) + sage: x = G(3/8) + sage: x / 4 + 3/32 + """ #TODO: This needs to be implemented. QZ = self.parent() other = ZZ(other) @@ -187,23 +240,23 @@ def __div__(self, other): def _repr_(self): r""" - Display the element + Display the element. EXAMPLES:: - sage: G = QmodnZ(8) + sage: G = QQ/(8*ZZ) sage: g = G(25/7); g; 25/7 - """ - return repr(self._x) def __hash__(self): r""" + Hashing. + TESTS:: - sage: G = QmodnZ(4) + sage: G = QQ/(4*ZZ) sage: g = G(4/5) sage: hash(g) -7046029254386353128 @@ -212,16 +265,11 @@ def __hash__(self): sage: hash(G(1)) 1 """ - return hash(self._x) def _richcmp_(self, right, op): r""" - Compare ``self`` with ``right``. - - OUTPUT: - - boolean + Compare two elements. EXAMPLES:: @@ -240,17 +288,17 @@ def _richcmp_(self, right, op): def additive_order(self): r""" - Returns the order of ``self`` in the abelian group Q/nZ. + Returns the order of this element in the abelian group `\Q/n\Z`. EXAMPLES:: - sage: G = QmodnZ(12) + + sage: G = QQ/(12*ZZ) sage: g = G(5/3) sage: g.additive_order() 36 - sage: (-g).additive_order() # indirect doctest + sage: (-g).additive_order() 36 """ - # a/b * k = n/m * r QZ = self.parent() if QZ.n == 0: From b0ce12ab80b801713799ec9a0f78d0ef8b9ec278 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 20:22:54 +0000 Subject: [PATCH 166/218] Moving qmodz to additive_abelian --- src/sage/groups/{abelian_gps => additive_abelian}/qmodnz.py | 0 .../groups/{abelian_gps => additive_abelian}/qmodnz_element.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/sage/groups/{abelian_gps => additive_abelian}/qmodnz.py (100%) rename src/sage/groups/{abelian_gps => additive_abelian}/qmodnz_element.py (100%) diff --git a/src/sage/groups/abelian_gps/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py similarity index 100% rename from src/sage/groups/abelian_gps/qmodnz.py rename to src/sage/groups/additive_abelian/qmodnz.py diff --git a/src/sage/groups/abelian_gps/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py similarity index 100% rename from src/sage/groups/abelian_gps/qmodnz_element.py rename to src/sage/groups/additive_abelian/qmodnz_element.py From dc34258b04d4a3060e67ccee9b50ef4fbd919287 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 20:27:35 +0000 Subject: [PATCH 167/218] Fallout from the move to additive abelian --- src/sage/groups/additive_abelian/qmodnz.py | 10 +++++----- src/sage/groups/additive_abelian/qmodnz_element.py | 10 +++++----- src/sage/rings/rational_field.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index d9fda7e2a7d..839cdc9671a 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -32,9 +32,9 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.rings.all import ZZ, QQ -from sage.groups.abelian_gps.qmodnz_element import QmodnZ_Element from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from sage.arith import srange +from .qmodnz_element import QmodnZ_Element class QmodnZ(Parent, UniqueRepresentation): r""" @@ -59,7 +59,7 @@ class QmodnZ(Parent, UniqueRepresentation): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: QQ/(19*ZZ) Q/19Z @@ -77,7 +77,7 @@ def __init__(self, n=1): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(2) sage: G Q/2Z @@ -98,7 +98,7 @@ def _repr_(self): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(1); G Q/Z @@ -125,7 +125,7 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(2/3) sage: G(5/6) 1/6 diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index febde8bc32a..f06e5abdecf 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -104,7 +104,7 @@ def __neg__(self): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: -g @@ -132,7 +132,7 @@ def _add_(self, other): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(9/10) sage: g = G(5) sage: h = G(1/2) @@ -159,7 +159,7 @@ def _sub_(self, other): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(9/10) sage: g = G(4) sage: h = G(1/2) @@ -185,7 +185,7 @@ def _rmul_(self, c): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: g*6 @@ -200,7 +200,7 @@ def _lmul_(self, c): EXAMPLES:: - sage: from sage.groups.abelian_gps.qmodnz import QmodnZ + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ sage: G = QmodnZ(5/7) sage: g = G(13/21) sage: 6*g diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 42b2f7f3592..e03d12391d0 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -439,7 +439,7 @@ def __truediv__(self, I): TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. """ from sage.rings.ideal import Ideal_generic - from sage.groups.abelian_gps.qmodnz import QmodnZ + from sage.groups.additive_abelian.qmodnz import QmodnZ if I is ZZ: return QmodnZ(1) elif isinstance(I, Ideal_generic) and I.base_ring() is ZZ: From 4ad5dbdc71a29848310b1981d775945e7f1ab49f Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 20:33:45 +0000 Subject: [PATCH 168/218] Remove some blank lines --- src/sage/groups/additive_abelian/qmodnz_element.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index f06e5abdecf..18eb77ac0cc 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -47,9 +47,7 @@ class QmodnZ_Element(AdditiveGroupElement): sage: G = QQ/(19*ZZ) sage: G(400/19) 39/19 - """ - def __init__(self, parent, x, construct=False): r""" Create an element of `\Q/n\Z`. @@ -95,7 +93,6 @@ def lift(self): sage: q.parent() is QQ True """ - return self._x def __neg__(self): @@ -119,7 +116,6 @@ def __neg__(self): sage: g + -g == G(0) True """ - if self._x == 0: return self else: @@ -146,7 +142,6 @@ def _add_(self, other): sage: h + g == G(1/10) True """ - QZ = self.parent() ans = self._x + other._x if ans >= QZ.n: @@ -172,7 +167,6 @@ def _sub_(self, other): sage: h - g == G(1/10) True """ - QZ = self.parent() ans = self._x - other._x if ans < 0: From c96014b267046a9b36d7f6d5612b5776485c6076 Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 20:45:53 +0000 Subject: [PATCH 169/218] Editing docstrings, a few small code fixes --- ...free_quadratic_module_integer_symmetric.py | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 781c04c53d1..af813218797 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -29,16 +29,15 @@ def IntegralLattice(inner_product_matrix, basis=None): Here, lattices have an ambient quadratic space `\Q^n` and a distinguished basis. INPUT: - + - ``inner_product_matrix`` -- a symmetric matrix over the rationals - ``basis`` -- a list of elements of ambient or a matrix - + Output: - + A lattice in the ambient space defined by the inner_product_matrix. - Unless specified the basis of the lattice is the standard basis. - + Unless specified, the basis of the lattice is the standard basis. EXAMPLES:: @@ -82,14 +81,15 @@ def IntegralLattice(inner_product_matrix, basis=None): class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): r""" This class represents non-degenerate, integral, symmetric free quadratic `\Z`-modules. - + INPUT: - - - ``ambient`` -- - - - ``basis`` -- - - - ``inner_product_matrix`` -- + + - ``ambient`` -- an ambient free quadratic module + + - ``basis`` -- a list of elements of ambient or a matrix + + - ``inner_product_matrix`` -- a symmetric matrix over the rationals + EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice @@ -111,10 +111,10 @@ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_ech sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) sage: TestSuite(L).run() """ - FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False) + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=check, already_echelonized=already_echelonized) if self.determinant() == 0: raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") - if self.gram_matrix().base_ring() != ZZ: + if self.gram_matrix().base_ring() is not ZZ: if self.gram_matrix().denominator() != 1: raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") @@ -161,10 +161,7 @@ def is_even(self): sage: L.is_even() True """ - for d in self.gram_matrix().diagonal(): - if d % 2 != 0: - return False - return True + return all(d % 2 == 0 for d in self.gram_matrix().diagonal()) def dual_lattice(self): r""" @@ -200,7 +197,12 @@ def discriminant_group(self, s=0): INPUT: - - ``s`` -- an integer + - ``s`` -- an integer (default: 0) + + OUTPUT: + + The `s` primary part of the discriminant group. + If `s=0`, returns the whole discriminant group. EXAMPLES:: @@ -244,7 +246,7 @@ def signature(self): def signature_pair(self): r""" - Returns the signature tuple `(n_+,n_-)` of this lattice. + Return the signature tuple `(n_+,n_-)` of this lattice. Here `n_+` (resp. `n_-`) is the number of positive (resp. negative) eigenvalues of the Gram matrix. @@ -262,9 +264,9 @@ def signature_pair(self): def direct_sum(self, M): r""" Return the direct sum of this lattice with ``M``. - - INPUT: - + + INPUT: + - ``M`` -- a module over `\Z` EXAMPLES:: @@ -294,13 +296,13 @@ def is_primitive(self, M): r""" Return whether ``M`` is a primitive submodule of this lattice. - A `\Z`-submodule ``M`` of a `\Z`-module `L` is called primitive if + A `\Z`-submodule ``M`` of a `\Z`-module ``L`` is called primitive if the quotient ``L/M`` is torsion free. - + INPUT: - + - ``M`` -- a submodule of this lattice - + EXAMPLES:: sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice @@ -324,10 +326,10 @@ def is_primitive(self, M): def orthogonal_complement(self, M): r""" Return the orthogonal complement of ``M`` in this lattice. - + INPUT: - - - ``M`` -- a Module in the same ambient space or + + - ``M`` -- a module in the same ambient space or a list of elements of the ambient space EXAMPLES:: @@ -342,7 +344,7 @@ def orthogonal_complement(self, M): Inner product matrix: [ 2 1] [ 1 -2] - + sage: L = IntegralLattice(matrix.identity(2)) sage: L.orthogonal_complement([vector(ZZ,[1,0])]) Lattice of degree 2 and rank 1 over Integer Ring @@ -357,7 +359,7 @@ def orthogonal_complement(self, M): M = self.span(M) elif M.ambient_vector_space()!=self.ambient_vector_space(): raise ValueError("M must have the same ambient vector space as this lattice.") - + K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() K.base_extend(QQ) return self.sublattice(self.intersection(K).basis()) @@ -386,12 +388,11 @@ def sublattice(self, basis): Traceback (most recent call last): ... ValueError: Lattices must be integral. Use FreeQuadraticModule instead - + sage: S.sublattice([vector([1,-1])]) Traceback (most recent call last): ... ValueError: Argument basis (= [(1, -1)]) does not span a submodule of this lattice - """ M = FreeQuadraticModule_integer_symmetric( ambient=self.ambient_module(), basis=basis, From 1598fd0724e68568bd58080e568e4713f7f292ee Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Sun, 1 Oct 2017 22:42:08 +0000 Subject: [PATCH 170/218] Reviewer patch: some minor edits --- src/sage/groups/additive_abelian/qmodnz.py | 5 ++--- src/sage/groups/additive_abelian/qmodnz_element.py | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index 839cdc9671a..c60c7728963 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -13,7 +13,7 @@ sage: [G.random_element() for _ in range(4)] [15/16, 0, 1/2, 139/190] -There is an iterator over the (infinitly many) elements:: +There is an iterator over the (infinitely many) elements:: sage: import itertools sage: list(itertools.islice(G, 10)) @@ -33,7 +33,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.rings.all import ZZ, QQ from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups -from sage.arith import srange from .qmodnz_element import QmodnZ_Element class QmodnZ(Parent, UniqueRepresentation): @@ -189,7 +188,7 @@ def __iter__(self): EXAMPLES: - The first 19 elements of Q/5Z:: + The first 19 elements of `\Q/5\Z`:: sage: import itertools sage: list(itertools.islice(QQ/(5*ZZ),19)) diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index 18eb77ac0cc..06967dda12f 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -227,7 +227,6 @@ def __div__(self, other): sage: x / 4 3/32 """ - #TODO: This needs to be implemented. QZ = self.parent() other = ZZ(other) return QZ.element_class(QZ, self._x / other, True) @@ -239,7 +238,7 @@ def _repr_(self): EXAMPLES:: sage: G = QQ/(8*ZZ) - sage: g = G(25/7); g; + sage: g = G(25/7); g 25/7 """ return repr(self._x) From f6f20563bbd2f8b60a6897edcc24c5b2e13a7ea9 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Sun, 1 Oct 2017 22:55:26 +0000 Subject: [PATCH 171/218] Fix doctests for QQ --- src/sage/rings/rational_field.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index e03d12391d0..7f3caf17929 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -158,8 +158,9 @@ def __init__(self): sage: Q.is_field() True sage: Q.category() - Join of Category of number fields + Join of Category of number fields and Category of quotient fields + and Category of topological commutative additive groups and Category of metric spaces sage: Q.zeta() -1 @@ -428,15 +429,12 @@ def __iter__(self): def __truediv__(self, I): """ - Dividing one ring by another is not supported because there is no good - way to specify generator names. + Form the quotient by an integral ideal. EXAMPLES:: sage: QQ / ZZ - Traceback (most recent call last): - ... - TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. + Q/Z """ from sage.rings.ideal import Ideal_generic from sage.groups.additive_abelian.qmodnz import QmodnZ From c53f548b65287f5be823cb50545ba7add883c63c Mon Sep 17 00:00:00 2001 From: David Roe Date: Sun, 1 Oct 2017 23:24:08 +0000 Subject: [PATCH 172/218] Conversion and coercion maps --- src/sage/groups/additive_abelian/qmodnz.py | 30 ++++++++++++ .../groups/additive_abelian/qmodnz_element.py | 46 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index 839cdc9671a..c5f8fc3355a 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -115,6 +115,36 @@ def _repr_(self): else: return "Q/(%s)Z"%(self.n) + def _coerce_map_from_(self, S): + r""" + Coercion from a parent ``S``. + + There is a coercion from ``S`` if ``S`` has a coerce map to `\Q` + or if `S = \Q/m\Z` for `m` a multiple of `n`. + + TESTS:: + + sage: G2 = QQ/(2*ZZ) + sage: G3 = QQ/(3*ZZ) + sage: G4 = QQ/(4*ZZ) + sage: G2.has_coerce_map_from(QQ) + True + sage: G2.has_coerce_map_from(ZZ) + True + sage: G2.has_coerce_map_from(ZZ['x']) + False + sage: G2.has_coerce_map_from(G3) + False + sage: G2.has_coerce_map_from(G4) + True + sage: G4.has_coerce_map_from(G2) + False + """ + if QQ.has_coerce_map_from(S): + return True + if isinstance(S, QmodnZ) and (S.n / self.n in ZZ): + return True + #TODO: Disallow order comparisons between different Q/nZ's # e.g., sage: QmodnZ(10/3) > QmodnZ(5/3) # returns False. diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index 18eb77ac0cc..8be92c98f0a 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -95,6 +95,52 @@ def lift(self): """ return self._x + def _rational_(self): + r""" + Lift to `\Q`. + + TESTS:: + + sage: QQ((QQ/ZZ)(4/3)) # indirect doctest + 1/3 + """ + return self._x + + def _integer_(self, Z): + r""" + Lift to `\Z`. + + This is the smallest non-negative integer reducing to this element, + or a ``ValueError`` if none exists. + + TESTS:: + + sage: G = QQ/(2*ZZ) + sage: ZZ(G(3)) + 1 + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(8/3) + sage: ZZ(G(1/3)) + 3 + + sage: all(ZZ(G(i)) == i for i in range(8)) + True + + sage: G = QmodnZ(101/34) + sage: all(ZZ(G(i)) == i for i in range(101)) + True + """ + QZ = self.parent() + b = self._x.denominator() + n = QZ.n.numerator() + m = QZ.n.denominator() + if not b.divides(m): + raise ValueError("No integral lift") + a = self._x.numerator() * (m // b) + # a/m + q*(n/m) = (a + qn)/m = km/m so a + qn = km, + # k = a*m^(-1) mod n. + return (a * m.inverse_mod(n)) % n + def __neg__(self): r""" Return the additive inverse of this element in `\Q/n\Z`. From 3dea3c3acdb99f8ecf06ea066f6a10521a8952b8 Mon Sep 17 00:00:00 2001 From: David Roe Date: Mon, 2 Oct 2017 02:32:57 +0000 Subject: [PATCH 173/218] 32-bit doctests, remove toplogical axiom from additive abelian groups, fix doctest in sage/rings/ring.pyx --- src/sage/categories/commutative_additive_groups.py | 13 ------------- src/sage/groups/additive_abelian/qmodnz.py | 2 +- src/sage/groups/additive_abelian/qmodnz_element.py | 6 ++++-- src/sage/rings/rational_field.py | 3 +-- src/sage/rings/ring.pyx | 2 +- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/sage/categories/commutative_additive_groups.py b/src/sage/categories/commutative_additive_groups.py index fbf0fc24706..c1383022833 100644 --- a/src/sage/categories/commutative_additive_groups.py +++ b/src/sage/categories/commutative_additive_groups.py @@ -13,7 +13,6 @@ from sage.categories.algebra_functor import AlgebrasCategory from sage.categories.cartesian_product import CartesianProductsCategory from sage.categories.additive_groups import AdditiveGroups -from sage.categories.topological_spaces import TopologicalSpacesCategory class CommutativeAdditiveGroups(CategoryWithAxiom, AbelianCategory): """ @@ -96,15 +95,3 @@ def additive_order(self): class Algebras(AlgebrasCategory): pass - - class Topological(TopologicalSpacesCategory): - """ - Category of topological additive abelian groups. - - A topological additive group `G` is a group which has a topology such that - addition and negation are continuous functions. - - REFERENCES: - - - :wikipedia:`Topological_group` - """ diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index e55e754c9bc..43610c29a3c 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -87,7 +87,7 @@ def __init__(self, n=1): sage: TestSuite(G).run() """ self.n = QQ(n).abs() - category = CommutativeAdditiveGroups().Topological().Infinite() + category = CommutativeAdditiveGroups().Infinite() Parent.__init__(self, base=ZZ, category=category) self._populate_coercion_lists_(coerce_list=[QQ]) diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index ea5a814b208..c674fb66f75 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -298,9 +298,11 @@ def __hash__(self): sage: G = QQ/(4*ZZ) sage: g = G(4/5) sage: hash(g) - -7046029254386353128 + 2135587864 # 32-bit + -7046029254386353128 # 64-bit sage: hash(G(3/4)) - 3938850096065010962 + 527949074 # 32-bit + 3938850096065010962 # 64-bit sage: hash(G(1)) 1 """ diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 7f3caf17929..dca06b9d2d1 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -158,9 +158,8 @@ def __init__(self): sage: Q.is_field() True sage: Q.category() - Join of Category of number fields + Join of Category of number fields and Category of quotient fields - and Category of topological commutative additive groups and Category of metric spaces sage: Q.zeta() -1 diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index f428c0a5b8f..a5b6c593b39 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -645,7 +645,7 @@ cdef class Ring(ParentWithGens): EXAMPLES:: - sage: QQ / ZZ + sage: QQ['x'] / ZZ Traceback (most recent call last): ... TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. From 0a0fbe9a30f6fe4c0f1414f5710f1d1900572b5c Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 2 Oct 2017 06:00:46 +0200 Subject: [PATCH 174/218] Adapted _eq_ for sage.categories.Homset and modifided code for pushout where != was used --- src/sage/categories/homset.py | 6 +++--- src/sage/categories/pushout.py | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 3013ab20587..7fa73428744 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -236,14 +236,14 @@ def Hom(X, Y, category=None, check=True): sage: U1 = FreeModule(ZZ,2) sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]])) sage: U1 == U2, U1 is U2 - (True, False) + (False, False) sage: V = ZZ^3 sage: H1 = Hom(U1, V); H2 = Hom(U2, V) sage: H1 == H2, H1 is H2 - (True, False) + (False, False) sage: H1 = Hom(V, U1); H2 = Hom(V, U2) sage: H1 == H2, H1 is H2 - (True, False) + (False, False) Since :trac:`11900`, the meet of the categories of the given arguments is used to determine the default category of the homset. This can also be a diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 8d2476ca03f..2e27f9fe2d7 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1887,7 +1887,7 @@ def _apply_functor_to_morphism(self, f): def __eq__(self, other): """ - Only the rank of the to-be-created modules is compared, *not* the inner product matrix. + The rank and the inner product matrix are compared. TESTS:: @@ -1895,16 +1895,14 @@ def __eq__(self, other): sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 == F2 - True + False sage: F1(QQ) == F2(QQ) - True - sage: F1(QQ).inner_product_matrix() == F2(QQ).inner_product_matrix() False sage: F1 == loads(dumps(F1)) True """ if isinstance(other, VectorFunctor): - return self.n == other.n + return (self.n == other.n and self.inner_product_matrix==other.inner_product_matrix) return False def __ne__(self, other): @@ -1917,9 +1915,9 @@ def __ne__(self, other): sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 != F2 - False + True sage: F1(QQ) != F2(QQ) - False + True sage: F1 != loads(dumps(F1)) False """ @@ -1927,7 +1925,7 @@ def __ne__(self, other): def merge(self, other): """ - Two constructors of free modules merge, if the module ranks coincide. If both + Two constructors of free modules merge, if the module ranks and the inner products coincide. If both have explicitly given inner product matrices, they must coincide as well. EXAMPLES: @@ -1976,7 +1974,7 @@ def merge(self, other): [6 7 8]' """ - if self != other: + if not isinstance(other, VectorFunctor): return None if self.inner_product_matrix is None: return VectorFunctor(self.n, self.is_sparse and other.is_sparse, other.inner_product_matrix) From 77f541333d3cbd2bb72c58ac90d59a3e45e47cfb Mon Sep 17 00:00:00 2001 From: Koen van Woerden Date: Mon, 2 Oct 2017 11:19:50 +0200 Subject: [PATCH 175/218] Modify docstring. Replace "gotten" in docstring by "obtained", and change reference to ``f`` to a reference to ``self``. --- src/sage/rings/laurent_series_ring_element.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 710454f5f0d..a667612e42c 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -693,12 +693,12 @@ cdef class LaurentSeries(AlgebraElement): def O(self, prec): r""" - Return the Laurent series of precision at most ``prec`` got by adding - `O(q^\text{prec})` to `f`, where `q` is the variable. + Return the Laurent series of precision at most ``prec`` obtained by + adding `O(q^\text{prec})`, where `q` is the variable. - The precision of `f` and the integer ``prec`` can be arbitrary. The + The precision of ``self`` and the integer ``prec`` can be arbitrary. The resulting Laurent series will have precision equal to the minimum of - the precision of `f` and ``prec``. The term `O(q^\text{prec})` is the + the precision of ``self`` and ``prec``. The term `O(q^\text{prec})` is the zero series with precision ``prec``. EXAMPLES:: From 778b876a2895a80c1622c11cb28441211b907ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 2 Oct 2017 14:13:50 +0200 Subject: [PATCH 176/218] removing TAB again --- src/doc/en/reference/references/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 4c45894ee31..daf90b3a9d3 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1247,7 +1247,7 @@ REFERENCES: groups*, Ann. Math. (2) 67 (1958), 282-312. .. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*, - Princeton University Press, Princeton NJ, 1991. + Princeton University Press, Princeton NJ, 1991. .. [Kaw2009] Kawahira, Tomoki. *An algorithm to draw external rays of the Mandelbrot set*, Nagoya University, 23 Apr. 2009. From d1d443153ad6229577b2ce2cc61ba3986ff6250e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 3 Oct 2017 19:51:51 +0200 Subject: [PATCH 177/218] 23932: clean LaurentPolynomialRing constructor --- .../rings/polynomial/laurent_polynomial.pyx | 5 +- .../polynomial/laurent_polynomial_ring.py | 228 ++++-------------- 2 files changed, 47 insertions(+), 186 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index d7085f3a19a..bde2707d436 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2953,7 +2953,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): INPUT: - - ``R`` - (default: ``None``) PolynomialRing + - ``R`` - (default: ``None``) a univariate Laurent polynomial ring If this polynomial is not in at most one variable, then a ``ValueError`` exception is raised. The new polynomial is over @@ -2992,13 +2992,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): elif len(v) == 1: x = v[0] i = self._parent.gens().index(x) + x = str(x) else: x = 'x' i = 0 #construct ring if none if R is None: - R = LaurentPolynomialRing(self.base_ring(),x) + R = LaurentPolynomialRing(self.base_ring(), x) return R(dict((m[i],c) for m,c in self.dict().items())) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 3b234e82321..b21135219e4 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -50,8 +50,7 @@ from sage.rings.ring import is_Ring from sage.rings.infinity import infinity from sage.rings.integer import Integer -from sage.rings.polynomial.polynomial_ring_constructor import _single_variate as _single_variate_poly -from sage.rings.polynomial.polynomial_ring_constructor import _multi_variate as _multi_variate_poly +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.latex import latex from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair, LaurentPolynomial_univariate from sage.rings.ring import CommutativeRing @@ -74,7 +73,8 @@ def is_LaurentPolynomialRing(R): """ return isinstance(R, LaurentPolynomialRing_generic) -def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order='degrevlex', names = None, name=None): +_cache = {} +def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial ring with given properties and variable name or names. @@ -155,7 +155,7 @@ def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order sage: LaurentPolynomialRing(QQ) Traceback (most recent call last): ... - TypeError: You must specify the names of the variables. + TypeError: you must specify the names of the variables sage: R. = LaurentPolynomialRing(QQ, sparse=True); R Univariate Laurent Polynomial Ring in abc over Rational Field @@ -227,166 +227,21 @@ def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order sage: (w0 + 2*w8 + w13)^2 w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ - if is_Element(arg1) and not isinstance(arg1, integer_types + (Integer,)): - arg1 = repr(arg1) - if is_Element(arg2) and not isinstance(arg2, integer_types + (Integer,)): - arg2 = repr(arg2) - - if isinstance(arg1, integer_types + (Integer,)): - arg1, arg2 = arg2, arg1 - - if not names is None: - arg1 = names - elif not name is None: - arg1 = name - - if not is_Ring(base_ring): - raise TypeError('base_ring must be a ring') - - if arg1 is None: - raise TypeError("You must specify the names of the variables.") - - R = None - if isinstance(arg1, (list, tuple)): - arg1 = [str(x) for x in arg1] - if isinstance(arg2, (list, tuple)): - arg2 = [str(x) for x in arg2] - if isinstance(arg2, integer_types + (Integer,)): - # 3. LaurentPolynomialRing(base_ring, names, n, order='degrevlex'): - if not isinstance(arg1, (list, tuple, str)): - raise TypeError("You *must* specify the names of the variables.") - n = int(arg2) - names = arg1 - R = _multi_variate(base_ring, names, n, sparse, order) - - elif isinstance(arg1, str) or (isinstance(arg1, (list,tuple)) and len(arg1) == 1) and isinstance(arg1[0], str): - if isinstance(arg1, (list,tuple)): - arg1 = arg1[0] - if not ',' in arg1: - # 1. LaurentPolynomialRing(base_ring, name, sparse=False): - if not arg2 is None: - raise TypeError("if second arguments is a string with no commas, then there must be no other non-optional arguments") - name = arg1 - R = _single_variate(base_ring, name, sparse) - else: - # 2-4. LaurentPolynomialRing(base_ring, names, order='degrevlex'): - if not arg2 is None: - raise TypeError("invalid input to LaurentPolynomialRing function; please see the docstring for that function") - names = arg1.split(',') - n = len(names) - R = _multi_variate(base_ring, names, n, sparse, order) - elif isinstance(arg1, (list, tuple)): - # LaurentPolynomialRing(base_ring, names (list or tuple), order='degrevlex'): - names = arg1 - n = len(names) - R = _multi_variate(base_ring, names, n, sparse, order) - - if arg1 is None and arg2 is None: - raise TypeError("you *must* specify the indeterminates (as not None).") - if R is None: - raise TypeError("invalid input (%s, %s, %s) to PolynomialRing function; please see the docstring for that function"%(base_ring, arg1, arg2)) - - return R - -_cache = {} -def _get_from_cache(key): - """ - EXAMPLES:: - - sage: from sage.rings.polynomial.laurent_polynomial_ring import _get_from_cache - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: L2 = _get_from_cache( (QQ,('x0','x1'),2,False,TermOrder('degrevlex')) ); L2 - Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - sage: L is L2 - True - """ - try: - if key in _cache: - return _cache[key] # put () here to re-enable weakrefs - except TypeError as msg: - raise TypeError('key = %s\n%s'%(key,msg)) - return None + from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing -def _save_in_cache(key, R): - """ - EXAMPLES:: + R = PolynomialRing(base_ring, *args, **kwds) + if R in _cache: + return _cache[R] # put () here to re-enable weakrefs - sage: from sage.rings.polynomial.laurent_polynomial_ring import _save_in_cache, _get_from_cache - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: _save_in_cache('testkey', L) - sage: _get_from_cache('testkey') - Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - sage: _ is L - True - """ - try: - # We disable weakrefs since they cause segfault at the end of doctesting. - #weakref.ref(R) - _cache[key] = R - except TypeError as msg: - raise TypeError('key = %s\n%s'%(key,msg)) - -def _single_variate(base_ring, names, sparse): - """ - EXAMPLES:: - - sage: from sage.rings.polynomial.laurent_polynomial_ring import _single_variate - sage: _single_variate(QQ, ('x',), False) - Univariate Laurent Polynomial Ring in x over Rational Field - """ - names = normalize_names(1, names) - key = (base_ring, names, sparse) - P = _get_from_cache(key) - if P is not None: - return P - prepend_string = "qk" - while True: - if prepend_string in names: - prepend_string += 'k' - else: - break - R = _single_variate_poly(base_ring, names, sparse, None) - P = LaurentPolynomialRing_univariate(R, names) - _save_in_cache(key, P) - return P - -def _multi_variate(base_ring, names, n, sparse, order): - """ - EXAMPLES:: + if is_PolynomialRing(R): + # univariate case + P = LaurentPolynomialRing_univariate(R) + else: + assert is_MPolynomialRing(R) + P = LaurentPolynomialRing_mpair(R) - sage: from sage.rings.polynomial.laurent_polynomial_ring import _multi_variate - sage: _multi_variate(QQ, ('x','y'), 2, False, 'degrevlex') - Multivariate Laurent Polynomial Ring in x, y over Rational Field - """ - # We need to come up with a name for the inverse that is easy to search - # for in a string *and* doesn't overlap with the name that we already have. - # For now, I'm going to use a name mangling with checking method. - names = normalize_names(n, names) - - from .term_order import TermOrder - order = TermOrder(order, n) - - if isinstance(names, list): - names = tuple(names) - elif isinstance(names, str): - if ',' in names: - names = tuple(names.split(',')) - - key = (base_ring, names, n, sparse, order) - P = _get_from_cache(key) - if P is not None: - return P - prepend_string = "qk" - while True: - for a in names: - if prepend_string in a: - prepend_string += 'k' - break - else: - break - R = _multi_variate_poly(base_ring, names, sparse, order) - P = LaurentPolynomialRing_mpair(R, prepend_string, names) - _save_in_cache(key, P) + _cache[R] = P return P def _split_dict_(D, indices, group_by=None): @@ -545,7 +400,7 @@ class LaurentPolynomialRing_generic(CommutativeRing, ParentWithGens): sage: TestSuite(R).run() """ - def __init__(self, R, prepend_string, names): + def __init__(self, R): """ EXAMPLES:: @@ -555,26 +410,11 @@ def __init__(self, R, prepend_string, names): """ self._n = R.ngens() self._R = R - self._prepend_string = prepend_string + names = R.variable_names() CommutativeRing.__init__(self, R.base_ring(), names=names) self._populate_coercion_lists_(element_constructor=self._element_constructor_, init_no_parent=True) - - def __repr__(self): - """ - TESTS:: - - sage: LaurentPolynomialRing(QQ,2,'x').__repr__() - 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' - sage: LaurentPolynomialRing(QQ,1,'x').__repr__() - 'Univariate Laurent Polynomial Ring in x over Rational Field' - """ - if self._n == 1: - return "Univariate Laurent Polynomial Ring in %s over %s"%(self._R.variable_name(), self._R.base_ring()) - else: - return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) - def ngens(self): """ Returns the number of generators of self. @@ -1001,7 +841,7 @@ def fraction_field(self): return self.polynomial_ring().fraction_field() class LaurentPolynomialRing_univariate(LaurentPolynomialRing_generic): - def __init__(self, R, names): + def __init__(self, R): """ EXAMPLES:: @@ -1015,7 +855,16 @@ def __init__(self, R, names): raise ValueError("must be 1 generator") if not R.base_ring().is_integral_domain(): raise ValueError("base ring must be an integral domain") - LaurentPolynomialRing_generic.__init__(self, R, '', names) + LaurentPolynomialRing_generic.__init__(self, R) + + def _repr_(self): + """ + TESTS:: + + sage: LaurentPolynomialRing(QQ,'x') # indirect doctest + Univariate Laurent Polynomial Ring in x over Rational Field + """ + return "Univariate Laurent Polynomial Ring in %s over %s"%(self._R.variable_name(), self._R.base_ring()) def _element_constructor_(self, x): """ @@ -1103,10 +952,10 @@ def __reduce__(self): sage: loads(dumps(L)) == L True """ - return LaurentPolynomialRing_univariate, (self._R, self._names) + return LaurentPolynomialRing_univariate, (self._R,) class LaurentPolynomialRing_mpair(LaurentPolynomialRing_generic): - def __init__(self, R, prepend_string, names): + def __init__(self, R): """ EXAMPLES:: @@ -1121,7 +970,18 @@ def __init__(self, R, prepend_string, names): raise ValueError("n must be positive") if not R.base_ring().is_integral_domain(): raise ValueError("base ring must be an integral domain") - LaurentPolynomialRing_generic.__init__(self, R, prepend_string, names) + LaurentPolynomialRing_generic.__init__(self, R) + + def _repr_(self): + """ + TESTS:: + + sage: LaurentPolynomialRing(QQ,2,'x').__repr__() + 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' + sage: LaurentPolynomialRing(QQ,1,'x').__repr__() + 'Multivariate Laurent Polynomial Ring in x over Rational Field' + """ + return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) def monomial(self, *args): r""" @@ -1292,6 +1152,6 @@ def __reduce__(self): sage: loads(dumps(L)) == L True """ - return LaurentPolynomialRing_mpair, (self._R, self._prepend_string, self._names) + return LaurentPolynomialRing_mpair, (self._R,) From d48ba7f50349da4b296ddfd325daa6407bf9dbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Oct 2017 21:33:04 +0200 Subject: [PATCH 178/218] richcmp in function field ideal --- src/sage/rings/function_field/function_field_ideal.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/function_field/function_field_ideal.py b/src/sage/rings/function_field/function_field_ideal.py index eb477ac222b..f24a25986b5 100644 --- a/src/sage/rings/function_field/function_field_ideal.py +++ b/src/sage/rings/function_field/function_field_ideal.py @@ -50,6 +50,8 @@ #***************************************************************************** from sage.rings.ideal import Ideal_generic +from sage.structure.richcmp import richcmp + class FunctionFieldIdeal(Ideal_generic): """ @@ -203,7 +205,7 @@ def intersection(self, other): raise ValueError("rings must be the same") return FunctionFieldIdeal_module(self.ring(), self.module().intersection(other.module())) - def __cmp__(self, other): + def __richcmp__(self, other, op): """ Compare self and ``other``. @@ -226,7 +228,7 @@ def __cmp__(self, other): other = self.ring().ideal(other) if self.ring() != other.ring(): raise ValueError("rings must be the same") - return cmp(self.module(), other.module()) + return richcmp(self.module(), other.module(), op) def __invert__(self): """ From b6c62d0d0be8add74bb92dbbd8d261c4bed2f694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Wed, 4 Oct 2017 13:19:42 +0800 Subject: [PATCH 179/218] Fix doctests and put these factorizations in here that look much nicer/make much more sense. --- src/sage/rings/fraction_field.py | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 8546fcf801e..37ceab27f80 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -864,7 +864,7 @@ def _factor_univariate_polynomial(self, f): sage: R. = K[] sage: f = x^3 + a sage: f.factor() - (t + 2*a + 1)^3 + (x + 2*a + 1)^3 """ # The default implementation would try to convert this element to singular and factor there. diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 5bab530c90d..34b14c2bf5c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3993,9 +3993,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: factor(x) x sage: factor(x^2 - q^2) - (-1) * (-x + q) * (x + q) + (x - q) * (x + q) sage: factor(x^2 - q^-2) - (1/q^2) * (q*x - 1) * (q*x + 1) + (x - 1/q) * (x + 1/q) sage: P. = PolynomialRing(ZZ) sage: R. = PolynomialRing(FractionField(P)) From f8c0088fbb70a1ac2211791bfcd6f3b5aeeb71d5 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 4 Oct 2017 08:25:12 +0200 Subject: [PATCH 180/218] 23844: infix 'in' for GapElement --- src/sage/libs/gap/element.pyx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 8924293a7e4..c7ca311ad52 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -466,6 +466,29 @@ cdef class GapElement(RingElement): """ return self.deepcopy(0) + def __contains__(self, other): + r""" + TESTS:: + + sage: libgap(1) in libgap.eval('Integers') + True + sage: 1 in libgap.eval('Integers') + True + + sage: 3 in libgap([1,5,3,2]) + True + sage: -5 in libgap([1,5,3,2]) + False + + sage: libgap.eval('Integers') in libgap(1) + Traceback (most recent call last): + ... + ValueError: libGAP: Error, no method found! Error, no 1st choice method found for `in' on 2 arguments + """ + from sage.libs.gap.libgap import libgap + GAP_IN = libgap.eval(r'\in') + return GAP_IN(other, self).sage() + cpdef _type_number(self): """ Return the GAP internal type number. From c51f1a50ac40cc38efba2d57cdaf9ae1b5723558 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 4 Oct 2017 09:06:01 +0100 Subject: [PATCH 181/218] one more doctest fix --- src/sage/libs/pynac/pynac.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index c456afabb1f..b5f08fa3159 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -1815,7 +1815,7 @@ cdef py_atan2(x, y): sage: atan2(CC(I), CC(I+1)) 0.553574358897045 + 0.402359478108525*I sage: atan2(CBF(I), CBF(I+1)) - [0.55357435889705 +/- 5.75e-15] + [0.40235947810852 +/- 6.01e-15]*I + [0.55357435889705 +/- 5.58e-15] + [0.402359478108525 +/- 7.11e-16]*I Check that :trac:`23776` is fixed and RDF input gives real output:: From e0810d72fb883a7d394c1f0929a249cf9fb48da7 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sun, 1 Oct 2017 11:38:29 +0200 Subject: [PATCH 182/218] Add includes to include_path for cython() --- src/sage/misc/cython.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 0790edf20f1..b313269b882 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -488,7 +488,10 @@ def cython(filename, verbose=0, compile_message=False, language=language) try: - ext, = cythonize([ext], aliases=cython_aliases(), quiet=not verbose) + ext, = cythonize([ext], + aliases=cython_aliases(), + include_path=includes, + quiet=not verbose) except CompileError: msg = "Error converting {} to C".format(filename) # Check for names in old_pxi_names From fea3848d0d397a7abbc196b3de93df48a2b0fbc3 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 4 Oct 2017 13:59:17 +0200 Subject: [PATCH 183/218] Do not call mp_set_memory_functions() in gmpy2 --- build/pkgs/gmpy2/package-version.txt | 2 +- .../gmpy2/patches/no_set_memory_functions.patch | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/gmpy2/patches/no_set_memory_functions.patch diff --git a/build/pkgs/gmpy2/package-version.txt b/build/pkgs/gmpy2/package-version.txt index 815e68dd20e..6c28a87df9c 100644 --- a/build/pkgs/gmpy2/package-version.txt +++ b/build/pkgs/gmpy2/package-version.txt @@ -1 +1 @@ -2.0.8 +2.0.8.p0 diff --git a/build/pkgs/gmpy2/patches/no_set_memory_functions.patch b/build/pkgs/gmpy2/patches/no_set_memory_functions.patch new file mode 100644 index 00000000000..29fa9432293 --- /dev/null +++ b/build/pkgs/gmpy2/patches/no_set_memory_functions.patch @@ -0,0 +1,17 @@ +Remove call to mp_set_memory_functions() + +Merged upstream in 68bad31a7c636b77f20b064e1728b86f2386972d +as part of a much larger patch. + +diff -ru a/src/gmpy2.c b/src/gmpy2.c +--- a/src/gmpy2.c 2016-06-13 21:17:56.000000000 +0200 ++++ b/src/gmpy2.c 2017-10-04 14:14:23.925780258 +0200 +@@ -842,8 +842,6 @@ + PyObject *temp = NULL; + #endif + +- mp_set_memory_functions(gmpy_allocate, gmpy_reallocate, gmpy_free); +- + set_zcache(); + set_pympzcache(); + set_pympqcache(); From be1e9bcbc919ea0b78ab5768d603cfd951e55646 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 26 Sep 2017 10:54:47 +0200 Subject: [PATCH 184/218] Upgrade to cypari2 version 1.1.3 --- build/pkgs/cypari/checksums.ini | 6 +-- build/pkgs/cypari/package-version.txt | 2 +- .../schemes/elliptic_curves/period_lattice.py | 43 +------------------ 3 files changed, 5 insertions(+), 46 deletions(-) diff --git a/build/pkgs/cypari/checksums.ini b/build/pkgs/cypari/checksums.ini index d1b898c428b..fa58aa5691e 100644 --- a/build/pkgs/cypari/checksums.ini +++ b/build/pkgs/cypari/checksums.ini @@ -1,4 +1,4 @@ tarball=cypari2-VERSION.tar.gz -sha1=3388af8a9c847e16348864ad58f9c033f5a91592 -md5=1fabc73b44d56ef222fb9e87628b3ecb -cksum=2221981199 +sha1=9e1848b5dc566133edad79437fd39e298e336642 +md5=f268f870d255bb98bd4e917f0d74a463 +cksum=3159551499 diff --git a/build/pkgs/cypari/package-version.txt b/build/pkgs/cypari/package-version.txt index 524cb55242b..781dcb07cd8 100644 --- a/build/pkgs/cypari/package-version.txt +++ b/build/pkgs/cypari/package-version.txt @@ -1 +1 @@ -1.1.1 +1.1.3 diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 42032e76e3c..e0473b9b51c 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -115,46 +115,6 @@ from sage.libs.all import pari -# Do we need to work around the PARI ellwp() bug? -_ellwp_factor2 = None - -def _ellwp_flag1(lattice, z): - """ - Evaluate the Weierstrass P function attached to the lattice - ``lattice`` and its derivative at ``z``. - - This calls the PARI function ``ellwp(..., flag=1)``, working around - a bug in PARI versions <= 2.9.3 where the derivative is a factor 2 - too small. - - OUTPUT: ``(P(z), P'(z))`` - - TESTS:: - - sage: from sage.schemes.elliptic_curves.period_lattice import _ellwp_flag1 - sage: E = EllipticCurve([0, 1]) - sage: _ellwp_flag1(E, E((0,1)).elliptic_logarithm()) - (-7.718602... E-30, 2.00000000000000) - """ - global _ellwp_factor2 - if _ellwp_factor2 is None: - # Check whether our PARI/GP version is buggy or not. This - # computation should return 1.0, but in older PARI versions it - # returns 0.5 - d = float(pari("my(E=ellinit([0,1/4]));ellwp(E,ellpointtoz(E,[0,1/2]),1)[2]")) - if d == 1.0: - _ellwp_factor2 = False - elif d == 0.5: - _ellwp_factor2 = True - else: - raise AssertionError("unexpected result from ellwp() test: {}".format(d)) - x, y = pari.ellwp(lattice, z, 1) - if _ellwp_factor2: - return (x, 2*y) - else: - return (x, y) - - class PeriodLattice(FreeModule_generic_pid): """ The class for the period lattice of an algebraic variety. @@ -643,7 +603,6 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): periods = self.E.pari_curve().omega(prec).sage() return (R(periods[0]), C(periods[1])) - from sage.libs.pari.all import pari E_pari = pari([R(self.embedding(ai).real()) for ai in self.E.a_invariants()]).ellinit() periods = E_pari.omega(prec).sage() return (R(periods[0]), C(periods[1])) @@ -1819,7 +1778,7 @@ def elliptic_exponential(self, z, to_curve=True): # So we force the results back into the real/complex fields of # the same precision as the input. - x, y = _ellwp_flag1(self.basis(prec=prec), z) + x, y = pari(self.basis(prec=prec)).ellwp(z, flag=1) x, y = [C(t) for t in (x,y)] if self.real_flag and z_is_real: From 3cff14c2ea4863634fac9f9009f65efcecbf6b1a Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 4 Oct 2017 12:32:14 +0200 Subject: [PATCH 185/218] rank() of elliptic curves should always consult Cremona database --- src/sage/schemes/elliptic_curves/BSD.py | 2 +- .../elliptic_curves/ell_rational_field.py | 121 ++++++++++-------- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index 3d2076399bf..3c41b2fecd6 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -369,7 +369,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, sage: E.rank() 1 sage: E._EllipticCurve_rational_field__rank - {True: 1} + (1, True) sage: E.analytic_rank = lambda : 0 sage: E.prove_BSD() Traceback (most recent call last): diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 6d2934b4448..410abec6494 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -176,7 +176,7 @@ def __init__(self, ainvs, **kwds): """ self.__np = {} self.__gens = {} - self.__rank = {} + self.__rank = None # tuple (rank, proven) self.__regulator = {} self.__generalized_modular_degree = {} self.__generalized_congruence_number = {} @@ -215,12 +215,11 @@ def _set_rank(self, r): sage: E._set_rank(99) # bogus value -- not checked sage: E.rank() # returns bogus cached value 99 - sage: E._EllipticCurve_rational_field__rank={} # undo the damage + sage: E._EllipticCurve_rational_field__rank = None # undo the damage sage: E.rank() # the correct rank 1 """ - self.__rank = {} - self.__rank[True] = Integer(r) + self.__rank = (Integer(r), True) def _set_torsion_order(self, t): """ @@ -862,7 +861,7 @@ def two_descent(self, verbose=True, if C.certain(): self.__gens[True] = [self.point(x, check=True) for x in C.gens()] self.__gens[True].sort() - self.__rank[True] = len(self.__gens[True]) + self.__rank = (Integer(len(self.__gens[True])), True) return C.certain() #################################################################### @@ -1926,7 +1925,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, if len(gens) == rank_low_bd: self.__gens[True] = gens self.__gens[True].sort() - self.__rank[True] = rank_low_bd + self.__rank = (Integer(rank_low_bd), True) return rank_low_bd, two_selmer_rank, pts @@ -1981,10 +1980,10 @@ def three_selmer_rank(self, algorithm='UseSUnits'): E = magma(self) return Integer(E.ThreeSelmerGroup(MethodForFinalStep = magma('"%s"'%algorithm)).Ngens()) - def rank(self, use_database=False, verbose=False, - only_use_mwrank=True, - algorithm='mwrank_lib', - proof=None): + def rank(self, use_database=True, verbose=False, + only_use_mwrank=True, + algorithm='mwrank_lib', + proof=None): """ Return the rank of this elliptic curve, assuming no conjectures. @@ -1993,9 +1992,8 @@ def rank(self, use_database=False, verbose=False, INPUT: - - - ``use_database (bool)`` - (default: ``False``), if - ``True``, try to look up the regulator in the Cremona database. + - ``use_database (bool)`` -- (default: ``True``), if + ``True``, try to look up the rank in the Cremona database. - ``verbose`` - (default: ``False``), if specified changes the verbosity of mwrank computations. @@ -2013,12 +2011,7 @@ def rank(self, use_database=False, verbose=False, proof.elliptic_curve or sage.structure.proof). Note that results obtained from databases are considered proof = True - - OUTPUT: - - - - ``rank (int)`` - the rank of the elliptic curve. - + OUTPUT: the rank of the elliptic curve as :class:`Integer` IMPLEMENTATION: Uses L-functions, mwrank, and databases. @@ -2057,33 +2050,60 @@ def rank(self, use_database=False, verbose=False, sage: EllipticCurve([1,0,0,0,37455]).rank(proof=True) Traceback (most recent call last): ... - RuntimeError: Rank not provably correct. + RuntimeError: rank not provably correct (lower bound: 0) + + TESTS:: + + sage: EllipticCurve([1,10000]).rank(algorithm="garbage") + Traceback (most recent call last): + ... + ValueError: unknown algorithm 'garbage' + + Since :trac:`23962`, the default is to use the Cremona + database. We also check that the result is cached correctly:: + + sage: E = EllipticCurve([-517, -4528]) # 1888b1 + sage: E.rank(use_database=False) + Traceback (most recent call last): + ... + RuntimeError: rank not provably correct (lower bound: 0) + sage: E._EllipticCurve_rational_field__rank + (0, False) + sage: E.rank() + 0 + sage: E._EllipticCurve_rational_field__rank + (0, True) """ if proof is None: from sage.structure.proof.proof import get_flag proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) - try: - return self.__rank[proof] - except KeyError: - if proof is False and True in self.__rank: - return self.__rank[True] + + if self.__rank: + rank, proven = self.__rank + if proven or not proof: + return rank + if use_database: try: - self.__rank[True] = self.database_attributes()['rank'] - return self.__rank[True] + rank = Integer(self.database_attributes()['rank']) except LookupError: # curve not in database, or rank not known pass + else: + self.__rank = (rank, True) + return rank + if not only_use_mwrank: # Try zero sum rank bound first; if this is 0 or 1 it's the # true rank rank_bound = self.analytic_rank_upper_bound() if rank_bound <= 1: misc.verbose("rank %s due to zero sum bound and parity"%rank_bound) - self.__rank[proof] = rank_bound - return self.__rank[proof] + rank = Integer(rank_bound) + self.__rank = (rank, proof) + return rank # Next try evaluate the L-function or its derivative at the # central point N = self.conductor() @@ -2092,14 +2112,16 @@ def rank(self, use_database=False, verbose=False, L, err = self.lseries().at1(prec) if abs(L) > err + R(0.0001): # definitely doesn't vanish misc.verbose("rank 0 because L(E,1)=%s"%L) - self.__rank[proof] = 0 - return self.__rank[proof] + rank = Integer(0) + self.__rank = (rank, proof) + return rank else: Lprime, err = self.lseries().deriv_at1(prec) if abs(Lprime) > err + R(0.0001): # definitely doesn't vanish misc.verbose("rank 1 because L'(E,1)=%s"%Lprime) - self.__rank[proof] = 1 - return self.__rank[proof] + rank = Integer(1) + self.__rank = (rank, proof) + return rank if algorithm == 'mwrank_lib': misc.verbose("using mwrank lib") @@ -2107,35 +2129,36 @@ def rank(self, use_database=False, verbose=False, else: E = self.integral_model() C = E.mwrank_curve() C.set_verbose(verbose) - r = C.rank() - if C.certain(): - proof = True - else: + rank = Integer(C.rank()) + proven = C.certain() + self.__rank = (rank, proven) + if not proven: if proof: - print("Unable to compute the rank with certainty (lower bound=%s)." % C.rank()) + print("Unable to compute the rank with certainty (lower bound=%s)." % rank) print("This could be because Sha(E/Q)[2] is nontrivial.") print("Try calling something like two_descent(second_limit=13) on the") print("curve then trying this command again. You could also try rank") print("with only_use_mwrank=False.") del E.__mwrank_curve - raise RuntimeError('Rank not provably correct.') + raise RuntimeError('rank not provably correct (lower bound: {})'.format(rank)) else: misc.verbose("Warning -- rank not proven correct", level=1) - self.__rank[proof] = r - elif algorithm == 'mwrank_shell': + return rank + + if algorithm == 'mwrank_shell': misc.verbose("using mwrank shell") X = self.mwrank() if 'determined unconditionally' not in X or 'only a lower bound of' in X: if proof: X= "".join(X.split("\n")[-4:-2]) print(X) - raise RuntimeError('Rank not provably correct.') + raise RuntimeError('rank not provably correct') else: misc.verbose("Warning -- rank not proven correct", level=1) s = "lower bound of" X = X[X.rfind(s)+len(s)+1:] - r = Integer(X.split()[0]) + rank = Integer(X.split()[0]) else: if proof is False: proof = True #since we actually provably found the rank @@ -2147,10 +2170,11 @@ def rank(self, use_database=False, verbose=False, if i == -1: raise RuntimeError("%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't."%X) j = i + X[i:].find('\n') - r = Integer(X[i+len(match)+1:j]) - self.__rank[proof] = r + rank = Integer(X[i+len(match)+1:j]) + self.__rank = (rank, proof) + return rank - return self.__rank[proof] + raise ValueError("unknown algorithm {!r}".format(algorithm)) def gens(self, proof=None, **kwds): """ @@ -2241,7 +2265,7 @@ def gens(self, proof=None, **kwds): result, proved = self._compute_gens(proof, **kwds) self.__gens[proved] = result - self.__rank[proved] = len(result) + self.__rank = (Integer(len(result)), proved) self._known_points = result return list(result) @@ -2838,7 +2862,6 @@ def point_search(self, height_limit, verbose=False, rank_bound=None): points = self.saturation(points, verbose=verbose)[0] return points - def selmer_rank(self): """ The rank of the 2-Selmer group of the curve. @@ -2886,7 +2909,6 @@ def selmer_rank(self): self.__selmer_rank = C.selmer_rank() return self.__selmer_rank - def rank_bound(self): """ Upper bound on the rank of the curve, computed using @@ -2921,7 +2943,6 @@ def rank_bound(self): self.__rank_bound = C.rank_bound() return self.__rank_bound - def an(self, n): """ The n-th Fourier coefficient of the modular form corresponding to From 55b33e4ecbe79e0731d6f14a2f39afeb5f668689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 5 Oct 2017 14:48:44 +0800 Subject: [PATCH 186/218] Coercions to the fraction field are injective --- src/sage/categories/rings.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index b8a8525bea4..d10f778ff1f 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -128,6 +128,12 @@ def is_injective(self): sage: f.is_injective() True + A coercion to the fraction field is injective:: + + sage: R = ZpFM(3) + sage: R.fraction_field().coerce_map_from(R).is_injective() + True + """ if self.domain().is_zero(): return True @@ -155,6 +161,10 @@ def is_injective(self): if self.domain().fraction_field() in NumberFields(): return True + if self._is_coercion: + if self.domain().fraction_field() is self.codomain(): + return True + if self.domain().cardinality() > self.codomain().cardinality(): return False From d8c961bfe6d67c265a5c615557ad7744cdf42e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Oct 2017 09:05:30 +0200 Subject: [PATCH 187/218] trac 23671 care for pdf doc --- src/sage/modular/hypergeometric_motive.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index f6f756e978e..fd0ff831ea3 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -253,7 +253,7 @@ def alpha_to_cyclotomic(alpha): The output represent a product of cyclotomic polynomials with exactly the given roots. Note that the multiplicity of `r/s` in the list - must be independent of `r`; otherwise, a ValueError will be raised. + must be independent of `r`; otherwise, a ``ValueError`` will be raised. This is the inverse of :func:`cyclotomic_to_alpha`. @@ -386,7 +386,7 @@ def gamma_list_to_cyclotomic(galist): class HypergeometricData(object): def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): - """ + r""" Creation of hypergeometric motives. INPUT: @@ -538,7 +538,7 @@ def primitive_data(self): return HypergeometricData(gamma_list=[x / d for x in g]) def zigzag(self, x, flip_beta=False): - """ + r""" Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. This function is used to compute the weight and the Hodge numbers. From 87c900cc682f0d52c7bc6e3ef23f466eba373939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 5 Oct 2017 16:02:35 +0800 Subject: [PATCH 188/218] normalize() FP elements to detect an exact zero unit after conversion --- src/sage/rings/padics/FP_template.pxi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index fb05e02cc05..7c287e0c8db 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -97,8 +97,7 @@ cdef class FPElement(pAdicTemplateElement): - ``x`` -- data defining a `p`-adic element: int, long, Integer, Rational, other `p`-adic element... - - ``val`` -- the valuation of the resulting element (unused; - for compatibility with other `p`-adic precision modes) + - ``val`` -- the valuation of the resulting element - ``xprec -- an inherent precision of ``x`` (unused; for compatibility with other `p`-adic precision modes) @@ -138,6 +137,7 @@ cdef class FPElement(pAdicTemplateElement): ccopy(self.unit, (x).unit, self.prime_pow) else: cconv(self.unit, x, self.prime_pow.prec_cap, val, self.prime_pow) + self._normalize() cdef int _set_exact_zero(self) except -1: """ From f5e5765874b291d48bf4d8fede927befbddddfb7 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 4 Sep 2017 14:04:53 +0200 Subject: [PATCH 189/218] Support SAGE_NUM_THREADS for all parallellism --- src/bin/sage-runtests | 5 +-- src/sage/homology/simplicial_complex.py | 9 ++--- src/sage/numerical/backends/coin_backend.pyx | 7 ++-- src/sage/parallel/map_reduce.py | 38 ++++++++++++-------- src/sage/parallel/ncpus.py | 10 ++++++ 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 09b8aa24be9..d94d192cdc0 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -108,9 +108,10 @@ if __name__ == "__main__": if lim == resource.RLIM_INFINITY or lim > memlimit: resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) - # Limit the number of OMP threads to 2 to save system resources - # See Trac #23892 + # Limit the number of threads to 2 to save system resources. + # See Trac #23713 and #23892 os.environ["OMP_NUM_THREADS"] = "2" + os.environ["SAGE_NUM_THREADS"] = "2" from sage.doctest.control import DocTestController DC = DocTestController(options, args) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index aefe15563ae..9ca1dd1f0a1 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -2856,12 +2856,9 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0): """ from sage.parallel.decorate import parallel - if ncpus == 0: - import os - try: - ncpus = int(os.environ['SAGE_NUM_THREADS']) - except KeyError: - ncpus = 1 + if not ncpus: + from sage.parallel.ncpus import ncpus as get_ncpus + ncpus = get_ncpus() facs = [ x for x in self.face_iterator() ] n = len(facs) diff --git a/src/sage/numerical/backends/coin_backend.pyx b/src/sage/numerical/backends/coin_backend.pyx index 504183b4abd..da527137d21 100644 --- a/src/sage/numerical/backends/coin_backend.pyx +++ b/src/sage/numerical/backends/coin_backend.pyx @@ -28,6 +28,9 @@ from cysignals.signals cimport sig_on, sig_off from sage.numerical.mip import MIPSolverException from copy import copy +from sage.parallel.ncpus import ncpus + + cdef class CoinBackend(GenericBackend): """ @@ -760,7 +763,7 @@ cdef class CoinBackend(GenericBackend): # multithreading import multiprocessing - model.setNumberThreads(multiprocessing.cpu_count()) + model.setNumberThreads(ncpus()) model.branchAndBound() @@ -1413,7 +1416,7 @@ cdef class CoinBackend(GenericBackend): # multithreading import multiprocessing - model.setNumberThreads(multiprocessing.cpu_count()) + model.setNumberThreads(ncpus()) if n != self.model.solver().getNumCols() or m != self.model.solver().getNumRows(): raise ValueError("Must provide the status of every column and row variables") diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 1b1d2d95503..db790673780 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -202,8 +202,10 @@ passing parameters to the :meth:`RESetMapReduce.run` method. One can use the three following parameters: -- ``max_proc`` -- maximum number of process used. - default: number of processor on the machine +- ``max_proc`` -- (integer, default: ``None``) if given, the + maximum number of worker processors to use. The actual number + is also bounded by the value of the environment variable + ``SAGE_NUM_THREADS`` (the number of cores by default). - ``timeout`` -- a timeout on the computation (default: ``None``) - ``reduce_locally`` -- whether the workers should reduce locally their work or sends results to the master as soon as possible. @@ -501,7 +503,7 @@ """ from __future__ import print_function, absolute_import -from multiprocessing import Process, Value, Semaphore, Lock, cpu_count +from multiprocessing import Process, Value, Semaphore, Lock from multiprocessing.queues import Pipe, SimpleQueue from multiprocessing.sharedctypes import RawArray from threading import Thread @@ -509,6 +511,7 @@ from sage.misc.lazy_attribute import lazy_attribute import collections import copy +import os import sys import random import ctypes @@ -537,13 +540,14 @@ -def proc_number(max_proc = None): +def proc_number(max_proc=None): r""" - Computing the number of process used + Return the number of processes to use INPUT: - - ``max_proc`` -- the maximum number of process used + - ``max_proc`` -- an upper bound on the number of processes or + ``None``. EXAMPLES:: @@ -555,10 +559,12 @@ def proc_number(max_proc = None): sage: proc_number(max_proc=2) in (1, 2) True """ + from sage.parallel.ncpus import ncpus + n = ncpus() if max_proc is None: - return max(cpu_count(), 1) + return n else: - return min(max_proc, max(cpu_count(), 2)) + return min(max_proc, n) class AbortError(Exception): @@ -1036,14 +1042,14 @@ def reduce_init(self): """ return copy.copy(self._reduce_init) - - def setup_workers(self, max_proc = None, reduce_locally=True): + def setup_workers(self, max_proc=None, reduce_locally=True): r""" Setup the communication channels INPUT: - - ``mac_proc`` -- an integer: the maximum number of workers + - ``max_proc`` -- (integer) an upper bound on the number of + worker processes. - ``reduce_locally`` -- whether the workers should reduce locally their work or sends results to the master as soon as possible. @@ -1337,8 +1343,8 @@ def random_worker(self): return self._workers[victim] def run(self, - max_proc = None, - reduce_locally = True, + max_proc=None, + reduce_locally=True, timeout=None, profile=None): r""" @@ -1346,8 +1352,10 @@ def run(self, INPUT: - - ``max_proc`` -- maximum number of process used. - default: number of processor on the machine + - ``max_proc`` -- (integer, default: ``None``) if given, the + maximum number of worker processors to use. The actual number + is also bounded by the value of the environment variable + ``SAGE_NUM_THREADS`` (the number of cores by default). - ``reduce_locally`` -- See :class:`RESetMapReduceWorker` (default: ``True``) - ``timeout`` -- a timeout on the computation (default: ``None``) - ``profile`` -- directory/filename prefix for profiling, or ``None`` diff --git a/src/sage/parallel/ncpus.py b/src/sage/parallel/ncpus.py index 88882528c69..7222e0a5d69 100644 --- a/src/sage/parallel/ncpus.py +++ b/src/sage/parallel/ncpus.py @@ -43,6 +43,16 @@ def ncpus(): sage: sage.parallel.ncpus.ncpus() # random output -- depends on machine. 2 """ + # Support Sage environment variable SAGE_NUM_THREADS + # NOTE: while doctesting, this is forced to be 2 by the + # sage-runtests script + try: + n = os.environ["SAGE_NUM_THREADS"] + except KeyError: + pass + else: + return int(n) + #for Linux, Unix and MacOS if hasattr(os, "sysconf"): if "SC_NPROCESSORS_ONLN" in os.sysconf_names: From 8bce6fff2c8425978a458b282256b4767651bbe3 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 5 Oct 2017 15:28:06 +0200 Subject: [PATCH 190/218] Simpler caching in ell_rational_field --- src/sage/schemes/elliptic_curves/BSD.py | 4 +- .../elliptic_curves/ell_rational_field.py | 130 ++++++++---------- 2 files changed, 63 insertions(+), 71 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index 3c41b2fecd6..16b93f222e7 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -528,9 +528,9 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, rank_lower_bd > rank_upper_bd: raise RuntimeError("Something went wrong with 2-descent.") if BSD.rank != len(gens): - if BSD.rank != len(BSD.curve._EllipticCurve_rational_field__gens[True]): + gens = BSD.curve.gens(proof=True) + if BSD.rank != len(gens): raise RuntimeError("Could not get generators") - gens = BSD.curve._EllipticCurve_rational_field__gens[True] BSD.gens = [BSD.curve.point(x, check=True) for x in gens] if BSD.rank != BSD.curve.analytic_rank(): diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 410abec6494..e8e0b8f6746 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -174,13 +174,18 @@ def __init__(self, ainvs, **kwds): [True, True] """ - self.__np = {} - self.__gens = {} - self.__rank = None # tuple (rank, proven) - self.__regulator = {} + # Cached values for the generators, rank and regulator. + # The format is a tuple (value, proven). "proven" is a boolean + # which says whether or not the value was proven. + self.__gens = None + self.__rank = None + self.__regulator = None + + # Other cached values self.__generalized_modular_degree = {} self.__generalized_congruence_number = {} self._isoclass = {} + EllipticCurve_number_field.__init__(self, Q, ainvs) if 'conductor' in kwds: @@ -196,7 +201,7 @@ def __init__(self, ainvs, **kwds): if 'rank' in kwds: self._set_rank(kwds['rank']) if 'regulator' in kwds: - self.__regulator[True] = kwds['regulator'] + self.__regulator = (kwds['regulator'], True) if 'torsion_order' in kwds: self._set_torsion_order(kwds['torsion_order']) @@ -332,9 +337,8 @@ def _set_gens(self, gens): sage: E.gens() [(-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1)] """ - self.__gens = {} - self.__gens[True] = [self.point(x, check=True) for x in gens] - self.__gens[True].sort() + gens = sorted(self.point(x, check=True) for x in gens) + self.__gens = (gens, True) def lmfdb_page(self): r""" @@ -859,9 +863,9 @@ def two_descent(self, verbose=True, first_limit, second_limit, n_aux, second_descent) if C.certain(): - self.__gens[True] = [self.point(x, check=True) for x in C.gens()] - self.__gens[True].sort() - self.__rank = (Integer(len(self.__gens[True])), True) + gens = sorted(self.point(x, check=True) for x in C.gens()) + self.__gens = (gens, True) + self.__rank = (Integer(len(gens)), True) return C.certain() #################################################################### @@ -1923,8 +1927,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, print("Rank determined successfully, saturating...") gens = self.saturation(pts)[0] if len(gens) == rank_low_bd: - self.__gens[True] = gens - self.__gens[True].sort() + self.__gens = (gens, True) self.__rank = (Integer(rank_low_bd), True) return rank_low_bd, two_selmer_rank, pts @@ -2181,13 +2184,6 @@ def gens(self, proof=None, **kwds): Return generators for the Mordell-Weil group E(Q) *modulo* torsion. - .. warning:: - - If the program fails to give a provably correct result, it - prints a warning message, but does not raise an - exception. Use :meth:`~gens_certain` to find out if this - warning message was printed. - INPUT: - ``proof`` -- bool or None (default None), see @@ -2225,6 +2221,12 @@ def gens(self, proof=None, **kwds): - ``generators`` - list of generators for the Mordell-Weil group modulo torsion + .. NOTE:: + + If you call this with ``proof=False``, then you can use the + :meth:`~gens_certain` method to find out afterwards + whether the generators were proved. + IMPLEMENTATION: Uses Cremona's mwrank C library. EXAMPLES:: @@ -2254,20 +2256,16 @@ def gens(self, proof=None, **kwds): proof = bool(proof) # If the gens are already cached, return them: - try: - return list(self.__gens[proof]) # return copy so not changed - except KeyError: - if proof is False and True in self.__gens: - return list(self.__gens[True]) - - # At this point, self.__gens[True] does not exist, and in case - # proof is False, self.__gens[False] does not exist either. + if self.__gens: + gens, proven = self.__gens + if proven or not proof: + return list(gens) # Return a copy - result, proved = self._compute_gens(proof, **kwds) - self.__gens[proved] = result - self.__rank = (Integer(len(result)), proved) - self._known_points = result - return list(result) + gens, proved = self._compute_gens(proof, **kwds) + self.__gens = (gens, proved) + self.__rank = (Integer(len(gens)), proved) + self._known_points = gens + return list(gens) def _compute_gens(self, proof, verbose=False, @@ -2415,8 +2413,18 @@ def gens_certain(self): [(0 : -1 : 1)] sage: E.gens_certain() True + + TESTS:: + + sage: E = EllipticCurve([2, 4, 6, 8, 10]) + sage: E.gens_certain() + Traceback (most recent call last): + ... + RuntimeError: no generators have been computed yet """ - return True in self.__gens + if not self.__gens: + raise RuntimeError("no generators have been computed yet") + return self.__gens[1] def ngens(self, proof=None): """ @@ -2447,26 +2455,20 @@ def ngens(self, proof=None): """ return len(self.gens(proof = proof)) - def regulator(self, use_database=True, proof=None, precision=None, - descent_second_limit=12, verbose=False): + def regulator(self, proof=None, precision=53, **kwds): r""" Return the regulator of this curve, which must be defined over `\QQ`. INPUT: - - ``use_database`` -- bool (default: ``False``), if ``True``, - try to look up the generators in the Cremona database. - - ``proof`` -- bool or ``None`` (default: ``None``, see proof.[tab] or sage.structure.proof). Note that results from databases are considered proof = True - - ``precision`` -- int or ``None`` (default: ``None``): the - precision in bits of the result (default real precision if None) + - ``precision`` -- (int, default 53): the precision in bits of + the result - - ``descent_second_limit`` -- (default: 12)- used in 2-descent - - - ``verbose`` -- whether to print mwrank's verbose output + - ``**kwds`` -- passed to :meth:`gens()` method EXAMPLES:: @@ -2486,11 +2488,7 @@ def regulator(self, use_database=True, proof=None, precision=None, sage: EllipticCurve([0, 0, 1, -79, 342]).regulator(proof=False) # long time (6s on sage.math, 2011) 14.790527570131... """ - if precision is None: - RR = rings.RealField() - precision = RR.precision() - else: - RR = rings.RealField(precision) + R = rings.RealField(precision) if proof is None: from sage.structure.proof.proof import get_flag @@ -2499,29 +2497,23 @@ def regulator(self, use_database=True, proof=None, precision=None, proof = bool(proof) # We return a cached value if it exists and has sufficient precision: - try: - reg = self.__regulator[proof] - if reg.parent().precision() >= precision: - return RR(reg) - else: # Found regulator value but precision is too low - pass - except KeyError: - if proof is False and True in self.__regulator: - reg = self.__regulator[True] - if reg.parent().precision() >= precision: - return RR(reg) - else: # Found regulator value but precision is too low + if self.__regulator: + reg, proven = self.__regulator + if proven or not proof: + # Coerce to the target field R. This will fail if the + # precision was too low. + try: + return R.coerce(reg) + except TypeError: pass - # Next we find the gens, taking them from the database if they - # are there and use_database is True, else computing them: - - G = self.gens(proof=proof, use_database=use_database, descent_second_limit=descent_second_limit, verbose=verbose) - - # Finally compute the regulator of the generators found: + G = self.gens(proof=proof, **kwds) - self.__regulator[proof] = self.regulator_of_points(G,precision=precision) - return self.__regulator[proof] + # Compute the regulator of the generators found: + reg = self.regulator_of_points(G, precision=precision) + self.__regulator = (reg, self.gens_certain()) + assert reg.parent() is R + return reg def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False): """ From 09a8953cbcb10a64c4a555fe54017be6db75ec21 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Thu, 5 Oct 2017 22:59:04 +0200 Subject: [PATCH 191/218] trac #18395: increase relative tolerance in doctests --- src/sage/graphs/generic_graph_pyx.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 451911e270c..22f7815e52a 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -108,9 +108,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: pos = spring_layout_fast(G) - sage: pos[0] # abs tol 0.03 + sage: pos[0] # abs tol 0.1 [0.00..., 0.03...] - sage: pos[902] # abs tol 0.03 + sage: pos[902] # abs tol 0.1 [-0.48..., -0.10...] sage: len(pos) == G.order() True @@ -129,9 +129,9 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast sage: pos = spring_layout_fast(G, by_component = True) - sage: pos[0] # abs tol 0.03 + sage: pos[0] # abs tol 0.1 [2.21..., -0.00...] - sage: pos[902] # abs tol 0.03 + sage: pos[902] # abs tol 0.1 [3.07..., 0.86...] sage: len(pos) == G.order() True From f1d2109bbf3f2cc42046286752a3f2c3468ee16d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 5 Oct 2017 17:04:40 +0200 Subject: [PATCH 192/218] Reference manual: fix groups index --- src/doc/en/reference/groups/index.rst | 44 ++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index fb0a2b7e46e..204c3ccfc76 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -20,6 +20,18 @@ Groups sage/groups/raag sage/groups/group_exp sage/groups/group_semidirect_product + sage/groups/misc_gps/misc_groups + sage/groups/semimonomial_transformations/semimonomial_transformation_group + sage/groups/semimonomial_transformations/semimonomial_transformation + sage/groups/class_function + sage/groups/conjugacy_classes + +Abelian Groups +-------------- + +.. toctree:: + :maxdepth: 2 + sage/groups/abelian_gps/abelian_group sage/groups/abelian_gps/values sage/groups/abelian_gps/dual_abelian_group @@ -29,6 +41,13 @@ Groups sage/groups/abelian_gps/abelian_group_morphism sage/groups/additive_abelian/additive_abelian_group sage/groups/additive_abelian/additive_abelian_wrapper + +Permutation Groups +------------------ + +.. toctree:: + :maxdepth: 2 + sage/groups/perm_gps/permutation_groups_catalog sage/groups/perm_gps/permgroup sage/groups/perm_gps/permgroup_named @@ -36,6 +55,13 @@ Groups sage/groups/perm_gps/permgroup_morphism sage/groups/perm_gps/cubegroup sage/groups/perm_gps/symgp_conjugacy_class + +Matrix and Affine Groups +------------------------ + +.. toctree:: + :maxdepth: 2 + sage/groups/matrix_gps/catalog sage/groups/matrix_gps/matrix_group sage/groups/matrix_gps/group_element @@ -52,13 +78,17 @@ Groups sage/groups/affine_gps/affine_group sage/groups/affine_gps/euclidean_group sage/groups/affine_gps/group_element - sage/groups/misc_gps/misc_groups - sage/groups/semimonomial_transformations/semimonomial_transformation_group - sage/groups/semimonomial_transformations/semimonomial_transformation - sage/groups/class_function - sage/groups/conjugacy_classes - sage/groups/perm_gps/partn_ref - sage/groups/perm_gps/partn_ref2 + +Partition Refinement +-------------------- + +.. toctree:: + :maxdepth: 2 + + sage/groups/perm_gps/partn_ref/canonical_augmentation + sage/groups/perm_gps/partn_ref/data_structures + sage/groups/perm_gps/partn_ref/refinement_lists + sage/groups/perm_gps/partn_ref/refinement_matrices Internals --------- From a4d9ad6429371fc8cca4b60353642bb36cf1402a Mon Sep 17 00:00:00 2001 From: David Roe Date: Thu, 5 Oct 2017 23:55:42 +0000 Subject: [PATCH 193/218] Catch exceptions raised by attempting to find fraction field --- src/sage/categories/rings.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index d10f778ff1f..ba0f70d1a8f 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -162,8 +162,13 @@ def is_injective(self): return True if self._is_coercion: - if self.domain().fraction_field() is self.codomain(): - return True + try: + K = self.domain().fraction_field() + except (TypeError, AttributeError, ValueError): + pass + else: + if K is self.codomain(): + return True if self.domain().cardinality() > self.codomain().cardinality(): return False From b8de18928c9d5ec2e4aade83ab910e97673191d4 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 6 Oct 2017 03:00:50 +0000 Subject: [PATCH 194/218] Different fix for 23966, add doctest --- src/sage/rings/padics/FP_template.pxi | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index 286b1a14ff5..75eb345a6cc 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -99,12 +99,11 @@ cdef class FPElement(pAdicTemplateElement): - ``val`` -- the valuation of the resulting element - - ``xprec -- an inherent precision of ``x`` (unused; for - compatibility with other `p`-adic precision modes) + - ``xprec -- an inherent precision of ``x``, if ``val`` + is larger then the result will be zero. - - ``absprec`` -- an absolute precision cap for this element - (unused; for compatibility with other `p`-adic precision - modes) + - ``absprec`` -- an absolute precision cap for this element, + if ``val`` is larger then the result will be zero. - ``relprec`` -- a relative precision cap for this element (unused; for compatibility with other `p`-adic precision @@ -125,9 +124,16 @@ cdef class FPElement(pAdicTemplateElement): True sage: R(5) - R(5) 0 + + We check that :trac:`23966` is resolved:: + + sage: R = ZpFM(2) + sage: K = R.fraction_field() + sage: K(R.zero()) + 0 """ cconstruct(self.unit, self.prime_pow) - if very_pos_val(val): + if val >= xprec or val >= absprec: self._set_exact_zero() elif very_neg_val(val): self._set_infinity() @@ -137,7 +143,6 @@ cdef class FPElement(pAdicTemplateElement): ccopy(self.unit, (x).unit, self.prime_pow) else: cconv(self.unit, x, self.prime_pow.prec_cap, val, self.prime_pow) - self._normalize() cdef int _set_exact_zero(self) except -1: """ From d727d6c46bb3b74e4e87f122e9d3da3856897adc Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 6 Oct 2017 10:16:29 +0200 Subject: [PATCH 195/218] Fixed orthogonal_complement() --- src/sage/modules/free_quadratic_module_integer_symmetric.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index af813218797..cfa09b2bff4 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -361,7 +361,8 @@ def orthogonal_complement(self, M): raise ValueError("M must have the same ambient vector space as this lattice.") K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() - K.base_extend(QQ) + K = self.span( K.basis() ) + K = K.base_extend(QQ) return self.sublattice(self.intersection(K).basis()) def sublattice(self, basis): From 06b8167770e2cf4d025b7d1e444d9878542f0b1f Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 6 Oct 2017 11:19:26 +0200 Subject: [PATCH 196/218] Fixed the loads(dumps(x)) issue by fixing comparison for free modules. The change only kicks in if the unique parent assumption is violated. This seems to happen in the loads dumps process. --- src/sage/modules/free_module.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 7c74b3c61cc..e4ae6185e70 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -4416,7 +4416,10 @@ def __richcmp__(self, other, op): #this only affects free_quadratic_modules lx = self.inner_product_matrix() rx = other.inner_product_matrix() - return richcmp_not_equal(lx,rx,op) + if lx != rx: + return richcmp_not_equal(lx,rx,op) + else: + return rich_to_bool(op,0) try: if self.base_ring().is_subring(other.base_ring()): return rich_to_bool(op, -1) From c2c8fd878f026054dcafd946f4acb46ef6cc9e70 Mon Sep 17 00:00:00 2001 From: Frederic HAN Date: Fri, 6 Oct 2017 11:35:31 +0200 Subject: [PATCH 197/218] update to giacpy_sage 0.6.6 + reset threads to orig in doctest --- build/pkgs/giacpy_sage/checksums.ini | 6 +++--- build/pkgs/giacpy_sage/package-version.txt | 2 +- src/sage/libs/giac.py | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/pkgs/giacpy_sage/checksums.ini b/build/pkgs/giacpy_sage/checksums.ini index 62f3e872805..d2cab244fed 100644 --- a/build/pkgs/giacpy_sage/checksums.ini +++ b/build/pkgs/giacpy_sage/checksums.ini @@ -1,4 +1,4 @@ tarball=giacpy_sage-VERSION.tar.gz -sha1=1f4dcec697296d1cce88fa9a03c14df2a9ba71c5 -md5=515734bc266c15c69e195636f448cd97 -cksum=2454875195 +sha1=0d82ae71219d546532e1234fee4ea8b1b6f53ccf +md5=d8cc9fe590e808c2543b8fc712ea9481 +cksum=1760632879 diff --git a/build/pkgs/giacpy_sage/package-version.txt b/build/pkgs/giacpy_sage/package-version.txt index 5a2a5806df6..05e8a4593fa 100644 --- a/build/pkgs/giacpy_sage/package-version.txt +++ b/build/pkgs/giacpy_sage/package-version.txt @@ -1 +1 @@ -0.6 +0.6.6 diff --git a/src/sage/libs/giac.py b/src/sage/libs/giac.py index ffcdec029a1..e0d7712146a 100644 --- a/src/sage/libs/giac.py +++ b/src/sage/libs/giac.py @@ -113,6 +113,7 @@ def local_giacsettings(func): True sage: gp Date: Fri, 6 Oct 2017 11:04:27 +0200 Subject: [PATCH 198/218] sage-location: do not remove .pyc files --- src/bin/sage-location | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/bin/sage-location b/src/bin/sage-location index caeb9a6cf63..306cb33fdbf 100755 --- a/src/bin/sage-location +++ b/src/bin/sage-location @@ -62,23 +62,6 @@ SINGULAR %s f.close() -def remove_files(path, remove_extensions): - """ - Walk the tree starting at ``path``, and remove all files with - extensions in ``remove_extensions``. - The extensions in ``remove_extensions`` should start with a period, i.e., - e.g. use ``remove_files(path, ('.pyc', '.pyo'))``. - """ - for root, dirs, files in os.walk(path): - for file in files: - filename = os.path.join(root, file) - if os.path.splitext(filename)[1] in remove_extensions: - try: - os.unlink(filename) - except OSError as msg: - print(msg) - - def sage_relocate(): """ High-level function which calls various functions to handle @@ -90,10 +73,6 @@ def sage_relocate(): """ write_config_files() - # Compiled python files need to be regenerated, so we remove them: - for dir in glob.glob(os.path.join(SAGE_LOCAL, 'lib', 'python*')): - remove_files(dir, remove_extensions=('.pyc', '.pyo')) - # Write the new location file as last thing in this script, # so that it only gets written if there were no exceptions. write_location_file() From f050a342b6bf058dee452e2db0851cddb42c265e Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Fri, 6 Oct 2017 16:05:30 +0200 Subject: [PATCH 199/218] Cygwin does not support setting RLIMIT_AS; but rather than hard-code a special case just ignore failures here (which result in a ValueError) --- src/bin/sage-runtests | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 09b8aa24be9..fd855baac4a 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -106,7 +106,10 @@ if __name__ == "__main__": import resource lim, hard = resource.getrlimit(resource.RLIMIT_AS) if lim == resource.RLIM_INFINITY or lim > memlimit: - resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) + try: + resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) + except ValueError: + pass # Limit the number of OMP threads to 2 to save system resources # See Trac #23892 From 707a74e27dd6fea52d3785fe4dbe1f46b61d3a84 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Fri, 6 Oct 2017 20:53:26 +0200 Subject: [PATCH 200/218] clean up in __richcmp__ for free modules. --- src/sage/modules/free_module.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index e4ae6185e70..acd3d709a83 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -4410,16 +4410,13 @@ def __richcmp__(self, other, op): if lx == rx: #We do not want to create an inner product matrix in memory if #self and other use the dot product - if self._inner_product_is_dot_product()==True and other._inner_product_is_dot_product()==True: + if self._inner_product_is_dot_product() and other._inner_product_is_dot_product(): return rich_to_bool(op, 0) else: #this only affects free_quadratic_modules lx = self.inner_product_matrix() rx = other.inner_product_matrix() - if lx != rx: - return richcmp_not_equal(lx,rx,op) - else: - return rich_to_bool(op,0) + return richcmp(lx,rx,op) try: if self.base_ring().is_subring(other.base_ring()): return rich_to_bool(op, -1) From dda5551fa7d03fdd1cd1d9bc2ffb82b01acd7010 Mon Sep 17 00:00:00 2001 From: Frederic HAN Date: Sat, 7 Oct 2017 19:13:57 +0200 Subject: [PATCH 201/218] remove duplicate restoration of giacsetting.threads in doctest --- src/sage/libs/giac.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/libs/giac.py b/src/sage/libs/giac.py index e0d7712146a..ffcdec029a1 100644 --- a/src/sage/libs/giac.py +++ b/src/sage/libs/giac.py @@ -113,7 +113,6 @@ def local_giacsettings(func): True sage: gp Date: Sat, 7 Oct 2017 18:06:00 -0500 Subject: [PATCH 202/218] Speeding up LLT polynomials. --- src/sage/combinat/integer_matrices.py | 9 ++- src/sage/combinat/partition.py | 12 +++- src/sage/combinat/ribbon_tableau.py | 82 ++++++++++++++------------- src/sage/combinat/sf/llt.py | 18 +++--- 4 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/sage/combinat/integer_matrices.py b/src/sage/combinat/integer_matrices.py index 1467d50ebcb..af0a156cd7b 100644 --- a/src/sage/combinat/integer_matrices.py +++ b/src/sage/combinat/integer_matrices.py @@ -321,18 +321,17 @@ def integer_matrices_generator(row_sums, column_sums): [[0, 3], [2, 0], [0, 2]] [[0, 3], [1, 1], [1, 1]] [[0, 3], [0, 2], [2, 0]] - """ - row_sums = list(row_sums) - column_sums = list(column_sums) if sum(row_sums) != sum(column_sums): raise StopIteration - if len(row_sums) == 0: + if not row_sums: yield [] elif len(row_sums) == 1: yield [column_sums] else: - for comp in IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=column_sums): + I = IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=list(column_sums)) + for comp in I.backend._iter(): t = [column_sums[i]-ci for (i, ci) in enumerate(comp)] for mat in integer_matrices_generator(row_sums[1:], t): yield [list(comp)] + mat + diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index feb04f7e17c..db83b3d3333 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -539,11 +539,17 @@ def __init__(self, parent, mu): CombinatorialElement.__init__(self, parent, mu._list) return - elif len(mu)==0 or (all(mu[i] in NN and mu[i]>=mu[i+1] for i in range(len(mu)-1)) \ + elif not mu: + CombinatorialElement.__init__(self, parent, mu) + + elif (all(mu[i] in NN and mu[i] >= mu[i+1] for i in range(len(mu)-1)) and mu[-1] in NN): - if 0 in mu: + if mu[-1] == 0: # From the above checks, the last value must be == 0 or > 0 # strip all trailing zeros - CombinatorialElement.__init__(self, parent, mu[:mu.index(0)]) + temp = len(mu) - 1 + while temp > 0 and mu[temp-1] == 0: + temp -= 1 + CombinatorialElement.__init__(self, parent, mu[:temp]) else: CombinatorialElement.__init__(self, parent, mu) diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 874163abcdf..df76569af73 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -19,6 +19,7 @@ from __future__ import division, print_function, absolute_import from sage.structure.parent import Parent +from sage.structure.element import parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets @@ -33,6 +34,7 @@ from . import permutation import functools +from sage.combinat.permutation import to_standard class RibbonTableau(SkewTableau): r""" @@ -597,27 +599,26 @@ def spin_rec(t, nexts, current, part, weight, length): sage: spin_rec(t, [[t^5], [t^4], [t^6 + t^4 + t^2]], [[[2, 2, 2, 2, 1], [0, 0, 3]], [[3, 3, 1, 1, 1], [0, 3, 0]], [[3, 3, 3], [3, 0, 0]]], sp([[3, 3, 3, 2, 1], []]), [2, 1, 1], 3) [2*t^7 + 2*t^5 + t^3] """ - from sage.combinat.words.word import Word - R = ZZ['t'] - if current == []: - return [R(0)] + if not current: + return [parent(t).zero()] tmp = [] partp = part[0].conjugate() + ell = len(partp) #compute the contribution of the ribbons added at #the current node - for perms in [current[i][1] for i in range(len(current))]: - perm = [partp[i] + len(partp) - (i + 1) - perms[i] - for i in range(len(partp))] - perm.reverse() - perm = Word(perm).standard_permutation() - tmp.append( (weight[-1]*(length-1)-perm.number_of_inversions()) ) - - if nexts != []: - return [sum([sum([t**tmp[i]*nexts[i][j] for j in range(len(nexts[i]))]) for i in range(len(tmp))])] + for val in current: + perms = val[1] + perm = [partp[i] + ell - (i + 1) - perms[i] for i in reversed(range(ell))] + perm = to_standard(perm) + tmp.append( weight[-1]*(length-1) - perm.number_of_inversions() ) + + if nexts: + return [ sum(sum(t**tval * nval for nval in nexts[i]) + for i, tval in enumerate(tmp)) ] else: - return [sum([t**tmp[i] for i in range(len(tmp))])] + return [ sum(t**val for val in tmp) ] def spin_polynomial_square(part, weight, length): @@ -644,7 +645,6 @@ def spin_polynomial_square(part, weight, length): 3*t^18 + 5*t^16 + 9*t^14 + 6*t^12 + 3*t^10 """ R = ZZ['t'] - t = R.gen() if part in _Partitions: part = SkewPartition([part,_Partitions([])]) @@ -652,8 +652,9 @@ def spin_polynomial_square(part, weight, length): part = SkewPartition(part) if part == [[],[]] and weight == []: - return t.parent()(1) + return R.one() + t = R.gen() return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec,t))[0]) def spin_polynomial(part, weight, length): @@ -680,10 +681,10 @@ def spin_polynomial(part, weight, length): 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR - sp = spin_polynomial_square(part,weight,length) + sp = spin_polynomial_square(part, weight, length) t = SR.var('t') - c = sp.coefficients(sparse=False) - return sum([c[i]*t**(QQ(i)/2) for i in range(len(c))]) + coeffs = sp.list() + return sum(c * t**(QQ(i)/2) for i,c in enumerate(coeffs)) def cospin_polynomial(part, weight, length): """ @@ -709,20 +710,18 @@ def cospin_polynomial(part, weight, length): 3*t^4 + 6*t^3 + 9*t^2 + 5*t + 3 """ R = ZZ['t'] - t = R.gen() # The power in the spin polynomial are all half integers # or all integers. Manipulation of expressions need to # separate cases sp = spin_polynomial_square(part, weight, length) if sp == 0: - return R(0) - - coeffs = [c for c in sp.coefficients(sparse=False) if c != 0] - d = len(coeffs)-1 - exponents = [d-e for e in range(len(coeffs))] + return R.zero() - return R(sum([ coeffs[i]*t**exponents[i] for i in range(len(coeffs))])) + coeffs = [c for c in sp.list() if c != 0] + d = len(coeffs) - 1 + t = R.gen() + return R( sum(c * t**(d-i) for i,c in enumerate(coeffs)) ) ## ////////////////////////////////////////////////////////////////////////////////////////// @@ -753,6 +752,9 @@ def graph_implementation_rec(skp, weight, length, function): weight = [] partp = skp[0].conjugate() + ell = len(partp) + outer = skp[1] + outer_len = len(outer) ## Some tests in order to know if the shape and the weight are compatible. if weight != [] and weight[-1] <= len(partp): @@ -763,22 +765,22 @@ def graph_implementation_rec(skp, weight, length, function): selection = [] for j in range(len(perms)): - retire = [(partp[i]+ len(partp) - (i+1) - perms[j][i]) for i in range(len(partp))] + retire = [(val + ell - (i+1) - perms[j][i]) for i,val in enumerate(partp)] retire.sort(reverse=True) - retire = [ retire[i] - len(partp) + (i+1) for i in range(len(retire))] + retire = [val - ell + (i+1) for i,val in enumerate(retire)] - if retire[-1] >= 0 and retire == [i for i in reversed(sorted(retire))]: - retire = Partition([x for x in retire if x != 0]).conjugate() + if retire[-1] >= 0 and retire == sorted(retire, reverse=True): + retire = Partition(retire).conjugate() # Cutting branches if the retired partition has a line strictly included into the inner one - append = True - padded_retire = retire + [0]*(len(skp[1])-len(retire)) - for k in range(len(skp[1])): - if padded_retire[k] - skp[1][k] < 0: - append = False - break - if append: - selection.append([retire, perms[j]]) + if len(retire) >= outer_len: + append = True + for k in range(outer_len): + if retire[k] - outer[k] < 0: + append = False + break + if append: + selection.append([retire, perms[j]]) #selection contains the list of current nodes @@ -787,10 +789,10 @@ def graph_implementation_rec(skp, weight, length, function): else: #The recursive calls permit us to construct the list of the sons #of all current nodes in selection - a = [graph_implementation_rec([p[0], skp[1]], weight[:-1], length, function) for p in selection] + a = [graph_implementation_rec([p[0], outer], weight[:-1], length, function) + for p in selection] return function(a, selection, skp, weight, length) - ############################################################## diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index e3c52459519..5306e57e69a 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -35,7 +35,7 @@ import sage.combinat.ribbon_tableau as ribbon_tableau import sage.combinat.skew_partition from sage.rings.all import ZZ -import sage.combinat.partition +from sage.combinat.partition import Partition, Partitions, _Partitions from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom from sage.rings.rational_field import QQ @@ -247,22 +247,22 @@ def _llt_generic(self, skp, stat): sage: L3._llt_generic([[[2,2],[1]],[[2,1],[]]],f) m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1] + m[4] """ - if skp in sage.combinat.partition.Partitions(): + if skp in _Partitions: m = (sum(skp) / self.level()).floor() if m == 0: raise ValueError("level (%=) must divide %s "%(sum(skp), self.level())) - mu = sage.combinat.partition.Partitions( ZZ(sum(skp) / self.level()) ) + mu = Partitions( ZZ(sum(skp) / self.level()) ) elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions(): #skp is a list of skew partitions - skp2 = [sage.combinat.partition.Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] - skp2 += [sage.combinat.partition.Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] - mu = sage.combinat.partition.Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) + skp2 = [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] + skp2 += [Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] + mu = Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) skp = skp2 - elif isinstance(skp, list) and skp[0] in sage.combinat.partition.Partitions(): + elif isinstance(skp, list) and skp[0] in _Partitions: #skp is a list of partitions - skp = sage.combinat.partition.Partition(core=[], quotient=skp) - mu = sage.combinat.partition.Partitions( ZZ(sum(skp) / self.level() )) + skp = Partition(core=[], quotient=skp) + mu = Partitions( ZZ(sum(skp) / self.level()) ) else: raise ValueError("LLT polynomials not defined for %s"%skp) From a39304999445235c45d63298644c9dc7ecfd7a40 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 8 Oct 2017 02:52:03 -0500 Subject: [PATCH 203/218] Fixing output of case of integer_matrices_generator. --- src/sage/combinat/integer_matrices.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/integer_matrices.py b/src/sage/combinat/integer_matrices.py index af0a156cd7b..88287488fed 100644 --- a/src/sage/combinat/integer_matrices.py +++ b/src/sage/combinat/integer_matrices.py @@ -322,6 +322,7 @@ def integer_matrices_generator(row_sums, column_sums): [[0, 3], [1, 1], [1, 1]] [[0, 3], [0, 2], [2, 0]] """ + column_sums = list(column_sums) if sum(row_sums) != sum(column_sums): raise StopIteration if not row_sums: @@ -329,7 +330,7 @@ def integer_matrices_generator(row_sums, column_sums): elif len(row_sums) == 1: yield [column_sums] else: - I = IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=list(column_sums)) + I = IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=column_sums) for comp in I.backend._iter(): t = [column_sums[i]-ci for (i, ci) in enumerate(comp)] for mat in integer_matrices_generator(row_sums[1:], t): From ea6a00ba4750d97546755784041b5d3cee2f2de9 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 9 Oct 2017 09:50:51 +0200 Subject: [PATCH 204/218] Added a doctest for pickling. --- src/sage/modules/fg_pid/fgp_module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 483daf15ba7..d665f974fd6 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -310,6 +310,18 @@ class FGP_Module_class(Module): Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) + + TESTS:: + + Make sure that the problems in + http://trac.sagemath.org/sage_trac/ticket/7516 are fixed:: + + sage: V = FreeModule(QQ, 2) + sage: W = V.submodule([V([1,1])]) + sage: Z = W.submodule([]) + sage: WmodZ = W / Z + sage: loads(dumps(WmodZ))==WmodZ + True """ # The class to be used for creating elements of this From 4a31dbf28cc3b64beea87d09106f6824d5ea092d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 9 Oct 2017 14:05:46 +0200 Subject: [PATCH 205/218] Upgrade rst2ipynb to version 0.2.2 and check pandoc dependency --- build/pkgs/rst2ipynb/checksums.ini | 6 +- build/pkgs/rst2ipynb/package-version.txt | 2 +- .../pkgs/rst2ipynb/patches/check-pandoc.patch | 58 +++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 build/pkgs/rst2ipynb/patches/check-pandoc.patch diff --git a/build/pkgs/rst2ipynb/checksums.ini b/build/pkgs/rst2ipynb/checksums.ini index f59f4b55950..a9b05c6a268 100644 --- a/build/pkgs/rst2ipynb/checksums.ini +++ b/build/pkgs/rst2ipynb/checksums.ini @@ -1,4 +1,4 @@ tarball=rst2ipynb-VERSION.tar.gz -sha1=660df59d66a052a9337517ed55e018307d3549ce -md5=8d85aa294c25ccaf3bb080bc6eb50e59 -cksum=1127236178 +sha1=3c90b88061b436c54da5f960fa191892dfef709f +md5=100596c9eed3e22483e86061a88722db +cksum=4025690464 diff --git a/build/pkgs/rst2ipynb/package-version.txt b/build/pkgs/rst2ipynb/package-version.txt index 0c62199f16a..e31ae824d82 100644 --- a/build/pkgs/rst2ipynb/package-version.txt +++ b/build/pkgs/rst2ipynb/package-version.txt @@ -1 +1 @@ -0.2.1 +0.2.2.p0 diff --git a/build/pkgs/rst2ipynb/patches/check-pandoc.patch b/build/pkgs/rst2ipynb/patches/check-pandoc.patch new file mode 100644 index 00000000000..72e0b7bb5e1 --- /dev/null +++ b/build/pkgs/rst2ipynb/patches/check-pandoc.patch @@ -0,0 +1,58 @@ +See https://github.com/nthiery/rst-to-ipynb/pull/4 + +commit 08fbca3f57607f49bd40e9254106aecc1ac0dbe7 +Author: Jeroen Demeyer +Date: Mon Oct 9 12:38:19 2017 +0200 + + Check pandoc dependency + +diff --git a/setup.py b/setup.py +index e2e2ed3..5afaa33 100644 +--- a/setup.py ++++ b/setup.py +@@ -4,17 +4,35 @@ reST to Jupyter notebook converter + """ + + # Always prefer setuptools over distutils +-from setuptools import setup, find_packages ++from setuptools import setup ++from setuptools.command.install import install ++from distutils.errors import DistutilsExecError + # To use a consistent encoding + from codecs import open +-from os import path ++import os + +-here = path.abspath(path.dirname(__file__)) ++ ++here = os.path.dirname(__file__) + + # Get the long description from the README file +-with open(path.join(here, 'README.rst'), encoding='utf-8') as f: ++with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + ++ ++class check_install(install): ++ "Check that pandoc is installed on the system" ++ def run(self): ++ import subprocess ++ try: ++ # Hide stdout but allow stderr ++ subprocess.check_call(["pandoc", "-v"], stdout=open(os.devnull)) ++ except subprocess.CalledProcessError: ++ raise DistutilsExecError("rst2ipynb requires the Haskell program 'pandoc'. It seems to be installed, but it did not work properly.") ++ except OSError: ++ raise DistutilsExecError("rst2ipynb requires the Haskell program 'pandoc'. You need to install it on your system.") ++ install.run(self) ++ ++ + setup( + name='rst2ipynb', + version='0.2.2', +@@ -35,4 +53,5 @@ setup( + install_requires=['notedown', 'pandocfilters'], + #setup_requires=['pytest-runner'], + #tests_require=['pytest'], ++ cmdclass=dict(install=check_install) + ) From 8b4b3052f340736fbf551f6ae45cfb53a0492bce Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 9 Oct 2017 14:48:36 +0200 Subject: [PATCH 206/218] Sage package version should override pip package version --- src/sage/misc/package.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index e7b96d40353..6242d2d357a 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -281,11 +281,14 @@ def installed_packages(exclude_pip=True): :func:`sage.misc.package.list_packages` """ from sage.env import SAGE_SPKG_INST - installed = dict(pkgname_split(pkgname) for pkgname in os.listdir(SAGE_SPKG_INST)) + installed = {} if not exclude_pip: installed.update(pip_installed_packages()) + # Sage packages should override pip packages (Trac #23997) + installed.update(pkgname_split(pkgname) for pkgname in os.listdir(SAGE_SPKG_INST)) return installed + def is_package_installed(package, exclude_pip=True): """ Return whether (any version of) ``package`` is installed. From 13a60ea63818302d376a1aa44fbb6faf4f4e28f3 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 7 Oct 2017 14:23:12 +0200 Subject: [PATCH 207/218] Check for Graphviz dependency when installing dot2tex --- build/pkgs/dot2tex/package-version.txt | 2 +- build/pkgs/dot2tex/spkg-install | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/build/pkgs/dot2tex/package-version.txt b/build/pkgs/dot2tex/package-version.txt index 98a37394aba..4f194b20925 100644 --- a/build/pkgs/dot2tex/package-version.txt +++ b/build/pkgs/dot2tex/package-version.txt @@ -1 +1 @@ -2.9.0.p1 +2.9.0.p2 diff --git a/build/pkgs/dot2tex/spkg-install b/build/pkgs/dot2tex/spkg-install index 3a313a75ccc..8bf68e410e8 100644 --- a/build/pkgs/dot2tex/spkg-install +++ b/build/pkgs/dot2tex/spkg-install @@ -6,8 +6,15 @@ fi cd src -$PIP_INSTALL . +# Check that Graphviz is installed by running dot2tex from the source +# directory. +python -c "import sys; from dot2tex.dotparsing import find_graphviz; sys.exit(0 if find_graphviz() else 1)" +if [ $? -ne 0 ]; then + echo >&2 "Error: dot2tex requires Graphviz but Graphviz is not installed. You can download Graphviz at http://www.graphviz.org/Download..php" + exit 1 +fi +$PIP_INSTALL . if [ $? -ne 0 ]; then echo >&2 "Error installing dot2tex." exit 1 From 13d60a14be741a37edb5641f0f54f378a1097baa Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 10 Oct 2017 13:20:39 +0200 Subject: [PATCH 208/218] Support xz compressed tarballs --- build/sage_bootstrap/uncompress/action.py | 4 +- build/sage_bootstrap/uncompress/tar_file.py | 66 ++++++++++++++------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/build/sage_bootstrap/uncompress/action.py b/build/sage_bootstrap/uncompress/action.py index fef21579b33..bc265edafa6 100644 --- a/build/sage_bootstrap/uncompress/action.py +++ b/build/sage_bootstrap/uncompress/action.py @@ -15,11 +15,11 @@ import os -from sage_bootstrap.uncompress.tar_file import SageTarFile +from sage_bootstrap.uncompress.tar_file import SageTarFile, SageTarXZFile from sage_bootstrap.uncompress.zip_file import SageZipFile from sage_bootstrap.util import retry -ARCHIVE_TYPES = [SageTarFile, SageZipFile] +ARCHIVE_TYPES = [SageTarFile, SageZipFile, SageTarXZFile] diff --git a/build/sage_bootstrap/uncompress/tar_file.py b/build/sage_bootstrap/uncompress/tar_file.py index b13a03f4936..e4fc6eb1b22 100644 --- a/build/sage_bootstrap/uncompress/tar_file.py +++ b/build/sage_bootstrap/uncompress/tar_file.py @@ -18,11 +18,13 @@ import copy import tarfile import stat +import subprocess +from io import BytesIO from sage_bootstrap.uncompress.filter_os_files import filter_os_files -class SageTarFile(tarfile.TarFile): +class SageBaseTarFile(tarfile.TarFile): """ Sage as tarfile.TarFile, but applies the user's current umask to the permissions of all extracted files and directories. @@ -31,29 +33,13 @@ class SageTarFile(tarfile.TarFile): See http://trac.sagemath.org/ticket/20218#comment:16 for more background. """ - - def __new__(cls, *args, **kwargs): - # This is is that SageTarFile() is equivalent to TarFile.open() which - # is more flexible than the basic TarFile.__init__ - inst = tarfile.TarFile.open(*args, **kwargs) - inst.__class__ = cls - return inst - def __init__(self, *args, **kwargs): # Unfortunately the only way to get the current umask is to set it # and then restore it + super(SageBaseTarFile, self).__init__(*args, **kwargs) self.umask = os.umask(0o777) os.umask(self.umask) - @classmethod - def can_read(cls, filename): - """ - Given an archive filename, returns True if this class can read and - process the archive format of that file. - """ - - return tarfile.is_tarfile(filename) - @property def names(self): """ @@ -69,7 +55,7 @@ def chmod(self, tarinfo, target): tarinfo = copy.copy(tarinfo) tarinfo.mode &= ~self.umask tarinfo.mode &= ~(stat.S_ISUID | stat.S_ISGID) - return super(SageTarFile, self).chmod(tarinfo, target) + return super(SageBaseTarFile, self).chmod(tarinfo, target) def extractall(self, path='.', members=None): """ @@ -81,7 +67,7 @@ def extractall(self, path='.', members=None): members = [m if isinstance(m, tarfile.TarInfo) else name_to_member[m] for m in members] - return super(SageTarFile, self).extractall(path=path, members=members) + return super(SageBaseTarFile, self).extractall(path=path, members=members) def extractbytes(self, member): """ @@ -95,3 +81,43 @@ def extractbytes(self, member): return reader.read() +class SageTarFile(SageBaseTarFile): + """ + A wrapper around SageBaseTarFile such that SageTarFile(filename) is + essentially equivalent to TarFile.open(filename) which is more + flexible than the basic TarFile.__init__ + """ + def __new__(cls, filename): + return SageBaseTarFile.open(filename) + + @staticmethod + def can_read(filename): + """ + Given an archive filename, returns True if this class can read and + process the archive format of that file. + """ + return tarfile.is_tarfile(filename) + + +class SageTarXZFile(SageBaseTarFile): + """ + A ``.tar.xz`` file which is uncompressed in memory. + """ + def __new__(cls, filename): + # Read uncompressed data through a pipe + proc = subprocess.Popen(["xz", "-d", "-c", filename], stdout=subprocess.PIPE) + data, _ = proc.communicate() + return SageBaseTarFile(mode="r", fileobj=BytesIO(data)) + + @staticmethod + def can_read(filename): + """ + Given an archive filename, returns True if this class can read and + process the archive format of that file. + """ + devnull = open(os.devnull, 'w') + try: + subprocess.check_call(["xz", "-l", filename], stdout=devnull, stderr=devnull) + except Exception: + return False + return True From 188ed32783282e72f3e76393a4b049576c0dfc67 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Tue, 10 Oct 2017 17:23:02 +0200 Subject: [PATCH 209/218] Enable munmap/mmap on Cygwin, but fix issues with its implementation on Cygwin; see https://trac.sagemath.org/ticket/23973 --- ...rotect-instead-of-mmap-to-set-PROT_N.patch | 75 +++++++++++++++++++ build/pkgs/gc/spkg-install | 2 + 2 files changed, 77 insertions(+) create mode 100644 build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch diff --git a/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch b/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch new file mode 100644 index 00000000000..3161874f9fb --- /dev/null +++ b/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch @@ -0,0 +1,75 @@ +On Cygwin, use mprotect to set PROT_NONE on a memory-mapped region, instead +of trying to reuse mmap on an existing region, which breaks. Use the +allocation granularity for determining allocation sizes/offsets, rather +than the actual page size (as Cygwin itself does). See +https://trac.sagemath.org/ticket/23973 +diff --git a/os_dep.c b/os_dep.c +index e6283ac..a1bb9e4 100644 +--- a/os_dep.c ++++ b/os_dep.c +@@ -698,7 +698,11 @@ GC_INNER word GC_page_size = 0; + GC_INNER void GC_setpagesize(void) + { + GetSystemInfo(&GC_sysinfo); +- GC_page_size = GC_sysinfo.dwPageSize; ++# if defined(CYGWIN32) && defined(USE_MUNMAP) ++ GC_page_size = GC_sysinfo.dwAllocationGranularity; ++# else ++ GC_page_size = GC_sysinfo.dwPageSize; ++# endif + # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION) + { + OSVERSIONINFO verInfo; +@@ -2404,12 +2408,18 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes) + /* We immediately remap it to prevent an intervening mmap from */ + /* accidentally grabbing the same address space. */ + { +- void * result; +- result = mmap(start_addr, len, PROT_NONE, +- MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, +- zero_fd, 0/* offset */); +- if (result != (void *)start_addr) +- ABORT("mmap(PROT_NONE) failed"); ++# ifdef CYGWIN32 ++ if (mprotect(start_addr, len, PROT_NONE)) ++ ABORT("mprotect(PROT_NONE) failed"); ++# else ++ void * result; ++ ++ result = mmap(start_addr, len, PROT_NONE, ++ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, ++ zero_fd, 0/* offset */); ++ if (result != (void *)start_addr) ++ ABORT("mmap(PROT_NONE) failed"); ++# endif + } + GC_unmapped_bytes += len; + # endif +@@ -2515,13 +2525,18 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, + } + # else + if (len != 0) { ++# ifdef CYGWIN32 ++ if (mprotect(start_addr, len, PROT_NONE)) ++ ABORT("mprotect(PROT_NONE) failed"); ++# else + /* Immediately remap as above. */ +- void * result; +- result = mmap(start_addr, len, PROT_NONE, +- MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, +- zero_fd, 0/* offset */); +- if (result != (void *)start_addr) +- ABORT("mmap(PROT_NONE) failed"); ++ void * result; ++ result = mmap(start_addr, len, PROT_NONE, ++ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, ++ zero_fd, 0/* offset */); ++ if (result != (void *)start_addr) ++ ABORT("mmap(PROT_NONE) failed"); ++# endif + } + GC_unmapped_bytes += len; + # endif +-- +2.8.3 + diff --git a/build/pkgs/gc/spkg-install b/build/pkgs/gc/spkg-install index 8898abe8296..c6a955eecfc 100644 --- a/build/pkgs/gc/spkg-install +++ b/build/pkgs/gc/spkg-install @@ -22,6 +22,8 @@ CONFIGURE_FLAGS="--enable-large-config" if [ "$UNAME" = "CYGWIN" ]; then # See https://trac.sagemath.org/ticket/22694 CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-threads=posix --enable-handle-fork" + # Force use of mmap on Cygwin https://trac.sagemath.org/ticket/23973 + export CFLAGS="$CFLAGS -DUSE_MMAP -DUSE_MUNMAP" fi ./configure --prefix="$SAGE_LOCAL" --libdir="$SAGE_LOCAL/lib" $CONFIGURE_FLAGS From 54846bf4f0758636eac705a45158ee21b6482703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 10 Oct 2017 19:28:18 +0200 Subject: [PATCH 210/218] trac 23818 adding hash --- src/sage/rings/complex_interval_field.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index d9e5af767d3..c52a86b5805 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -397,6 +397,20 @@ def __eq__(self, other): return False return self._prec == other._prec + def __hash__(self): + """ + Return the hash. + + EXAMPLES:: + + sage: C = ComplexIntervalField(200) + sage: from sage.rings.complex_interval_field import ComplexIntervalField_class + sage: D = ComplexIntervalField_class(200) + sage: hash(C) == hash(D) + True + """ + return hash((self.__class__, self._prec)) + def __ne__(self, other): """ Test whether ``self`` is not equal to ``other``. From 5c878e6454fe3156fbd9c8dd3187d6a26edd6c42 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 5 Oct 2017 15:53:09 +0200 Subject: [PATCH 211/218] Upgrade eclib to version 20171002 --- build/pkgs/eclib/SPKG.txt | 19 ++++++++++++------- build/pkgs/eclib/checksums.ini | 6 +++--- build/pkgs/eclib/package-version.txt | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/build/pkgs/eclib/SPKG.txt b/build/pkgs/eclib/SPKG.txt index 1de401d1e87..dfbd7424a9b 100644 --- a/build/pkgs/eclib/SPKG.txt +++ b/build/pkgs/eclib/SPKG.txt @@ -2,9 +2,16 @@ == Description == -John Cremona's programs for enumerating and computing with elliptic -curves defined over the rational numbers. This is the culmination of -over 25 years of hard work. +mwrank is a program written in C++ for computing Mordell-Weil groups of +elliptic curves over Q via 2-descent. It is available as source code in +the eclib package, which may be distributed under the GNU General Public +License, version 2, or any later version. + +mwrank is now only distributed as part of eclib. eclib is also included +in Sage, and for most potential users the easiest way to run mwrank is +to install Sage (which also of course gives you much much more). I no +longer provide a source code distribution of mwrank by itself: use eclib +instead. == License == @@ -14,13 +21,11 @@ eclib is licensed GPL v2+. * Author: John Cremona * Email: john.cremona@gmail.com - * Website: https://github.com/JohnCremona/eclib + * Website: http://homepages.warwick.ac.uk/staff/J.E.Cremona/mwrank/index.html + * Repository: https://github.com/JohnCremona/eclib == Dependencies == * PARI * NTL * FLINT - - - diff --git a/build/pkgs/eclib/checksums.ini b/build/pkgs/eclib/checksums.ini index b0e51d59f08..4527f4291fd 100644 --- a/build/pkgs/eclib/checksums.ini +++ b/build/pkgs/eclib/checksums.ini @@ -1,4 +1,4 @@ tarball=eclib-VERSION.tar.bz2 -sha1=2527c49624bb90619b4b185c38dc6c3bc9737b38 -md5=2c0557cecb1145b7df6ddc71332b0656 -cksum=1113684095 +sha1=abd277f71416966f36eb8e1b0a814d7028c56baa +md5=2c6e90c61f49cf9c38a5c9fd9a1ebcef +cksum=1683788031 diff --git a/build/pkgs/eclib/package-version.txt b/build/pkgs/eclib/package-version.txt index 6a141b04abd..8d66f7e048f 100644 --- a/build/pkgs/eclib/package-version.txt +++ b/build/pkgs/eclib/package-version.txt @@ -1 +1 @@ -20170330 +20171002 From 5863356b68e1796ea3c6d92391753a6bfbc93ca7 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Wed, 11 Oct 2017 15:27:37 +0200 Subject: [PATCH 212/218] Updated patch level --- build/pkgs/gc/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/gc/package-version.txt b/build/pkgs/gc/package-version.txt index a940330e279..e67c9d21592 100644 --- a/build/pkgs/gc/package-version.txt +++ b/build/pkgs/gc/package-version.txt @@ -1 +1 @@ -7.2f.p0 +7.2f.p1 From 90507bf5507a26be255a4a231f5b608d7d2efa8e Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Thu, 12 Oct 2017 10:00:34 +0000 Subject: [PATCH 213/218] Only catch exception from setrlimit on Cygwin --- src/bin/sage-runtests | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index fd855baac4a..7fd45c07faf 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -109,7 +109,11 @@ if __name__ == "__main__": try: resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) except ValueError: - pass + if sys.platform != 'cygwin': + # RLIMIT_AS is not currently supported on Cygwin so + # this will probably fail there: + # https://trac.sagemath.org/ticket/23979 + raise # Limit the number of OMP threads to 2 to save system resources # See Trac #23892 From 5c0f24267f924ae62a7090b5c226c4584ab7b7a9 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Thu, 12 Oct 2017 15:01:12 +0200 Subject: [PATCH 214/218] Using 'TEMP' for this test is broken if the TEMP environment variable is set --- src/sage/env.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 6135c67c0de..b002e0ba44c 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -71,8 +71,8 @@ def _add_variable_or_fallback(key, fallback, force=False): Test that :trac:`23758` has been resolved:: sage: sage.env._add_variable_or_fallback('SAGE_BA', '---hello---') - sage: sage.env._add_variable_or_fallback('TEMP', '$SAGE_BAR') - sage: sage.env.SAGE_ENV['TEMP'] + sage: sage.env._add_variable_or_fallback('SAGE_QUX', '$SAGE_BAR') + sage: sage.env.SAGE_ENV['SAGE_QUX'] '---foo---' """ global SAGE_ENV From e3ef69e701c55e6fa3ef565c6472fcf08065834f Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Thu, 12 Oct 2017 15:15:02 +0200 Subject: [PATCH 215/218] Add some small tolerance to these tests to account for numerical differences on Cygwin --- src/sage/misc/functional.py | 2 +- src/sage/symbolic/expression.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index afc3b146984..ba518eb395d 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -983,7 +983,7 @@ def log(x, b=None): 4 sage: log(3.) 1.09861228866811 - sage: log(float(3)) + sage: log(float(3)) # abs tol 1e-15 1.0986122886681098 """ deprecation(19444, 'use .log() or log() from sage.functions.log instead') diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 8e04431ea17..f0d7ef111ab 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1180,7 +1180,7 @@ cdef class Expression(CommutativeRingElement): -3.00000000000000 sage: cos(I)._eval_self(RR) 1.54308063481524 - sage: float(cos(I)) + sage: float(cos(I)) # abs tol 1e-15 1.5430806348152437 TESTS:: From fb3c27813e7f275f203e6665a4e5be224d343b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 13 Oct 2017 21:33:11 +0200 Subject: [PATCH 216/218] trac 20762 code and doc cleanup --- src/sage/homology/simplicial_complex.py | 119 +++++++++++++----------- 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index aecbc6af0c7..9ef5783a6f2 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -4361,7 +4361,7 @@ def cone_vertices(self): r""" Return the list of cone vertices of ``self``. - A vertex is a cone vertex iff it appears in every facet. + A vertex is a cone vertex if and only if it appears in every facet. EXAMPLES:: @@ -4378,7 +4378,7 @@ def cone_vertices(self): C = C.intersection(list(f)) if not C: break - return sorted(list(C)) + return sorted(C) def decone(self): r""" @@ -4391,7 +4391,7 @@ def decone(self): sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).decone() Simplicial complex with vertex set (2, 3, 4, 5, 6) and facets {(3, 4), (2, 3), (5, 6)} sage: X = SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]) - sage: X.decone()==X + sage: X.decone() == X True """ V = set(self.vertices()).difference(self.cone_vertices()) @@ -4399,25 +4399,28 @@ def decone(self): def is_balanced(self, check_purity=False, certificate=False): r""" - Determines whether ``self`` is balanced. + Determine whether ``self`` is balanced. - A simplicial complex `X` of dimension `d-1` is balanced iff its vertices - can be colored with `d` colors such that every face contains at most one - vertex of each color. An equivalent condition is that the 1-skeleton of - `X` is `d`-colorable. In some contexts, it is also required that `X` be - pure (i.e., that all maximal faces of `X` have the same dimension). + A simplicial complex `X` of dimension `d-1` is balanced if and + only if its vertices can be colored with `d` colors such that + every face contains at most one vertex of each color. An + equivalent condition is that the 1-skeleton of `X` is + `d`-colorable. In some contexts, it is also required that `X` + be pure (i.e., that all maximal faces of `X` have the same + dimension). INPUT: - - ``check_purity`` -- (default: False) if this is True, require that - ``self`` be pure as well as balanced + - ``check_purity`` -- (default: ``False``) if this is ``True``, + require that ``self`` be pure as well as balanced - - ``certificate`` -- (default: False) if this is True and ``self`` is - balanced, then return a `d`-coloring of the 1-skeleton. + - ``certificate`` -- (default: ``False``) if this is ``True`` and + ``self`` is balanced, then return a `d`-coloring of the 1-skeleton. - EXAMPLES:: + EXAMPLES: + + A 1-dim simplicial complex is balanced iff it is bipartite:: - # A 1-dim simplicial complex is balanced iff it is bipartite sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,5]]) sage: X.is_balanced() True @@ -4427,64 +4430,70 @@ def is_balanced(self, check_purity=False, certificate=False): sage: X.is_balanced() False - # Any barycentric division is balanced + Any barycentric division is balanced:: + sage: X = SimplicialComplex([[1,2,3],[1,2,4],[2,3,4]]) sage: X.is_balanced() False sage: X.barycentric_subdivision().is_balanced() True - # A non-pure balanced complex + A non-pure balanced complex:: + sage: X=SimplicialComplex([[1,2,3],[3,4]]) sage: X.is_balanced(check_purity=True) False sage: X.is_balanced(certificate=True) [[2], [1, 4], [3]] """ - d = 1+self.dimension() + d = 1 + self.dimension() if check_purity and not self.is_pure(): return False Skel = self.graph() if certificate: C = Skel.coloring() - C = C if len(C)==d else False + C = C if len(C) == d else False return C else: - ch = Skel.chromatic_number() - return ch==d + return Skel.chromatic_number() == d def is_partitionable(self, certificate=False): r""" - Determines whether ``self`` is partitionable. + Determine whether ``self`` is partitionable. + + A partitioning of a simplicial complex `X` is a decomposition + of its face poset into disjoint Boolean intervals `[R,F]`, + where `F` ranges over all facets of `X`. + + The method sets up an integer program with: + + - a variable `y_i` for each pair `(R,F)`, where `F` is a facet of `X` + and `R` is a subface of `F` - A partitioning of a simplicial complex `X` is a decomposition of its face - poset into disjoint Boolean intervals `[R,F]`, where `F` ranges over all - facets of `X`. + - a constraint `y_i+y_j \leq 1` for each pair `(R_i,F_i)`, `(R_j,F_j)` + whose Boolean intervals intersect nontrivially (equivalent to + `(R_i\subseteq F_j and R_j\subseteq F_i))` - The method sets up an integer program with - - a variable `y_i` for each pair `(R,F)`, where `F` is a facet of `X` - and `R` is a subface of `F` - - a constraint `y_i+y_j \leq 1` for each pair `(R_i,F_i)`, `(R_j,F_j)` - whose Boolean intervals intersect nontrivially (equivalent to - `(R_i\subseteq F_j and R_j\subseteq F_i))` - - objective function equal to the sum of all `y_i` + - objective function equal to the sum of all `y_i` - INPUT: + INPUT: + + - ``certificate`` -- (default: ``False``) If ``True``, + and ``self`` is partitionable, then return a list of pairs `(R,F)` + that form a partitioning. - - ``certificate`` -- (default: False) If True, and ``self`` is - partitionable, then return a list of pairs `(R,F)` that form - a partitioning. + EXAMPLES: - EXAMPLES:: + Simplices are trivially partitionable:: - # Simplices are trivially partitionable sage: X = SimplicialComplex([ [1,2,3,4] ]) sage: X.is_partitionable() True sage: X.is_partitionable(certificate=True) [((), (1, 2, 3, 4), 4)] - # Shellable complexes are partitionable + Shellable complexes are partitionable:: + sage: X = SimplicialComplex([ [1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5] ]) sage: X.is_partitionable() True @@ -4493,36 +4502,39 @@ def is_partitionable(self, certificate=False): sage: all( n_intervals_containing(f)==1 for k in X.faces().keys() for f in X.faces()[k] ) True - # A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Björner + A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Björner:: + sage: X = SimplicialComplex([ [1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,5,6] ]) sage: X.is_partitionable() True - # The bowtie complex is not partitionable + The bowtie complex is not partitionable:: + sage: X = SimplicialComplex([ [1,2,3],[1,4,5] ]) sage: X.is_partitionable() False """ from sage.numerical.mip import MixedIntegerLinearProgram Facets = self.facets() - RFPairs = [(Simplex(r),f,f.dimension()-len(r)+1) for f in self.facets() for r in Set(f).subsets()] + RFPairs = [(Simplex(r), f, f.dimension() - len(r) + 1) + for f in self.facets() for r in Set(f).subsets()] n = len(RFPairs) IP = MixedIntegerLinearProgram() y = IP.new_variable(binary=True) - for i0,pair0 in enumerate(RFPairs): - for i1,pair1 in enumerate(RFPairs): - if i0 Date: Sat, 14 Oct 2017 12:48:14 +0200 Subject: [PATCH 217/218] Mark one Cython test # random due to compiler warnings --- src/sage/libs/pynac/pynac.pxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/pynac/pynac.pxd b/src/sage/libs/pynac/pynac.pxd index 32361e785bb..f811466f956 100644 --- a/src/sage/libs/pynac/pynac.pxd +++ b/src/sage/libs/pynac/pynac.pxd @@ -7,7 +7,7 @@ Declarations for pynac, a Python frontend for ginac Check that we can externally cimport this (:trac:`18825`):: - sage: cython( # long time + sage: cython( # long time; random compiler warnings ....: ''' ....: #clang c++ ....: #clib pynac From a2e82e15a240f1e095c100d8cdb0f928373c6a68 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 17 Oct 2017 01:59:16 +0200 Subject: [PATCH 218/218] Updated SageMath version to 8.1.beta8 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 2 +- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 4859548c745..f2eb6594da5 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 8.1.beta7, Release Date: 2017-10-03 +SageMath version 8.1.beta8, Release Date: 2017-10-16 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 6a1829af070..b1bf07ff452 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=c0925b13727bea3cd55b1e257858f1efaebef736 -md5=47e2e7f83aa4a91552144e7637d5233b -cksum=613456504 +sha1=e3d622d2a2bb2269a80d329b24a8eb42482831fe +md5=66684bb9389e7d030bd6e16fd114ba29 +cksum=2091457177 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index b4249c475b8..eb08bc0b0bc 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -239 +240 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index d0195817910..95e8263b802 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath version 8.1.beta7, Release Date: 2017-10-03 │ +│ SageMath version 8.1.beta8, Release Date: 2017-10-16 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 4efafd3f623..9bcde786eb3 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='8.1.beta7' -SAGE_RELEASE_DATE='2017-10-03' +SAGE_VERSION='8.1.beta8' +SAGE_RELEASE_DATE='2017-10-16' diff --git a/src/sage/version.py b/src/sage/version.py index aaec001d8c5..b74807859b3 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '8.1.beta7' -date = '2017-10-03' +version = '8.1.beta8' +date = '2017-10-16'