def im_gens(self): r""" Return the images of the generators under this map. EXAMPLES:: sage: K.<a, b> = NumberField( [x^3 + 2, x^2 + x + 1] ) sage: K.hom(a, K).im_gens() [a, b] """ try: return self.__im_gens except AttributeError: pass D = self.domain() C = self.codomain() v = Sequence([self(x) for x in D.gens()], universe=C, check=False, immutable=True) self.__im_gens = v return v
def atkin_lehner_eigenvalue_numerical(self, t): (tau1, z, tau2) = t from sage.libs.mpmath import mp from sage.libs.mpmath.mp import exp, pi from sage.libs.mpmath.mp import j as i if not Integer(self.__level()).is_prime(): raise ValueError( "The Atkin Lehner involution is only unique if the level is a prime" ) precision = ParamodularFormD2Filter_trace(self.precision()) s = Sequence([tau1, z, tau2]) if not is_ComplexField(s): mp_precision = 30 else: mp_precision = ceil(3.33 * s.universe().precision()) mp.dps = mp_precision (tau1, z, tau2) = tuple(s) (tau1p, zp, tau2p) = (self.level() * tau1, self.level() * z, self.level() * tau2) (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2)) (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p)) self_value = s.universe().zero() trans_value = s.universe().zero() for k in precision: (a, b, c) = apply_GL_to_form(self._P1List()(k[1]), k[0]) self_value = self_value + self[k] * (e_tau1**a * e_z**b * e_tau2**c) trans_value = trans_value + self[k] * (e_tau1p**a * e_zp**b * e_tau2p**c) return trans_value / self_value
def list(self): """ Return a list of all the elements of self (for which the domain is a relative number field). EXAMPLES:: sage: K.<a, b> = NumberField([x^2 + x + 1, x^3 + 2]) sage: End(K).list() [ Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field Defn: a |--> a b |--> b, ... Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field Defn: a |--> a b |--> -b*a - b ] An example with an absolute codomain:: sage: K.<a, b> = NumberField([x^2 - 3, x^2 + 2]) sage: Hom(K, CyclotomicField(24, 'z')).list() [ Relative number field morphism: From: Number Field in a with defining polynomial x^2 - 3 over its base field To: Cyclotomic Field of order 24 and degree 8 Defn: a |--> z^6 - 2*z^2 b |--> -z^5 - z^3 + z, ... Relative number field morphism: From: Number Field in a with defining polynomial x^2 - 3 over its base field To: Cyclotomic Field of order 24 and degree 8 Defn: a |--> -z^6 + 2*z^2 b |--> z^5 + z^3 - z ] """ D = self.domain() C = self.codomain() D_abs = D.absolute_field('a') v = [self(f, check=False) for f in D_abs.Hom(C).list()] return Sequence(v, universe=self, check=False, immutable=True, cr=v!=[])
def list(self): """ Return a list of all the elements of self (for which the domain is a cyclotomic field). EXAMPLES:: sage: K.<z> = CyclotomicField(12) sage: G = End(K); G Automorphism group of Cyclotomic Field of order 12 and degree 4 sage: [g(z) for g in G] [z, z^3 - z, -z, -z^3 + z] sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1]) sage: L Number Field in a with defining polynomial x^2 + x + 1 over its base field sage: Hom(CyclotomicField(12), L)[3] Ring morphism: From: Cyclotomic Field of order 12 and degree 4 To: Number Field in a with defining polynomial x^2 + x + 1 over its base field Defn: zeta12 |--> -b^2*a sage: list(Hom(CyclotomicField(5), K)) [] sage: Hom(CyclotomicField(11), L).list() [] """ D = self.domain() C = self.codomain() z = D.gen() n = z.multiplicative_order() if not n.divides(C.zeta_order()): v = [] else: if D == C: w = z else: w = C.zeta(n) v = [self([w**k], check=False) for k in Zmod(n) if k.is_unit()] return Sequence(v, universe=self, check=False, immutable=True, cr=v != [])
def lcm(self, other): r""" Return the lcm of two factorizations. If the two factorizations have different universes, this method will attempt to find a common universe for the lcm. A TypeError is raised if this is impossible. EXAMPLES:: sage: factor(-10).lcm(factor(-16)) 2^4 * 5 sage: factor(lcm(-10,16)) 2^4 * 5 sage: R.<x> = ZZ[] sage: (factor(-20).lcm(factor(5*x+10))).universe() Univariate Polynomial Ring in x over Integer Ring """ if not isinstance(other, Factorization): raise NotImplementedError, "can't take lcm of factorization and non-factorization" if len(self) and len(other): try: # first get the two factorizations to have the same # universe U = Sequence([self[0][0], other[0][0]]).universe() self = self.base_change(U) other = other.base_change(U) except TypeError: raise TypeError, "Cannot take the lcm of %s and %s because they cannot be coerced into a common universe" % ( self, other) if self.is_commutative() and other.is_commutative(): d1 = dict(self) d2 = dict(other) s = {} for a in set(d1.keys()).union(set(d2.keys())): s[a] = max(d1.get(a, 0), d2.get(a, 0)) return Factorization(list(s.iteritems())) else: raise NotImplementedError, "lcm is not implemented for non-commutative factorizations"
def __init__(self, L, index_object): r""" \code{index_object} must be a Sage object with an _iter_ method containing the same number of elements as self, which is a list of elements taken from a field. EXAMPLES: sage: J = range(10) sage: A = [1/10 for j in J] sage: s = IndexedSequence(A,J) sage: s Indexed sequence: [1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10] indexed by [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: s.dict() {0: 1/10, 1: 1/10, 2: 1/10, 3: 1/10, 4: 1/10, 5: 1/10, 6: 1/10, 7: 1/10, 8: 1/10, 9: 1/10} sage: s.list() [1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10] sage: s.index_object() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: s.base_ring() Rational Field """ try: ind = index_object.list() except AttributeError: ind = list(index_object) self._index_object = index_object self._list = Sequence(L) self._base_ring = self._list.universe() dict = {} for i in range(len(ind)): dict[ind[i]] = L[i] self._dict = dict
def automorphisms(self): r""" Return all Galois automorphisms of ``self``. OUTPUT: - a sequence containing just the identity morphism EXAMPLES:: sage: QQ.automorphisms() [ Ring endomorphism of Rational Field Defn: 1 |--> 1 ] """ return Sequence([self.hom(1, self)], cr=True, immutable=False, check=False)
def interreduced_basis(self): """ A fully symmetrically reduced generating set (type :class:`~sage.structure.sequence.Sequence`) of self. This does essentially the same as :meth:`interreduction` with the option 'tailreduce', but it returns a :class:`~sage.structure.sequence.Sequence` rather than a :class:`~sage.rings.polynomial.symmetric_ideal.SymmetricIdeal`. EXAMPLES:: sage: X.<x> = InfinitePolynomialRing(QQ) sage: I=X*(x[1]+x[2],x[1]*x[2]) sage: I.interreduced_basis() [-x_1^2, x_2 + x_1] """ return Sequence(self.interreduction(tailreduce=True).gens(), self.ring(), check=False)
def __init__(self, L, index_object): r""" Initialize ``self``. EXAMPLES:: sage: J = range(10) sage: A = [1/10 for j in J] sage: s = IndexedSequence(A,J) sage: s Indexed sequence: [1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10] indexed by [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: s.dict() {0: 1/10, 1: 1/10, 2: 1/10, 3: 1/10, 4: 1/10, 5: 1/10, 6: 1/10, 7: 1/10, 8: 1/10, 9: 1/10} sage: s.list() [1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10] sage: s.index_object() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: s.base_ring() Rational Field """ try: ind = index_object.list() except AttributeError: ind = list(index_object) self._index_object = index_object self._list = Sequence(L) self._base_ring = self._list.universe() dict = {} for i in range(len(ind)): dict[ind[i]] = L[i] self._dict = dict
def ap(self, p): """ Return a list of the eigenvalues of the Hecke operator `T_p` on all the computed eigenforms. The eigenvalues match up between one prime and the next. INPUT: - ``p`` - integer, a prime number OUTPUT: - ``list`` - a list of double precision complex numbers EXAMPLES:: sage: n = numerical_eigenforms(11,4) sage: n.ap(2) # random order [9.0, 9.0, 2.73205080757, -0.732050807569] sage: n.ap(3) # random order [28.0, 28.0, -7.92820323028, 5.92820323028] sage: m = n.modular_symbols() sage: x = polygen(QQ, 'x') sage: m.T(2).charpoly('x').factor() (x - 9)^2 * (x^2 - 2*x - 2) sage: m.T(3).charpoly('x').factor() (x - 28)^2 * (x^2 + 2*x - 47) """ p = Integer(p) if not p.is_prime(): raise ValueError("p must be a prime") try: return self._ap[p] except AttributeError: self._ap = {} except KeyError: pass a = Sequence(self.eigenvalues([p])[0], immutable=True) self._ap[p] = a return a
def eisenstein_params(self): """ Return parameters that define all Eisenstein series in self. OUTPUT: an immutable Sequence EXAMPLES:: sage: m = ModularForms(Gamma0(22), 2) sage: v = m.eisenstein_params(); v [(Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 2), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 11), (Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, Dirichlet character modulo 22 of conductor 1 mapping 13 |--> 1, 22)] sage: type(v) <class 'sage.structure.sequence.Sequence_generic'> """ eps = self.character() if eps is None: if arithgroup.is_Gamma1(self.group()): eps = self.level() else: raise NotImplementedError params = eis_series.compute_eisenstein_params(eps, self.weight()) return Sequence(params, immutable=True)
def __init__(self, X, v, check=True): """ The Python constructor. See :class:`SchemeMorphism_point_affine` for details. TESTS:: sage: from sage.schemes.affine.affine_point import SchemeMorphism_point_affine sage: A3.<x,y,z> = AffineSpace(QQ, 3) sage: SchemeMorphism_point_affine(A3(QQ), [1, 2, 3]) (1, 2, 3) """ SchemeMorphism.__init__(self, X) if check: from sage.rings.ring import CommutativeRing if is_SchemeMorphism(v): v = list(v) else: try: if isinstance(v.parent(), CommutativeRing): v = [v] except AttributeError: pass # Verify that there are the right number of coords d = self.codomain().ambient_space().ngens() if len(v) != d: raise TypeError("argument v (=%s) must have %s coordinates" % (v, d)) if not isinstance(v, (list, tuple)): raise TypeError( "argument v (= %s) must be a scheme point, list, or tuple" % str(v)) # Make sure the coordinates all lie in the appropriate ring v = Sequence(v, X.value_ring()) # Verify that the point satisfies the equations of X. X.extended_codomain()._check_satisfies_equations(v) self._coords = tuple(v)
def _check_satisfies_equations(self, v): """ Return True if `v` defines a point on the scheme self; raise a TypeError otherwise. EXAMPLES:: sage: A = AffineSpace(3, ZZ) sage: A._check_satisfies_equations([1, 1, 0]) True sage: A._check_satisfies_equations((0, 1, 0)) True sage: A._check_satisfies_equations([0, 0, 0]) True sage: A._check_satisfies_equations([1, 2, 3, 4, 5]) Traceback (most recent call last): ... TypeError: The list v=[1, 2, 3, 4, 5] must have 3 components sage: A._check_satisfies_equations([1/2, 1, 1]) Traceback (most recent call last): ... TypeError: The components of v=[1/2, 1, 1] must be elements of Integer Ring sage: A._check_satisfies_equations(5) Traceback (most recent call last): ... TypeError: The argument v=5 must be a list or tuple """ if not isinstance(v, (list, tuple)): raise TypeError('The argument v=%s must be a list or tuple' % v) n = self.ngens() if not len(v) == n: raise TypeError('The list v=%s must have %s components' % (v, n)) R = self.base_ring() from sage.structure.sequence import Sequence if not Sequence(v).universe() == R: raise TypeError('The components of v=%s must be elements of %s' % (v, R)) return True
def __init__(self, invariants, names, number_field, gens, S, proof=True): r""" Create an S-class group. EXAMPLES:: sage: K.<a> = QuadraticField(-14) sage: I = K.ideal(2,a) sage: S = (I,) sage: K.S_class_group(S) S-class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 14 sage: K.<a> = QuadraticField(-105) sage: K.S_class_group([K.ideal(13, a + 8)]) S-class group of order 4 with structure C2 x C2 of Number Field in a with defining polynomial x^2 + 105 """ AbelianGroup_class.__init__(self, len(invariants), invariants, names) self._proof_flag = proof self.__number_field = number_field self.__S = S self.__gens = Sequence([SFractionalIdealClass(self, x) for x in gens], immutable=True, universe=self, check=False)
def parallelotope(self, generators): r""" Return the parallelotope spanned by the generators. The parallelotope is the multi-dimensional generalization of a parallelogram (2 generators) and a parallelepiped (3 generators). INPUT: - ``generators`` -- a list vector of vectors of same dimension EXAMPLES:: sage: polytopes.parallelotope([ (1,0), (0,1) ]) A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]) A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 16 vertices sage: K = QuadraticField(2, 'sqrt2') sage: sqrt2 = K.gen() sage: polytopes.parallelotope([ (1,sqrt2), (1,-1) ]) A 2-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2)^2 defined as the convex hull of 4 vertices """ from sage.modules.free_module_element import vector from sage.structure.sequence import Sequence generators = map(vector, generators) V = Sequence(generators).universe() R = V.base_ring() from itertools import combinations par = [V.zero()] par.extend( sum(c) for k in range(1, len(generators) + 1) for c in combinations(generators, k)) return Polyhedron(vertices=par, base_ring=R)
def __init__(self, parent, im_gens, base_map=None, check=True): """ EXAMPLES:: sage: L = LieAlgebra(QQ, 'x,y,z') sage: Lyn = L.Lyndon() sage: H = L.Hall() sage: phi = Lyn.coerce_map_from(H) We skip the category test because the Homset's element class does not match this class:: sage: TestSuite(phi).run(skip=['_test_category']) """ Morphism.__init__(self, parent) if not isinstance(im_gens, Sequence_generic): if not isinstance(im_gens, (tuple, list)): im_gens = [im_gens] im_gens = Sequence(im_gens, parent.codomain(), immutable=True) if check: if len(im_gens) != len(parent.domain().lie_algebra_generators()): raise ValueError( "number of images must equal number of generators") if base_map is not None and not ( base_map.domain() is parent.domain().base_ring() and parent.codomain().base_ring().has_coerce_map_from( base_map.codomain())): raise ValueError("Invalid base homomorphism") # TODO: Implement a (meaningful) _is_valid_homomorphism_() #if not parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens, base_map=base_map): # raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators.") if not im_gens.is_immutable(): import copy im_gens = copy.copy(im_gens) im_gens.set_immutable() self._im_gens = im_gens self._base_map = base_map
def characters(self): r""" Return the pair of characters (either of `\QQ_p^*` or of some quadratic extension) corresponding to this representation. EXAMPLES:: sage: f = [f for f in Newforms(63, 4, names='a') if f[2] == 1][0] sage: f.local_component(3).characters() [ Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> d, Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> -d - 2 ] """ minchars = self._min_twist.characters() G = minchars[0].parent() chi = self._chi if self.species() == "Supercuspidal": H = SmoothCharacterGroupQp(self.prime(), chi.base_ring()) Hchi = H.from_dirichlet(~chi) Gchi = G.compose_with_norm(Hchi) else: Gchi = G.from_dirichlet(~chi) return Sequence([c * Gchi for c in minchars], cr=True, universe=G)
def basis(self): r""" Returns a basis of ``self``. OUTPUT: - ``Sequence`` - an immutable sequence whose universe is ambient space of ``self``. EXAMPLES:: sage: C = codes.HammingCode(GF(2), 3) sage: C.basis() [ (1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1) ] sage: C.basis().universe() Vector space of dimension 7 over Finite Field of size 2 """ gens = self.gens() from sage.structure.sequence import Sequence return Sequence(gens, universe=self.ambient_space(), check = False, immutable=True, cr=True)
def right_angle_triangle(w, h): r""" TESTS:: sage: from flatsurf import * sage: R = similarity_surfaces.right_angle_triangle(2, 3) sage: R ConeSurface built from 2 polygons sage: TestSuite(R).run() """ from sage.modules.free_module_element import vector F = Sequence([w, h]).universe() if not F.is_field(): F = F.fraction_field() V = VectorSpace(F, 2) P = ConvexPolygons(F) s = Surface_list(base_ring=F) s.add_polygon(P([V((w, 0)), V((-w, h)), V((0, -h))])) # gets label 0 s.add_polygon(P([V((0, h)), V((-w, -h)), V((w, 0))])) # gets label 1 s.change_polygon_gluings(0, [(1, 2), (1, 1), (1, 0)]) s.set_immutable() return ConeSurface(s)
def __init__(self, X, v, check=True): """ The Python constructor. EXAMPLES:: sage: P = ProjectiveSpace(2, QQ) sage: P(2, 3/5, 4) (1/2 : 3/20 : 1) :: sage: P = ProjectiveSpace(1, ZZ) sage: P([0, 1]) (0 : 1) :: sage: P = ProjectiveSpace(1, ZZ) sage: P([0, 0, 1]) Traceback (most recent call last): ... TypeError: v (=[0, 0, 1]) must have 2 components :: sage: P = ProjectiveSpace(3, QQ) sage: P(0,0,0,0) Traceback (most recent call last): ... ValueError: [0, 0, 0, 0] does not define a valid point since all entries are 0 It is possible to avoid the possibly time-consuming checks, but be careful!! :: sage: P = ProjectiveSpace(3, QQ) sage: P.point([0,0,0,0], check=False) (0 : 0 : 0 : 0) :: sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) sage: X = P.subscheme([x^2-y*z]) sage: X([2, 2, 2]) (2 : 2 : 2) :: sage: R.<t> = PolynomialRing(ZZ) sage: P = ProjectiveSpace(1, R.quo(t^2+1)) sage: P([2*t, 1]) (2*tbar : 1) :: sage: P = ProjectiveSpace(ZZ,1) sage: P.point(Infinity) (1 : 0) sage: P(infinity) (1 : 0) :: sage: P = ProjectiveSpace(ZZ,2) sage: P(Infinity) Traceback (most recent call last): ... ValueError: +Infinity not well defined in dimension > 1 sage: P.point(infinity) Traceback (most recent call last): ... ValueError: +Infinity not well defined in dimension > 1 """ SchemeMorphism.__init__(self, X) if check: from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.rings.ring import CommutativeRing d = X.codomain().ambient_space().ngens() if is_SchemeMorphism(v) or isinstance(v, EllipticCurvePoint_field): v = list(v) else: try: if isinstance(v.parent(), CommutativeRing): v = [v] except AttributeError: pass if not isinstance(v, (list, tuple)): raise TypeError("argument v (= %s) must be a scheme point, list, or tuple"%str(v)) if len(v) != d and len(v) != d-1: raise TypeError("v (=%s) must have %s components"%(v, d)) R = X.value_ring() v = Sequence(v, R) if len(v) == d-1: # very common special case v.append(R(1)) n = len(v) all_zero = True for i in range(n): last = n-1-i if v[last]: all_zero = False break if all_zero: raise ValueError("%s does not define a valid point since all entries are 0"%repr(v)) X.extended_codomain()._check_satisfies_equations(v) self._coords = tuple(v)
def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, values_group=None): """ Construct an Abelian group with values associated to the generators. INPUT: - ``values`` -- a list/tuple/iterable of values that you want to associate to the generators. - ``n`` -- integer (optional). If not specified, will be derived from ``gens_orders``. - ``gens_orders`` -- a list of non-negative integers in the form `[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing order. This list is padded with zeros if it has length less than n. The orders of the commuting generators, with `0` denoting an infinite cyclic factor. - ``names`` -- (optional) names of generators - ``values_group`` -- a parent or ``None`` (default). The common parent of the values. This might be a group, but can also just contain the values. For example, if the values are units in a ring then the ``values_group`` would be the whole ring. If ``None`` it will be derived from the values. EXAMPLES:: sage: G = AbelianGroupWithValues([-1], [6]) sage: g = G.gen(0) sage: for i in range(7): ....: print((i, g^i, (g^i).value())) (0, 1, 1) (1, f, -1) (2, f^2, 1) (3, f^3, -1) (4, f^4, 1) (5, f^5, -1) (6, 1, 1) sage: G.values_group() Integer Ring The group elements come with a coercion embedding into the :meth:`values_group`, so you can use them like their :meth:`~sage.groups.abelian_gps.value.AbelianGroupWithValuesElement.value` :: sage: G.values_embedding() Generic morphism: From: Multiplicative Abelian group isomorphic to C6 To: Integer Ring sage: g.value() -1 sage: 0 + g -1 sage: 1 + 2*g -1 """ if check: raise NotImplementedError( 'checking that the values are a homomorphism is not implemented') gens_orders, names = _normalize(n, gens_orders, names) if values_group is None: from sage.structure.sequence import Sequence values_group = Sequence(values).universe() values = tuple(values_group(val) for val in values) M = AbelianGroupWithValues_class(gens_orders, names, values, values_group) return M
def coefficients_from_j(j, minimal_twist=True): """ Return Weierstrass coefficients `(a_1, a_2, a_3, a_4, a_6)` for an elliptic curve with given `j`-invariant. INPUT: See :func:`EllipticCurve_from_j`. EXAMPLES:: sage: from sage.schemes.elliptic_curves.constructor import coefficients_from_j sage: coefficients_from_j(0) [0, 0, 1, 0, 0] sage: coefficients_from_j(1728) [0, 0, 0, -1, 0] sage: coefficients_from_j(1) [1, 0, 0, 36, 3455] The ``minimal_twist`` parameter (ignored except over `\\QQ` and True by default) controls whether or not a minimal twist is computed:: sage: coefficients_from_j(100) [0, 1, 0, 3392, 307888] sage: coefficients_from_j(100, minimal_twist=False) [0, 0, 0, 488400, -530076800] """ try: K = j.parent() except AttributeError: K = rings.RationalField() if K not in _Fields: K = K.fraction_field() char = K.characteristic() if char == 2: if j == 0: return Sequence([0, 0, 1, 0, 0], universe=K) else: return Sequence([1, 0, 0, 0, 1 / j], universe=K) if char == 3: if j == 0: return Sequence([0, 0, 0, 1, 0], universe=K) else: return Sequence([0, j, 0, 0, -j**2], universe=K) if K is rings.RationalField(): # we construct the minimal twist, i.e. the curve with minimal # conductor with this j_invariant: if j == 0: return Sequence([0, 0, 1, 0, 0], universe=K) # 27a3 if j == 1728: return Sequence([0, 0, 0, -1, 0], universe=K) # 32a2 if not minimal_twist: k = j - 1728 return Sequence([0, 0, 0, -3 * j * k, -2 * j * k**2], universe=K) n = j.numerator() m = n - 1728 * j.denominator() a4 = -3 * n * m a6 = -2 * n * m**2 # Now E=[0,0,0,a4,a6] has j-invariant j=n/d from sage.sets.set import Set for p in Set(n.prime_divisors() + m.prime_divisors()): e = min(a4.valuation(p) // 2, a6.valuation(p) // 3) if e > 0: p = p**e a4 /= p**2 a6 /= p**3 # Now E=[0,0,0,a4,a6] is minimal at all p != 2,3 tw = [-1, 2, -2, 3, -3, 6, -6] E1 = EllipticCurve([0, 0, 0, a4, a6]) Elist = [E1] + [E1.quadratic_twist(t) for t in tw] Elist.sort(key=lambda E: E.conductor()) return Sequence(Elist[0].ainvs()) # defaults for all other fields: if j == 0: return Sequence([0, 0, 0, 0, 1], universe=K) if j == 1728: return Sequence([0, 0, 0, 1, 0], universe=K) k = j - 1728 return Sequence([0, 0, 0, -3 * j * k, -2 * j * k**2], universe=K)
def characters(self): r""" Return the two conjugate characters of `K^\times`, where `K` is some quadratic extension of `\QQ_p`, defining this representation. This is fully implemented only in the case where the power of `p` dividing the level of the form is even, in which case `K` is the unique unramified quadratic extension of `\QQ_p`. EXAMPLES: The first example from _[LW11]:: sage: f = Newform('50a') sage: Pi = LocalComponent(f, 5) sage: chars = Pi.characters(); chars [ Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> d, 5 |--> 1, Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -d - 1, 5 |--> 1 ] sage: chars[0].base_ring() Number Field in d with defining polynomial x^2 + x + 1 These characters are interchanged by the Frobenius automorphism of `\mathbb{F}_{25}`:: sage: chars[0] == chars[1]**5 True A more complicated example (higher weight and nontrivial central character):: sage: f = Newforms(GammaH(25, [6]), 3, names='j')[0]; f q + j0*q^2 + 1/3*j0^3*q^3 - 1/3*j0^2*q^4 + O(q^6) sage: Pi = LocalComponent(f, 5) sage: Pi.characters() [ Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> d, 5 |--> 5, Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -d - 1/3*j0^3, 5 |--> 5 ] sage: Pi.characters()[0].base_ring() Number Field in d with defining polynomial x^2 + 1/3*j0^3*x - 1/3*j0^2 over its base field .. warning:: The above output isn't actually the same as in Example 2 of _[LW11], due to an error in the published paper (correction pending) -- the published paper has the inverses of the above characters. A higher level example:: sage: f = Newform('81a', names='j'); f q + j0*q^2 + q^4 - j0*q^5 + O(q^6) sage: LocalComponent(f, 3).characters() # long time (12s on sage.math, 2012) [ Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> -2*d - j0, 4 |--> 1, 3*s + 1 |--> -j0*d - 2, 3 |--> 1, Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> 2*d + j0, 4 |--> 1, 3*s + 1 |--> j0*d + 1, 3 |--> 1 ] In the ramified case, it's not fully implemented, and just returns a string indicating which ramified extension is being considered:: sage: Pi = LocalComponent(Newform('27a'), 3) sage: Pi.characters() 'Character of Q_3(sqrt(-3))' sage: Pi = LocalComponent(Newform('54a'), 3) sage: Pi.characters() 'Character of Q_3(sqrt(3))' """ T = self.type_space() if self.conductor() % 2 == 0: G = SmoothCharacterGroupUnramifiedQuadratic( self.prime(), self.coefficient_field()) n = self.conductor() // 2 g = G.quotient_gen(n) m = g.matrix().change_ring(ZZ).list() tr = (~T.rho(m)).trace() # The inverse is needed here because T is the *homological* type space, # which is dual to the cohomological one that defines the local component. X = polygen(self.coefficient_field()) theta_poly = X**2 - (-1)**n * tr * X + self.central_character()( g.norm()) if theta_poly.is_irreducible(): F = self.coefficient_field().extension(theta_poly, "d") G = G.base_extend(F) chi1, chi2 = [ G.extend_character(n, self.central_character(), x[0]) for x in theta_poly.roots(G.base_ring()) ] # Consistency checks assert chi1.restrict_to_Qp() == chi2.restrict_to_Qp( ) == self.central_character() assert chi1 * chi2 == chi1.parent().compose_with_norm( self.central_character()) return Sequence([chi1, chi2], check=False, cr=True) else: # The ramified case. p = self.prime() if p == 2: # The ramified 2-adic representations aren't classified by admissible pairs. Die. raise NotImplementedError( "Computation with ramified 2-adic representations not implemented" ) if p % 4 == 3: a = ZZ(-1) else: a = ZZ(Zmod(self.prime()).quadratic_nonresidue()) tr1 = (~T.rho([0, 1, a * p, 0])).trace() tr2 = (~T.rho([0, 1, p, 0])).trace() if tr1 == tr2 == 0: # This *can* happen. E.g. if the central character satisfies # chi(-1) = -1, then we have theta(pi) + theta(-pi) = theta(pi) # * (1 + -1) = 0. In this case, one can presumably identify # the character and the extension by some more subtle argument # but I don't know of a good way to automate the process. raise NotImplementedError( "Can't identify ramified quadratic extension -- both traces zero" ) elif tr1 == 0: return "Character of Q_%s(sqrt(%s))" % (p, p) elif tr2 == 0: return "Character of Q_%s(sqrt(%s))" % (p, a * p) else: # At least one of the traces is *always* 0, since the type # space has to be isomorphic to its twist by the (ramified # quadratic) character corresponding to the quadratic # extension. raise RuntimeError("Can't get here!")
def permutation_action(g, v): r""" Returns permutation of rows g\*v. Works on lists, matrices, sequences and vectors (by permuting coordinates). The code requires switching from i to i+1 (and back again) since the SymmetricGroup is, by convention, the symmetric group on the "letters" 1, 2, ..., n (not 0, 1, ..., n-1). EXAMPLES:: sage: V = VectorSpace(GF(3),5) sage: v = V([0,1,2,0,1]) sage: G = SymmetricGroup(5) sage: g = G([(1,2,3)]) sage: permutation_action(g,v) (1, 2, 0, 0, 1) sage: g = G([()]) sage: permutation_action(g,v) (0, 1, 2, 0, 1) sage: g = G([(1,2,3,4,5)]) sage: permutation_action(g,v) (1, 2, 0, 1, 0) sage: L = Sequence([1,2,3,4,5]) sage: permutation_action(g,L) [2, 3, 4, 5, 1] sage: MS = MatrixSpace(GF(3),3,7) sage: A = MS([[1,0,0,0,1,1,0],[0,1,0,1,0,1,0],[0,0,0,0,0,0,1]]) sage: S5 = SymmetricGroup(5) sage: g = S5([(1,2,3)]) sage: A [1 0 0 0 1 1 0] [0 1 0 1 0 1 0] [0 0 0 0 0 0 1] sage: permutation_action(g,A) [0 1 0 1 0 1 0] [0 0 0 0 0 0 1] [1 0 0 0 1 1 0] It also works on lists and is a "left action":: sage: v = [0,1,2,0,1] sage: G = SymmetricGroup(5) sage: g = G([(1,2,3)]) sage: gv = permutation_action(g,v); gv [1, 2, 0, 0, 1] sage: permutation_action(g,v) == g(v) True sage: h = G([(3,4)]) sage: gv = permutation_action(g,v) sage: hgv = permutation_action(h,gv) sage: hgv == permutation_action(h*g,v) True AUTHORS: - David Joyner, licensed under the GPL v2 or greater. """ v_type_list = False if isinstance(v, list): v_type_list = True v = Sequence(v) if isinstance(v, Sequence_generic): V = v.universe() else: V = v.parent() n = len(list(v)) gv = [] for i in range(n): gv.append(v[g(i + 1) - 1]) if v_type_list: return gv return V(gv)
def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds): """ Return a ``UniqueFactory`` key and possibly extra parameters. INPUT: See the documentation for :class:`EllipticCurveFactory`. OUTPUT: A pair ``(key, extra_args)``: - ``key`` has the form `(R, (a_1, a_2, a_3, a_4, a_6))`, representing a ring and the Weierstrass coefficients of an elliptic curve over that ring; - ``extra_args`` is a dictionary containing additional data to be inserted into the elliptic curve structure. EXAMPLES:: sage: EllipticCurve.create_key_and_extra_args(j=8000) ((Rational Field, (0, -1, 0, -3, -1)), {}) When constructing a curve over `\\QQ` from a Cremona or LMFDB label, the invariants from the database are returned as ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1') sage: key (Rational Field, (0, 1, 1, -2, 0)) sage: data['conductor'] 389 sage: data['cremona_label'] '389a1' sage: data['lmfdb_label'] '389.a1' sage: data['rank'] 2 sage: data['torsion_order'] 1 User-specified keywords are also included in ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4) sage: data['rank'] 4 Furthermore, keywords takes precedence over data from the database, which can be used to specify an alternative set of generators for the Mordell-Weil group:: sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]]) sage: data['gens'] [[1, -1], [-2, 3], [4, -7]] sage: E = EllipticCurve.create_object(0, key, **data) sage: E.gens() [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)] Note that elliptic curves are equal if and only they have the same base ring and Weierstrass equation; the data in ``extra_args`` do not influence comparison of elliptic curves. A consequence of this is that passing keyword arguments only works when constructing an elliptic curve the first time:: sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] .. WARNING:: Manually specifying extra data is almost never necessary and is not guaranteed to have any effect, as the above example shows. Almost no checking is done, so specifying incorrect data may lead to wrong results of computations instead of errors or warnings. """ R = None if is_Ring(x): (R, x) = (x, y) if j is not None: if R is not None: try: j = R(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError( "First parameter must be a ring containing %s" % j) elif x is not None: raise ValueError( "First parameter (if present) must be a ring when j is specified" ) x = coefficients_from_j(j, minimal_twist) if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if is_MPolynomial(x): if y is None: x = coefficients_from_Weierstrass_polynomial(x) else: x = coefficients_from_cubic(x, y, morphism=False) if isinstance(x, string_types): # Interpret x as a Cremona or LMFDB label. from sage.databases.cremona import CremonaDatabase x, data = CremonaDatabase().coefficients_and_data(x) # User-provided keywords may override database entries. data.update(kwds) kwds = data if not isinstance(x, (list, tuple)): raise TypeError("invalid input to EllipticCurve constructor") if len(x) == 2: x = (0, 0, 0, x[0], x[1]) elif len(x) != 5: raise ValueError( "sequence of coefficients must have length 2 or 5") if R is None: R = Sequence(x).universe() if R in (rings.ZZ, ) + integer_types: R = rings.QQ return (R, tuple(R(a) for a in x)), kwds
def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None): """ Construct a polyhedron object. You may either define it with vertex/ray/line or inequalities/equations data, but not both. Redundant data will automatically be removed (unless ``minimize=False``), and the complementary representation will be computed. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of ``base_ring`` elements. - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. - ``base_ring`` -- a sub-field of the reals implemented in Sage. The field over which the polyhedron will be defined. For ``QQ`` and algebraic extensions, exact arithmetic will be used. For ``RDF``, floating point numbers will be used. Floating point arithmetic is faster but might give the wrong result for degenerate input. - ``ambient_dim`` -- integer. The ambient space dimension. Usually can be figured out automatically from the H/Vrepresentation dimensions. - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or `\RDF` coefficients depending on ``base_ring``. * ``'ppl'``: use ppl (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. * ``'field'``: use python implementation (:mod:`~sage.geometry.polyhedron.backend_field`) for any field Some backends support further optional arguments: - ``minimize`` -- boolean (default: ``True``). Whether to immediately remove redundant H/V-representation data. Currently not used. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. Only supported by the cdd backends. OUTPUT: The polyhedron defined by the input data. EXAMPLES: Construct some polyhedra:: sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]]) sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]]) sage: list(square_from_ieqs.vertex_generator()) [A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, -1)] sage: list(square_from_vertices.inequality_generator()) [An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0] sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF) sage: p.n_inequalities() 2 The same polyhedron given in two ways:: sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]]) sage: p.Vrepresentation() (A line in the direction (0, 0, 1), A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0), A vertex at (0, 0, 0)) sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]]) sage: q.Hrepresentation() (An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with coordinates `a, b, \dots, f` and * The inequality `e+b \geq c+d` * The inequality `e+c \geq b+d` * The equation `a+b+c+d+e+f = 31` :: sage: positive_coords = Polyhedron(ieqs=[ ... [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], ... [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]]) sage: P = Polyhedron(ieqs=positive_coords.inequalities() + ( ... [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]]) sage: P A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices sage: P.dim() 5 sage: P.Vrepresentation() (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31), A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0), A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0), A vertex at (0, 0, 0, 31/2, 31/2, 0)) .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``field=RDF`` allows numerical data to be used, it might not give the right answer for degenerate input data - the results can depend upon the tolerance setting of cdd. """ # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) lines = _make_listlist(lines) ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) got_Vrep = (len(vertices + rays + lines) > 0) got_Hrep = (len(ieqs + eqns) > 0) if got_Vrep and got_Hrep: raise ValueError('You cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] elif got_Hrep: deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1 else: if ambient_dim is None: deduced_ambient_dim = 0 else: deduced_ambient_dim = ambient_dim if base_ring is None: base_ring = ZZ # set ambient_dim if ambient_dim is not None and deduced_ambient_dim != ambient_dim: raise ValueError( 'Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.' ) ambient_dim = deduced_ambient_dim # figure out base_ring from sage.misc.flatten import flatten values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: try: convert = not all(x.parent() is base_ring for x in values) except AttributeError: # No x.parent() method? convert = True else: from sage.rings.integer import is_Integer from sage.rings.rational import is_Rational from sage.rings.real_double import is_RealDoubleElement if all(is_Integer(x) for x in values): if got_Vrep: base_ring = ZZ else: # integral inequalities usually do not determine a lattice polytope! base_ring = QQ convert = False elif all(is_Rational(x) for x in values): base_ring = QQ convert = False elif all(is_RealDoubleElement(x) for x in values): base_ring = RDF convert = False else: try: for v in values: ZZ(v) if got_Vrep: base_ring = ZZ else: base_ring = QQ convert = True except (TypeError, ValueError): from sage.structure.sequence import Sequence values = Sequence(values) common_ring = values.universe() if QQ.has_coerce_map_from(common_ring): base_ring = QQ convert = True elif common_ring is RR: # DWIM: replace with RDF base_ring = RDF convert = True else: base_ring = common_ring convert = True # Add the origin if necesarry if got_Vrep and len(vertices) == 0: vertices = [[0] * ambient_dim] # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() # finally, construct the Polyhedron Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] return parent(Vrep, Hrep, convert=convert, verbose=verbose)
def __init__(self, number_field, proof=True, S=None): """ Create a unit group of a number field. INPUT: - ``number_field`` - a number field - ``proof`` - boolean (default True): proof flag - ``S`` - tuple of prime ideals, or an ideal, or a single ideal or element from which an ideal can be constructed, in which case the support is used. If None, the global unit group is constructed; otherwise, the S-unit group is constructed. The proof flag is passed to pari via the ``pari_bnf()`` function which computes the unit group. See the documentation for the number_field module. EXAMPLES:: sage: x = polygen(QQ) sage: K.<a> = NumberField(x^2-38) sage: UK = K.unit_group(); UK Unit group with structure C2 x Z of Number Field in a with defining polynomial x^2 - 38 sage: UK.gens() (u0, u1) sage: UK.gens_values() [-1, 6*a - 37] sage: K.<a> = QuadraticField(-3) sage: UK = K.unit_group(); UK Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 sage: UK.gens() (u,) sage: UK.gens_values() [-1/2*a + 1/2] sage: K.<z> = CyclotomicField(13) sage: UK = K.unit_group(); UK Unit group with structure C26 x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 sage: UK.gens() (u0, u1, u2, u3, u4, u5) sage: UK.gens_values() # random [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z] sage: SUK = UnitGroup(K,S=2); SUK S-unit group with structure C26 x Z x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 with S = (Fractional ideal (2),) """ proof = get_flag(proof, "number_field") K = number_field pK = K.pari_bnf(proof) self.__number_field = K self.__pari_number_field = pK # process the parameter S: if not S: S = self.__S = () else: if isinstance(S, list): S = tuple(S) if not isinstance(S, tuple): try: S = tuple(K.ideal(S).prime_factors()) except (NameError, TypeError, ValueError): raise ValueError("Cannot make a set of primes from %s" % (S, )) else: try: S = tuple(K.ideal(P) for P in S) except (NameError, TypeError, ValueError): raise ValueError("Cannot make a set of primes from %s" % (S, )) if not all([P.is_prime() for P in S]): raise ValueError( "Not all elements of %s are prime ideals" % (S, )) self.__S = S self.__pS = pS = [P.pari_prime() for P in S] # compute the fundamental units via pari: fu = [K(u) for u in pK.bnfunit()] self.__nfu = len(fu) # compute the additional S-unit generators: if S: self.__S_unit_data = pK.bnfsunit(pS) su = [K(u) for u in self.__S_unit_data[0]] else: su = [] self.__nsu = len(su) self.__rank = self.__nfu + self.__nsu # compute a torsion generator and pick the 'simplest' one: n, z = pK.nfrootsof1() n = ZZ(n) self.__ntu = n z = K(z) # If we replaced z by another torsion generator we would need # to allow for this in the dlog function! So we do not. # Store the actual generators (torsion first): gens = [z] + fu + su values = Sequence(gens, immutable=True, universe=self, check=False) # Construct the abtract group: gens_orders = tuple([ZZ(n)] + [ZZ(0)] * (self.__rank)) AbelianGroupWithValues_class.__init__(self, gens_orders, 'u', values, number_field)
def __init__(self, X, v, check=True): """ The Python constructor. See :class:`SchemeMorphism_point_projective_ring` for details. This function still normalizes points so that the rightmost non-zero coordinate is 1. This is to maintain functionality with current implementations of curves in projectives space (plane, conic, elliptic, etc). The :class:`SchemeMorphism_point_projective_ring` is for general use. EXAMPLES:: sage: P = ProjectiveSpace(2, QQ) sage: P(2, 3/5, 4) (1/2 : 3/20 : 1) :: sage: P = ProjectiveSpace(3, QQ) sage: P(0, 0, 0, 0) Traceback (most recent call last): ... ValueError: [0, 0, 0, 0] does not define a valid point since all entries are 0 :: sage: P.<x, y, z> = ProjectiveSpace(2, QQ) sage: X = P.subscheme([x^2-y*z]) sage: X([2, 2, 2]) (1 : 1 : 1) :: sage: P = ProjectiveSpace(1, GF(7)) sage: Q=P([2, 1]) sage: Q[0].parent() Finite Field of size 7 :: sage: P = ProjectiveSpace(QQ,1) sage: P.point(Infinity) (1 : 0) sage: P(infinity) (1 : 0) :: sage: P = ProjectiveSpace(QQ,2) sage: P(infinity) Traceback (most recent call last): ... ValueError: +Infinity not well defined in dimension > 1 sage: P.point(infinity) Traceback (most recent call last): ... ValueError: +Infinity not well defined in dimension > 1 """ SchemeMorphism.__init__(self, X) if check: from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.rings.ring import CommutativeRing d = X.codomain().ambient_space().ngens() if is_SchemeMorphism(v) or isinstance(v, EllipticCurvePoint_field): v = list(v) else: try: if isinstance(v.parent(), CommutativeRing): v = [v] except AttributeError: pass if not isinstance(v, (list,tuple)): raise TypeError("argument v (= %s) must be a scheme point, list, or tuple"%str(v)) if len(v) != d and len(v) != d-1: raise TypeError("v (=%s) must have %s components"%(v, d)) R = X.value_ring() v = Sequence(v, R) if len(v) == d-1: # very common special case v.append(R(1)) n = len(v) all_zero = True for i in range(n): last = n-1-i if v[last]: all_zero = False c = v[last] if c == R.one(): break for j in range(last): v[j] /= c v[last] = R.one() break if all_zero: raise ValueError("%s does not define a valid point since all entries are 0"%repr(v)) X.extended_codomain()._check_satisfies_equations(v) self._coords = tuple(v)
def __init__(self, number_field, proof=True, S=None): """ Create a unit group of a number field. INPUT: - ``number_field`` - a number field - ``proof`` - boolean (default True): proof flag - ``S`` - tuple of prime ideals, or an ideal, or a single ideal or element from which an ideal can be constructed, in which case the support is used. If None, the global unit group is constructed; otherwise, the S-unit group is constructed. The proof flag is passed to pari via the ``pari_bnf()`` function which computes the unit group. See the documentation for the number_field module. EXAMPLES:: sage: x = polygen(QQ) sage: K.<a> = NumberField(x^2-38) sage: UK = K.unit_group(); UK Unit group with structure C2 x Z of Number Field in a with defining polynomial x^2 - 38 sage: UK.gens() (u0, u1) sage: UK.gens_values() [-1, 6*a - 37] sage: K.<a> = QuadraticField(-3) sage: UK = K.unit_group(); UK Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I sage: UK.gens() (u,) sage: UK.gens_values() [1/2*a + 1/2] sage: K.<z> = CyclotomicField(13) sage: UK = K.unit_group(); UK Unit group with structure C26 x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 sage: UK.gens() (u0, u1, u2, u3, u4, u5) sage: UK.gens_values() # random [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z] sage: SUK = UnitGroup(K,S=2); SUK S-unit group with structure C26 x Z x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12 with S = (Fractional ideal (2),) TESTS: Number fields defined by non-monic and non-integral polynomials are supported (:trac:`252`); the representation depends on the PARI version:: sage: K.<a> = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) sage: K.unit_group() Unit group with structure C2 x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 sage: UnitGroup(K, S=tuple(K.primes_above(7))) S-unit group with structure C2 x Z x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 with S = (Fractional ideal (...),) sage: K.primes_above(7)[0] in (7/225*a^2 - 7/75*a - 42/25, 28/225*a^2 + 77/75*a - 133/25) True Conversion from unit group to a number field and back gives the right results (:trac:`25874`):: sage: K = QuadraticField(-3).composite_fields(QuadraticField(2))[0] sage: U = K.unit_group() sage: tuple(U(K(u)) for u in U.gens()) == U.gens() True sage: US = K.S_unit_group(3) sage: tuple(US(K(u)) for u in US.gens()) == US.gens() True """ proof = get_flag(proof, "number_field") K = number_field pK = K.pari_bnf(proof) self.__number_field = K self.__pari_number_field = pK # process the parameter S: if not S: S = self.__S = () else: if isinstance(S, list): S = tuple(S) if not isinstance(S, tuple): try: S = tuple(K.ideal(S).prime_factors()) except (NameError, TypeError, ValueError): raise ValueError("Cannot make a set of primes from %s" % (S, )) else: try: S = tuple(K.ideal(P) for P in S) except (NameError, TypeError, ValueError): raise ValueError("Cannot make a set of primes from %s" % (S, )) if not all(P.is_prime() for P in S): raise ValueError( "Not all elements of %s are prime ideals" % (S, )) self.__S = S self.__pS = pS = [P.pari_prime() for P in S] # compute the fundamental units via pari: fu = [K(u, check=False) for u in pK.bnfunit()] self.__nfu = len(fu) # compute the additional S-unit generators: if S: self.__S_unit_data = pK.bnfsunit(pS) su = [K(u, check=False) for u in self.__S_unit_data[0]] else: su = [] self.__nsu = len(su) self.__rank = self.__nfu + self.__nsu # compute a torsion generator and pick the 'simplest' one: n, z = pK[7][ 3] # number of roots of unity and bnf.tu as in pari documentation n = ZZ(n) self.__ntu = n z = K(z, check=False) # If we replaced z by another torsion generator we would need # to allow for this in the dlog function! So we do not. # Store the actual generators (torsion first): gens = [z] + fu + su values = Sequence(gens, immutable=True, universe=self, check=False) # Construct the abtract group: gens_orders = tuple([ZZ(n)] + [ZZ(0)] * (self.__rank)) AbelianGroupWithValues_class.__init__(self, gens_orders, 'u', values, number_field)
def d_basis(F, strat=True): r""" Return the `d`-basis for the Ideal ``F`` as defined in [BW93]_. INPUT: - ``F`` - an ideal - ``strat`` - use update strategy (default: ``True``) EXAMPLE:: sage: from sage.rings.polynomial.toy_d_basis import d_basis sage: A.<x,y> = PolynomialRing(ZZ, 2) sage: f = -y^2 - y + x^3 + 7*x + 1 sage: fx = f.derivative(x) sage: fy = f.derivative(y) sage: I = A.ideal([f,fx,fy]) sage: gb = d_basis(I); gb [x - 2020, y - 11313, 22627] """ R = F.ring() K = R.base_ring() G = set(inter_reduction(F.gens())) B = set(filter(lambda (x, y): x != y, [(f1, f2) for f1 in G for f2 in G])) D = set() C = set(B) LCM = R.monomial_lcm divides = R.monomial_divides divides_ZZ = lambda x, y: ZZ(x).divides(ZZ(y)) while B != set(): while C != set(): f1, f2 = select(C) C.remove((f1, f2)) lcm_lmf1_lmf2 = LCM(LM(f1), LM(f2)) if not any( divides(LM(g), lcm_lmf1_lmf2) and \ divides_ZZ( LC(g), LC(f1) ) and \ divides_ZZ( LC(g), LC(f2) ) \ for g in G): h = gpol(f1, f2) h0 = h.reduce(G) if h0.lc() < 0: h0 *= -1 if not strat: D = D.union([(g, h0) for g in G]) G.add(h0) else: G, D = update(G, D, h0) G = inter_reduction(G) f1, f2 = select(B) B.remove((f1, f2)) h = spol(f1, f2) h0 = h.reduce(G) if h0 != 0: if h0.lc() < 0: h0 *= -1 if not strat: D = D.union([(g, h0) for g in G]) G.add(h0) else: G, D = update(G, D, h0) B = B.union(D) C = D D = set() return Sequence(sorted(inter_reduction(G), reverse=True))