def _element_constructor_(self, vectors): """ Construct an element of ``self`` from ``vectors``. TESTS:: sage: E.<x,y> = ExteriorAlgebra(QQ) sage: H = E.hochschild_complex(E) sage: H(0) Trivial chain sage: H(2) Chain(0: 2) sage: H(x+2*y) Chain(0: x + 2*y) sage: H({0: H.module(0).an_element()}) Chain(0: 2 + 2*x + 3*y) sage: H({2: H.module(2).an_element()}) Chain(2: 2*1 # 1 # 1 + 2*1 # 1 # x + 3*1 # 1 # y) sage: H({0:x-y, 2: H.module(2).an_element()}) Chain with 2 nonzero terms over Rational Field sage: H([2]) Traceback (most recent call last): ... ValueError: cannot construct an element from [2] """ if not vectors: # special case: the zero chain return self.element_class(self, {}) # special case: an element of the defining module if self._M.has_coerce_map_from(parent(vectors)): vectors = self._M(vectors) if parent(vectors) is self._M: mc = vectors.monomial_coefficients(copy=False) vec = self.module(0)._from_dict({(k,): mc[k] for k in mc}) return self.element_class(self, {0: vec}) if isinstance(vectors, (Chain_class, self.element_class)): vectors = vectors._vec data = dict() if not isinstance(vectors, dict): raise ValueError("cannot construct an element from {}".format(vectors)) # Special handling for the 0 free module # FIXME: Allow coercions between the 0 free module and the defining module if 0 in vectors: vec = vectors.pop(0) if parent(vec) is self._M: mc = vec.monomial_coefficients(copy=False) data[0] = self.module(0)._from_dict({(k,): mc[k] for k in mc}) else: data[0] = self.module(0)(vec) for degree in vectors: vec = self.module(degree)(vectors[degree]) if not vec: continue data[degree] = vec return self.element_class(self, data)
def __ge__(self, other): """ TESTS:: sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() sage: S = A.subcrystal(max_depth=2) sage: ([(i,j) for i in range(len(S)) for j in range(len(S)) if S[i]>=S[j]] ....: == [(i,j) for i in range(len(S)) for j in range(len(S)) if ....: S[i].value>=S[j].value]) True """ return parent(self) is parent(other) and self.value >= other.value
def __cmp__(self, other): """ TESTS:: sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() sage: S = A.subcrystal(max_depth=2) sage: ([(i,j,cmp(S[i],S[j])) for i in range(len(S)) for j in range(len(S))] ....: == [(i,j,cmp(S[i].value,S[j].value)) for i in range(len(S)) for j in range(len(S))]) True """ if parent(self) is parent(other): return cmp(self.value, other.value) else: return cmp(parent(self), parent(other))
def __ge__(self, other): """" EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) sage: b = K(rows=[[1]]) sage: c = K(rows=[[2]]) sage: c>=b True sage: b>=b True sage: b>=c False """ return parent(self) is parent(other) and self.value >= other.value
def __lt__(self, other): """" EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) sage: b = K(rows=[[1]]) sage: c = K(rows=[[2]]) sage: c<b False sage: b<b False sage: b<c True """ return parent(self) is parent(other) and self.value < other.value
def __contains__(self, x): r""" Test if x is an element of this group. This checks that x defines (is?) a 2x2 integer matrix of determinant 1, and then hands over to the routine _contains_sl2, which derived classes should implement. EXAMPLES:: sage: [1,2] in SL2Z # indirect doctest False sage: [1,2,0,1] in SL2Z # indirect doctest True sage: SL2Z([1,2,0,1]) in Gamma(3) # indirect doctest False sage: -1 in SL2Z True sage: 2 in SL2Z False """ # Do not override this function! Derived classes should override # _contains_sl2. if isinstance(x, list) and len(x) == 4: if not (x[0] in ZZ and x[1] in ZZ and x[2] in ZZ and x[3] in ZZ): return False a,b,c,d = map(ZZ, x) if a*d - b*c != 1: return False return self._contains_sl2(a,b,c,d) else: if parent(x) is not SL2Z: try: y = SL2Z(x) except TypeError: return False x = y return self._contains_sl2(x.a(),x.b(),x.c(),x.d())
def __pow__(self, n): """ EXAMPLES:: sage: a = maxima('2') sage: a^(3/4) 2^(3/4) :: sage: f = maxima.function('x','sin(x)') sage: g = maxima('-cos(x)') sage: f^g 1/sin(x)^cos(x) :: sage: f = maxima.function('x','sin(x)') sage: g = maxima('-cos(x)') # not a function sage: g^f (-cos(x))^sin(x) """ P = self._check_valid() if parent(n) is not P: n = P(n) return self._operation("^", n)
def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: sage: bessel_J(0.0, 1.0) 0.765197686557967 sage: bessel_J(0, 1).n(digits=20) 0.76519768655796655145 sage: bessel_J(0.5, 1.5) 0.649838074753747 Check for correct rounding (:trac:`17122`):: sage: R = RealField(113) sage: a = R("8.935761195587725798762818805462843676e-01") sage: aa = RealField(200)(a) sage: for n in [-10..10]: ....: b = bessel_J(R(n), a) ....: bb = R(bessel_J(n, aa)) ....: if b != bb: ....: print n, b-bb """ if parent is not None: x = parent(x) try: return x.jn(Integer(n)) except Exception: pass n, x = get_coercion_model().canonical_coercion(n, x) import mpmath return mpmath_utils.call(mpmath.besselj, n, x, parent=parent)
def index_of_object(self, i): """ Try to return the node of the Dynkin diagram indexing the object `i`. OUTPUT: a node of the Dynkin diagram or ``None`` EXAMPLES:: sage: L = RootSystem(["A",3]).root_lattice() sage: alpha = L.simple_roots() sage: omega = RootSystem(["A",3]).weight_lattice().fundamental_weights() sage: options = L.plot_parse_options(labels=False) sage: options.index_of_object(3) 3 sage: options.index_of_object(alpha[1]) 1 sage: options.index_of_object(omega[2]) 2 sage: options.index_of_object(omega[2]+omega[3]) sage: options.index_of_object(30) sage: options.index_of_object("bla") """ if parent(i) in RootLatticeRealizations and len(i) == 1 and i.leading_coefficient().is_one(): i = i.leading_support() if i in self.space.cartan_type().index_set(): return i return None
def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: sage: bessel_Y(0.5, 1.5) -0.0460831658930974 sage: bessel_Y(1.0+2*I, 3.0+4*I) 0.699410324467538 + 0.228917940896421*I sage: bessel_Y(0, 1).n(256) 0.08825696421567695798292676602351516282781752309067554671104384761199978932351 Check for correct rounding (:trac:`17122`):: sage: R = RealField(113) sage: a = R("8.935761195587725798762818805462843676e-01") sage: aa = RealField(200)(a) sage: for n in [-10..10]: ....: b = bessel_Y(R(n), a) ....: bb = R(bessel_Y(n, aa)) ....: if b != bb: ....: print n, b-bb """ if parent is not None: x = parent(x) try: return x.yn(Integer(n)) except Exception: pass n, x = get_coercion_model().canonical_coercion(n, x) import mpmath return mpmath_utils.call(mpmath.bessely, n, x, parent=parent)
def is_parent_of(self, element): """ Returns whether ``self`` is the parent of ``element`` INPUT: - ``element`` -- any object EXAMPLES:: sage: S = ZZ sage: S.is_parent_of(1) True sage: S.is_parent_of(2/1) False This method differs from :meth:`__contains__` because it does not attempt any coercion:: sage: 2/1 in S, S.is_parent_of(2/1) (True, False) sage: int(1) in S, S.is_parent_of(int(1)) (True, False) """ from sage.structure.element import parent return parent(element) == self
def strongly_finer(self): """ Return the set of ordered set partitions which are strongly finer than ``self``. See :meth:`is_strongly_finer` for the definition of "strongly finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).strongly_finer() sage: C.cardinality() 2 sage: C.list() [[{1}, {3}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).strongly_finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.strongly_finer().list() [[{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: buo = OrderedSetPartition.bottom_up_osp return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])])
def _cmp_(self, other): """ EXAMPLES:: sage: one = lisp(1); two = lisp(2) sage: one == one True sage: one != two True sage: one < two True sage: two > one True sage: one < 1 False sage: two == 2 True """ P = self._check_valid() if parent(other) is not P: other = P(other) if P.eval('(= %s %s)'%(self.name(), other.name())) == P._true_symbol(): return 0 elif P.eval('(< %s %s)'%(self.name(), other.name())) == P._true_symbol(): return -1 else: return 1
def _element_constructor_(self, element): """ Coerce ``element`` into ``self`` INPUT: - ``element`` -- any object This default implementation returns ``element`` if ``self`` is a facade for ``parent(element)`. Otherwise it attempts in turn to coerce ``element`` into each parent ``self`` is a facade for. This implementation is only valid for a facade parent which models the full union of the parents it is a facade for. Other facade parents should redefine :meth:`element_constructor` appropriately. EXAMPLES:: sage: S = Sets().Facades().example("union"); S An example of a facade set: the integers completed by +-infinity sage: S(1) 1 sage: S(1/2) Traceback (most recent call last): ... ValueError: Can't coerce `1/2` in any parent `An example of a facade set: the integers completed by +-infinity` is a facade for sage: S(2/1) 2 sage: S(2/1).parent() Integer Ring sage: S(int(1)) 1 sage: S(int(1)).parent() Integer Ring Facade parents that model strict subsets should redefine :meth:`element_constructor`:: sage: S = Sets().Facades().example(); S An example of facade set: the monoid of positive integers sage: S(-1) Traceback (most recent call last): ... ValueError: %s should be positive """ if self.is_parent_of(element): return element else: parents = self.facade_for() if parents is True: return NotImplementedError for parent in self.facade_for(): try: return parent(element) except Exception: pass raise ValueError, "Can't coerce `%s` in any parent `%s` is a facade for"%(element, self)
def __ne__(self, other): r""" TESTS:: sage: from flatsurf import * sage: t = translation_surfaces.square_torus() sage: F = t.fundamental_group() sage: a,b = F.gens() sage: a != b True sage: a*b != b*a True sage: a*b != a*b False """ return parent(self) is not parent(other) or \ self._polys != other._polys or \ self._edges != other._edges
def __cmp__(self, other): """" EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) sage: b = K(rows=[[1]]) sage: c = K(rows=[[2]]) sage: cmp(b,c) -1 sage: cmp(b,b) 0 If the parent are different, it uses comparison of the parents:: sage: cmp(b,1) == cmp(b.parent(), ZZ) True """ return cmp(parent(self), parent(other)) or cmp(self.value, other.value)
def __eq__(self, other): r""" TESTS:: sage: from flatsurf import * sage: t = translation_surfaces.square_torus() sage: F = t.fundamental_group() sage: a,b = F.gens() sage: a == b False sage: a*b == b*a False sage: a*b == a*b True """ return parent(self) is parent(other) and \ self._polys == other._polys and \ self._edges == other._edges
def __eq__(self, other): r""" Equality test. EXAMPLES:: sage: UCF = UniversalCyclotomicField() sage: UCF.one() == 1 True sage: 1 == UCF.one() True sage: UCF(2/3) == 2/3 True sage: 2/3 == UCF(2/3) True sage: UCF.gen(3) == UCF.gen(5) False sage: UCF.gen(5) + UCF.gen(3) == UCF.gen(3) + UCF.gen(5) True sage: UCF.zero() == None False sage: QQbar.zeta(5) == UCF.gen(5) True sage: UCF.gen(5) == QQbar.zeta(5) True sage: QQbar.zeta(5) == UCF.gen(5,2) False sage: UCF.gen(5,2) == QQbar.zeta(5) False """ if parent(self) is not parent(other): from sage.structure.element import get_coercion_model cm = get_coercion_model() try: self, other = cm.canonical_coercion(self, other) except TypeError: return False return self == other return self._obj == other._obj
def _test_codegrees(self, **options): """ Test the method :meth:`degrees`. INPUT: - ``options`` -- any keyword arguments accepted by :meth:`_tester` EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups sage: W = ComplexReflectionGroups().Finite().example(); W # optional - gap3 Reducible real reflection group of rank 4 and type A2 x B2 sage: W._test_codegrees() # optional - gap3 sage: W = SymmetricGroup(5) sage: W._test_codegrees() We now break the implementation of W.degrees and check that this is caught:: sage: W.codegrees = lambda: (1/1,5) sage: W._test_codegrees() Traceback (most recent call last): ... AssertionError: the codegrees should be integers sage: W.codegrees = lambda: (2,1,-1) sage: W._test_codegrees() Traceback (most recent call last): ... AssertionError: the codegrees should be nonnegative We restore W to its normal state:: sage: del W.codegrees sage: W._test_codegrees() See the documentation for :class:`TestSuite` for more information. """ from sage.structure.element import parent from sage.rings.integer_ring import ZZ tester = self._tester(**options) codegrees = self.codegrees() tester.assertIsInstance(codegrees, tuple, "the codegrees method should return a tuple") tester.assertTrue(all(parent(d) is ZZ for d in codegrees), "the codegrees should be integers") tester.assertTrue(all(d >= 0 for d in codegrees), "the codegrees should be nonnegative") tester.assertEqual(len(codegrees), self.rank(), "the number of codegrees should coincide with the rank") tester.assertEqual(sum(d + 1 for d in codegrees), self.number_of_reflection_hyperplanes(), "the sum of the codegrees should be consistent with the number of reflection hyperplanes")
def __cmp__(self, other): """ Comparison. TESTS:: sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: mg = A.module_generators[0] sage: mg == mg True sage: mg == mg.f(2).e(2) True sage: KT = crystals.TensorProductOfKirillovReshetikhinTableaux(['C',2,1], [[1,2],[2,1]]) sage: A = crystals.AffinizationOf(KT) sage: A(KT.module_generators[3], 1).f(0) == A.module_generators[0] True sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: mg = A.module_generators[0] sage: mg != mg.f(2) True sage: mg != mg.f(2).e(2) False sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: S = A.subcrystal(max_depth=2) sage: sorted(S) [[[1, 1], [2, 2]](0), [[1, 1], [2, 3]](0), [[1, 2], [2, 3]](0), [[1, 1], [3, 3]](0), [[1, 1], [2, 3]](1), [[1, 2], [2, 3]](1), [[1, 2], [3, 3]](1), [[2, 2], [3, 3]](2)] """ if parent(self) is parent(other): return cmp(self._m, other._m) or cmp(self._b, other._b) else: return cmp(parent(self), parent(other))
def __eq__(self, other): """ Non elements of the crystal are incomparable with elements of the crystal (or should it return ``NotImplemented``?). Elements of this crystal are compared using the comparison in the underlying classical crystal. EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) sage: b = K(rows=[[1]]) sage: c = K(rows=[[2]]) sage: b==c False sage: b==b True sage: b==1 False """ return parent(self) is parent(other) and self.value == other.value
def _evalf_(self, u, m, parent=None, algorithm=None): """ EXAMPLES:: sage: elliptic_eu(1,1).n() 0.761594155955765 sage: elliptic_eu(1,1).n(200) 0.7615941559557648881194582... """ R = parent or parent(z) return mpmath_utils.call(elliptic_eu_f, u, m, parent=R)
def __lt__(self, other): """ Non elements of the crystal are incomparable with elements of the crystal (or should it return NotImplemented?) Comparison of two elements of this crystal: - different length: incomparable - otherwise lexicographicaly, considering self[i] and other[i] as incomparable if self[i] < other[i] returns NotImplemented """ if parent(self) is not parent(other): return False if len(self) != len(other): return False for i in range(len(self)): if (self[i] < other[i]) == True: return True if (other[i] < self[i]) == True: return False return False
def __pow__(self, n): """ EXAMPLES:: sage: a = maxima('2') sage: a^(3/4) 2^(3/4) """ P = self._check_valid() if parent(n) is not P: n = P(n) return self._operation("^", n)
def __init__(self, p, a, b, s, t, sign): r""" Construct the similarity (x,y) mapsto (ax-by+s,bx+ay+t) if sign=1, and (ax+by+s,bx-ay+t) if sign=-1 """ if p is None: raise ValueError("The parent must be provided") field = p._field if parent(a) is not field or \ parent(b) is not field or \ parent(s) is not field or \ parent(t) is not field: raise ValueError("wrong parent for a,b,s or t") self._a = a self._b = b self._s = s self._t = t if parent(sign) is not ZZ or not sign.is_unit(): raise ValueError("sign must be either 1 or -1.") self._sign = sign MultiplicativeGroupElement.__init__(self, p)
def _element_constructor_(self, *args, **kwds): if len(args)!=1: return self.element_class(self, *args, **kwds) x = args[0] p=parent(x) if self._f.has_coerce_map_from(p): return self.element_class( self,self._f(x), self._f.zero(), self._f.zero(), self._f.zero()) if isinstance(p, SimilarityGroup): return self.element_class(self, x.a(), x.b(), x.s(), x.t()) if isinstance(p, TranslationGroup): return self.element_class( self,self._f.one(), self._f.zero(), x.s(), x.t() ) return self.element_class(self, x, **kwds)
def __contains__(self, elt): """ EXAMPLES:: sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: J = A.ideal(A([0,1])) sage: A([0,1]) in J True sage: A([1,0]) in J False """ if self.ring() is not parent(elt): return False return elt.vector() in self.vector_space()
def _evalf_(self, z, parent=None, algorithm=None): """ EXAMPLES:: sage: elliptic_kc(1/2).n() 1.85407467730137 sage: elliptic_kc(1/2).n(200) 1.85407467730137191843385034... sage: elliptic_kc(I).n() 1.42127228104504 + 0.295380284214777*I """ R = parent or parent(z) from mpmath import ellipk return mpmath_utils.call(ellipk, z, parent=R)
def _evalf_(self, z, m, parent=None, algorithm=None): """ EXAMPLES:: sage: elliptic_f(1,1).n() 1.22619117088352 sage: elliptic_f(1,1).n(200) 1.22619117088351707081306096... sage: elliptic_f(I,I).n() 0.149965060031782 + 0.925097284105771*I """ R = parent or parent(z) from mpmath import ellipf return mpmath_utils.call(ellipf, z, m, parent=R)
def _evalf_(self, x, parent=None, algorithm=None): """ EXAMPLES:: sage: elliptic_ec(sqrt(2)/2).n() 1.23742252487318 sage: elliptic_ec(sqrt(2)/2).n(200) 1.237422524873181672854746084083... sage: elliptic_ec(I).n() 1.63241178144043 - 0.369219492375499*I """ R = parent or parent(z) from mpmath import ellipe return mpmath_utils.call(ellipe, x, parent=R)
def _element_constructor_(self, x, check=False): r""" Create an element from x. This may be either an element of self, an element of the ambient group, or an iterable (in which case the result is the corresponding product of the generators of self). EXAMPLES:: sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2]) sage: G(V([6,2])) (6, 2) sage: G([1,1]) doctest:...: DeprecationWarning: The default behaviour changed! If you *really* want a linear combination of smith generators, use .linear_combination_of_smith_form_gens. See http://trac.sagemath.org/16261 for details. (6, 2) sage: G(G([1,1])) (6, 2) """ if parent(x) is self.universe(): return self.element_class(self, self._discrete_log(x), element=x) return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_( self, x, check)
def finer(self): """ Return the set of ordered set partitions which are finer than ``self``. See :meth:`is_finer` for the definition of "finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).finer() sage: C.cardinality() 3 sage: C.list() [[{1}, {3}, {2}], [{3}, {1}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.finer().list() [[{9}, {4}, {2}, {-1}], [{9}, {4}, {-1}, {2}], [{9}, {4}, {-1, 2}], [{4}, {9}, {2}, {-1}], [{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {2}, {-1}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) for C in cartesian_product([OrderedSetPartitions(X) for X in self])])
def strongly_finer(self): """ Return the set of ordered set partitions which are strongly finer than ``self``. See :meth:`is_strongly_finer` for the definition of "strongly finer". EXAMPLES:: sage: C = OrderedSetPartition([[1, 3], [2]]).strongly_finer() sage: C.cardinality() 2 sage: C.list() [[{1}, {3}, {2}], [{1, 3}, {2}]] sage: OrderedSetPartition([]).strongly_finer() {[]} sage: W = OrderedSetPartition([[4, 9], [-1, 2]]) sage: W.strongly_finer().list() [[{4}, {9}, {-1}, {2}], [{4}, {9}, {-1, 2}], [{4, 9}, {-1}, {2}], [{4, 9}, {-1, 2}]] """ par = parent(self) if not self: return FiniteEnumeratedSet([self]) else: buo = OrderedSetPartition.bottom_up_osp return FiniteEnumeratedSet([ par(sum((list(P) for P in C), [])) for C in cartesian_product( [[buo(X, comp) for comp in Compositions(len(X))] for X in self]) ])
def __gt__(self, other): if parent(self) is not parent(other): return NotImplemented return other.__lt__(self)
def _element_constructor_(self, elt): r""" TESTS:: sage: UCF = UniversalCyclotomicField() sage: UCF(3) 3 sage: UCF(3/2) 3/2 sage: C = CyclotomicField(13) sage: UCF(C.gen()) E(13) sage: UCF(C.gen() - 3*C.gen()**2 + 5*C.gen()**5) E(13) - 3*E(13)^2 + 5*E(13)^5 sage: C = CyclotomicField(12) sage: zeta12 = C.gen() sage: a = UCF(zeta12 - 3* zeta12**2) sage: a -E(12)^7 + 3*E(12)^8 sage: C(_) == a True sage: UCF('[[0, 1], [0, 2]]') Traceback (most recent call last): ... TypeError: [ [ 0, 1 ], [ 0, 2 ] ] of type <type 'sage.libs.gap.element.GapElement_List'> not valid to initialize an element of the universal cyclotomic field Some conversions from symbolic functions are possible:: sage: UCF = UniversalCyclotomicField() sage: [UCF(sin(pi/k, hold=True)) for k in range(1,10)] [0, 1, -1/2*E(12)^7 + 1/2*E(12)^11, 1/2*E(8) - 1/2*E(8)^3, -1/2*E(20)^13 + 1/2*E(20)^17, 1/2, -1/2*E(28)^19 + 1/2*E(28)^23, 1/2*E(16)^3 - 1/2*E(16)^5, -1/2*E(36)^25 + 1/2*E(36)^29] sage: [UCF(cos(pi/k, hold=True)) for k in range(1,10)] [-1, 0, 1/2, 1/2*E(8) - 1/2*E(8)^3, -1/2*E(5)^2 - 1/2*E(5)^3, -1/2*E(12)^7 + 1/2*E(12)^11, -1/2*E(7)^3 - 1/2*E(7)^4, 1/2*E(16) - 1/2*E(16)^7, -1/2*E(9)^4 - 1/2*E(9)^5] .. TODO:: Implement conversion from QQbar (and as a consequence from the symbolic ring) """ elt = py_scalar_to_element(elt) if isinstance(elt, (Integer, Rational)): return self.element_class(self, libgap(elt)) elif isinstance( elt, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)): return self.element_class(self, elt) elif not elt: return self.zero() obj = None if isinstance(elt, gap.GapElement): obj = libgap(elt) elif isinstance(elt, gap3.GAP3Element): obj = libgap.eval(str(elt)) elif isinstance(elt, str): obj = libgap.eval(elt) if obj is not None: if not isinstance(obj, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)): raise TypeError( "{} of type {} not valid to initialize an element of the universal cyclotomic field" .format(obj, type(obj))) return self.element_class(self, obj) # late import to avoid slowing down the above conversions from sage.rings.number_field.number_field_element import NumberFieldElement from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField P = parent(elt) if isinstance(elt, NumberFieldElement) and isinstance( P, NumberField_cyclotomic): n = P.gen().multiplicative_order() elt = CyclotomicField(n)(elt) return sum(c * self.gen(n, i) for i, c in enumerate(elt._coefficients())) if hasattr(elt, '_algebraic_'): return elt._algebraic_(self) raise TypeError( "{} of type {} not valid to initialize an element of the universal cyclotomic field" .format(elt, type(elt)))
def __call__(self, x=None, order=unk): """ EXAMPLES:: sage: from sage.combinat.species.stream import Stream sage: L = LazyPowerSeriesRing(QQ) sage: L() Uninitialized lazy power series sage: L(1) 1 sage: L(ZZ).coefficients(10) [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] sage: L(iter(ZZ)).coefficients(10) [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] sage: L(Stream(ZZ)).coefficients(10) [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] :: sage: a = L([1,2,3]) sage: a.coefficients(3) [1, 2, 3] sage: L(a) is a True sage: L_RR = LazyPowerSeriesRing(RR) sage: b = L_RR(a) sage: b.coefficients(3) [1.00000000000000, 2.00000000000000, 3.00000000000000] sage: L(b) Traceback (most recent call last): ... TypeError: do not know how to coerce ... into self TESTS:: sage: L(pi) Traceback (most recent call last): ... TypeError: do not know how to coerce pi into self """ cls = self._element_class BR = self.base_ring() if x is None: res = cls(self, stream=None, order=unk, aorder=unk, aorder_changed=True, is_initialized=False) res.compute_aorder = uninitialized return res if isinstance(x, LazyPowerSeries): x_parent = x.parent() if x_parent.__class__ != self.__class__: raise ValueError if x_parent.base_ring() == self.base_ring(): return x else: if self.base_ring().has_coerce_map_from(x_parent.base_ring()): return x._new(partial(x._change_ring_gen, self.base_ring()), lambda ao: ao, x, parent=self) if BR.has_coerce_map_from(parent(x)): x = BR(x) return self.term(x, 0) if hasattr(x, "__iter__") and not isinstance(x, Stream_class): x = iter(x) if is_iterator(x): x = Stream(x) if isinstance(x, Stream_class): aorder = order if order != unk else 0 return cls(self, stream=x, order=order, aorder=aorder, aorder_changed=False, is_initialized=True) elif not isinstance(x, Element): x = BR(x) return self.term(x, 0) raise TypeError("do not know how to coerce %s into self" % x)
def balance_sample(s, q=None): r""" Given ``(a,c) = s`` return a tuple ``(a',c')`` where ``a'`` is an integer vector with entries between -q//2 and q//2 and ``c`` is also within these bounds. If ``q`` is given ``(a,c) = s`` may live in the integers. If ``q`` is not given, then ``(a,c)`` are assumed to live in `\Zmod{q}`. INPUT: - ``s`` - sample of the form (a,c) where a is a vector and c is a scalar - ``q`` - modulus (default: ``None``) EXAMPLE:: sage: from sage.crypto.lwe import balance_sample, samples, Regev sage: map(balance_sample, samples(10, 5, Regev)) [((-9, -4, -4, 4, -4), 6), ((-3, -10, 8, -3, -1), -10), ((-6, -12, -3, -2, -6), -6), ... ((-1, -8, -11, 13, 4), -6), ((10, 11, -3, -13, 0), 6), ((6, -1, 2, -11, 14), 2)] sage: from sage.crypto.lwe import balance_sample, DiscreteGaussianPolynomialSampler, RingLWE, samples sage: D = DiscreteGaussianPolynomialSampler(8, 5) sage: rlwe = RingLWE(20, 257, D) sage: map(balance_sample, samples(10, 8, rlwe)) [((5, -55, -31, -90, 6, 100, -46, -107), (6, -64, -40, 117, 27, 54, -98, -56)), ((109, -106, 28, 77, -14, -109, 115, 34), (82, 17, -89, 62, 1, -77, 128, 64)), ... ((-32, 51, -110, -106, 35, -82, 14, -113), (126, -120, 126, 119, 101, 3, -122, -75))] .. note:: This function is useful to convert between Sage's standard representation of elements in `\Zmod{q}` as integers between 0 and q-1 and the usual representation of such elements in lattice cryptography as integers between -q//2 and q//2. """ a, c = s try: c[0] scalar = False except TypeError: c = vector(c.parent(), [c]) scalar = True if q is None: q = parent(c[0]).order() a = a.change_ring(ZZ) c = c.change_ring(ZZ) else: K = IntegerModRing(q) a = a.change_ring(K).change_ring(ZZ) c = c.change_ring(K).change_ring(ZZ) q2 = q // 2 if scalar: return vector(ZZ, len(a), [e if e <= q2 else e - q for e in a]), c[0] if c[0] <= q2 else c[0] - q else: return vector(ZZ, len(a), [e if e <= q2 else e - q for e in a]), vector( ZZ, len(c), [e if e <= q2 else e - q for e in c])
def _element_constructor_(self, x, n=0): r""" Construct a Laurent series from `x`. INPUT: - ``x`` -- object that can be converted into a Laurent series - ``n`` -- (default: 0) multiply the result by `t^n` EXAMPLES:: sage: R.<u> = LaurentSeriesRing(Qp(5, 10)) sage: S.<t> = LaurentSeriesRing(RationalField()) sage: print R(t + t^2 + O(t^3)) (1 + O(5^10))*u + (1 + O(5^10))*u^2 + O(u^3) Note that coercing an element into its own parent just produces that element again (since Laurent series are immutable):: sage: u is R(u) True Rational functions are accepted:: sage: I = sqrt(-1) sage: K.<I> = QQ[I] sage: P.<t> = PolynomialRing(K) sage: L.<u> = LaurentSeriesRing(QQ[I]) sage: L((t*I)/(t^3+I*2*t)) 1/2 + 1/4*I*u^2 - 1/8*u^4 - 1/16*I*u^6 + 1/32*u^8 + 1/64*I*u^10 - 1/128*u^12 - 1/256*I*u^14 + 1/512*u^16 + 1/1024*I*u^18 + O(u^20) :: sage: L(t*I) / L(t^3+I*2*t) 1/2 + 1/4*I*u^2 - 1/8*u^4 - 1/16*I*u^6 + 1/32*u^8 + 1/64*I*u^10 - 1/128*u^12 - 1/256*I*u^14 + 1/512*u^16 + 1/1024*I*u^18 + O(u^20) TESTS: When converting from `R((z))` to `R((z))((w))`, the variable `z` is sent to `z` rather than to `w` (see :trac:`7085`):: sage: A.<z> = LaurentSeriesRing(QQ) sage: B.<w> = LaurentSeriesRing(A) sage: B(z) z sage: z/w z*w^-1 Various conversions from PARI (see also :trac:`2508`):: sage: L.<q> = LaurentSeriesRing(QQ) sage: L.set_default_prec(10) sage: L(pari('1/x')) q^-1 sage: L(pari('poltchebi(5)')) 5*q - 20*q^3 + 16*q^5 sage: L(pari('poltchebi(5) - 1/x^4')) -q^-4 + 5*q - 20*q^3 + 16*q^5 sage: L(pari('1/poltchebi(5)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + O(q^9) sage: L(pari('poltchebi(5) + O(x^40)')) 5*q - 20*q^3 + 16*q^5 + O(q^40) sage: L(pari('poltchebi(5) - 1/x^4 + O(x^40)')) -q^-4 + 5*q - 20*q^3 + 16*q^5 + O(q^40) sage: L(pari('1/poltchebi(5) + O(x^10)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + 8192/125*q^9 + O(q^10) sage: L(pari('1/poltchebi(5) + O(x^10)'), -10) # Multiply by q^-10 1/5*q^-11 + 4/5*q^-9 + 64/25*q^-7 + 192/25*q^-5 + 2816/125*q^-3 + 8192/125*q^-1 + O(1) sage: L(pari('O(x^-10)')) O(q^-10) """ from sage.rings.fraction_field_element import is_FractionFieldElement from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.multi_polynomial_element import is_MPolynomial from sage.structure.element import parent P = parent(x) if isinstance(x, self.element_class) and n == 0 and P is self: return x # ok, since Laurent series are immutable (no need to make a copy) elif P is self.base_ring(): # Convert x into a power series; if P is itself a Laurent # series ring A((t)), this prevents the implementation of # LaurentSeries.__init__() from effectively applying the # ring homomorphism A((t)) -> A((t))((u)) sending t to u # instead of the one sending t to t. We cannot easily # tell LaurentSeries.__init__() to be more strict, because # A((t)) -> B((u)) is expected to send t to u if A admits # a coercion to B but A((t)) does not, and this condition # would be inefficient to check there. x = self.power_series_ring()(x) elif isinstance(x, pari_gen): t = x.type() if t == "t_RFRAC": # Rational function x = self(self.polynomial_ring()(x.numerator())) / \ self(self.polynomial_ring()(x.denominator())) return (x << n) elif t == "t_SER": # Laurent series n += x._valp() bigoh = n + x.length() x = self(self.polynomial_ring()(x.Vec())) return (x << n).add_bigoh(bigoh) else: # General case, pretend to be a polynomial return self(self.polynomial_ring()(x)) << n elif is_FractionFieldElement(x) and \ (x.base_ring() is self.base_ring() or x.base_ring() == self.base_ring()) and \ (is_Polynomial(x.numerator()) or is_MPolynomial(x.numerator())): x = self(x.numerator()) / self(x.denominator()) return (x << n) return self.element_class(self, x, n)
def reduce_load(parent, x): return parent(x)
def _element_constructor_(self, elt): r""" TESTS:: sage: UCF = UniversalCyclotomicField() sage: UCF(3) 3 sage: UCF(3/2) 3/2 sage: C = CyclotomicField(13) sage: UCF(C.gen()) E(13) sage: UCF(C.gen() - 3*C.gen()**2 + 5*C.gen()**5) E(13) - 3*E(13)^2 + 5*E(13)^5 sage: C = CyclotomicField(12) sage: zeta12 = C.gen() sage: a = UCF(zeta12 - 3* zeta12**2) sage: a -E(12)^7 + 3*E(12)^8 sage: C(_) == a True sage: UCF('[[0, 1], [0, 2]]') Traceback (most recent call last): ... TypeError: [ [ 0, 1 ], [ 0, 2 ] ] of type <type 'sage.libs.gap.element.GapElement_List'> not valid to initialize an element of the universal cyclotomic field .. TODO:: Implement conversion from QQbar (and as a consequence from the symbolic ring) """ elt = py_scalar_to_element(elt) if isinstance(elt, (Integer, Rational)): return self.element_class(self, libgap(elt)) elif isinstance(elt, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)): return self.element_class(self, elt) elif not elt: return self.zero() obj = None if isinstance(elt, gap.GapElement): obj = libgap(elt) elif isinstance(elt, gap3.GAP3Element): obj = libgap.eval(str(elt)) elif isinstance(elt, str): obj = libgap.eval(elt) if obj is not None: if not isinstance(obj, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)): raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(obj, type(obj))) return self.element_class(self, obj) # late import to avoid slowing down the above conversions from sage.rings.number_field.number_field_element import NumberFieldElement from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField P = parent(elt) if isinstance(elt, NumberFieldElement) and isinstance(P, NumberField_cyclotomic): n = P.gen().multiplicative_order() elt = CyclotomicField(n)(elt) return sum(c * self.gen(n, i) for i, c in enumerate(elt._coefficients())) else: raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(elt, type(elt)))
def _element_constructor_(self, x, e=1, prec=infinity): r""" Construct a Puiseux series from ``x``. INPUT: - ``x`` -- an object that can be converted into a Puiseux series - ``e`` -- (default: ``1``) the ramification index of the series - ``prec`` -- (default: ``infinity``) the precision of the series as a rational number EXAMPLES:: sage: P = PuiseuxSeriesRing(QQ, 'y') sage: y = P.gen() sage: P([1,3,5,7]) 1 + 3*y + 5*y^2 + 7*y^3 sage: P(33/14) 33/14 sage: Q = PowerSeriesRing(QQ, 'y') sage: z = Q([1,2,4,5]).O(6); z 1 + 2*y + 4*y^2 + 5*y^3 + O(y^6) sage: P(z) + y**(1/2) 1 + y^(1/2) + 2*y + 4*y^2 + 5*y^3 + O(y^6) sage: Q = LaurentSeriesRing(QQ, 'y') sage: z = Q([3,2,1,2]).add_bigoh(5); z 3 + 2*y + y^2 + 2*y^3 + O(y^5) sage: P(z) + y**(1/2) 3 + y^(1/2) + 2*y + y^2 + 2*y^3 + O(y^5) sage: from sage.modular.etaproducts import qexp_eta sage: y^(1/24)*qexp_eta(P, prec=30) y^(1/24) - y^(25/24) - y^(49/24) + y^(121/24) + y^(169/24) - y^(289/24) - y^(361/24) + y^(529/24) + y^(625/24) + O(y^(721/24)) """ P = parent(x) # 1. x is a Puiseux series belonging to this ring. # This is short-circuited by the coercion framework. #if isinstance(x, self.element_class) and P is self: # return x # 2. x is a Puiseux series but not an element of this ring. the laurent # part should be coercible to the laurent series ring of self if isinstance(x, self.element_class): l = self._laurent_series_ring(x.laurent_part()) e = x.ramification_index() # 3. x is a member of the base ring then convert x to a laurent series # and set the ramification index of the Puiseux series to 1. elif P is self.base_ring(): l = self._laurent_series_ring(x) e = 1 # 4. x is a Laurent or power series with the same base ring elif (isinstance(x, (LaurentSeries, PowerSeries)) and P is self.base_ring()): l = self._laurent_series_ring(x) # 5. everything else: try to coerce to laurent series ring else: l = self._laurent_series_ring(x) # finally, construct an instance of the element class and adding # the precision afterwards (see also :trac:`28993`). return self.element_class(self, l, e=e).add_bigoh(prec)
def __call__(self, *values): """ Replace the generators of the free group by corresponding elements of the iterable ``values`` in the group element ``self``. INPUT: - ``*values`` -- a sequence of values, or a list/tuple/iterable of the same length as the number of generators of the free group. OUTPUT: The product of ``values`` in the order and with exponents specified by ``self``. EXAMPLES:: sage: G.<a,b> = FreeGroup() sage: w = a^2 * b^-1 * a^3 sage: w(1, 2) 1/2 sage: w(2, 1) 32 sage: w.subs(b=1, a=2) # indirect doctest 32 TESTS:: sage: w([1, 2]) 1/2 sage: w((1, 2)) 1/2 sage: w(i+1 for i in range(2)) 1/2 Check that :trac:`25017` is fixed:: sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = F(1) sage: parent(u.subs({x1:x0})) is F True sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = x0*x1 sage: u.subs({x0:3, x1:2}) 6 sage: u.subs({x0:1r, x1:2r}) 2 sage: M0 = matrix(ZZ,2,[1,1,0,1]) sage: M1 = matrix(ZZ,2,[1,0,1,1]) sage: u.subs({x0: M0, x1: M1}) [2 1] [1 1] TESTS:: sage: F.<x,y> = FreeGroup() sage: F.one().subs(x=x, y=1) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Free Group on generators {x, y}' and 'Integer Ring' """ if len(values) == 1: try: values = list(values[0]) except TypeError: pass G = self.parent() if len(values) != G.ngens(): raise ValueError( 'number of values has to match the number of generators') replace = dict(zip(G.gens(), values)) new_parent = coercion_model.common_parent(*[parent(v) for v in values]) try: return new_parent.prod(replace[gen]**power for gen, power in self.syllables()) except AttributeError: return prod( new_parent(replace[gen])**power for gen, power in self.syllables())
def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): """ A mutable list of elements with a common guaranteed universe, which can be set immutable. A universe is either an object that supports coercion (e.g., a parent), or a category. INPUT: - ``x`` - a list or tuple instance - ``universe`` - (default: None) the universe of elements; if None determined using canonical coercions and the entire list of elements. If list is empty, is category Objects() of all objects. - ``check`` -- (default: True) whether to coerce the elements of x into the universe - ``immutable`` - (default: True) whether or not this sequence is immutable - ``cr`` - (default: False) if True, then print a carriage return after each comma when printing this sequence. - ``cr_str`` - (default: False) if True, then print a carriage return after each comma when calling ``str()`` on this sequence. - ``use_sage_types`` -- (default: False) if True, coerce the built-in Python numerical types int, long, float, complex to the corresponding Sage types (this makes functions like vector() more flexible) OUTPUT: - a sequence EXAMPLES:: sage: v = Sequence(range(10)) sage: v.universe() <type 'int'> sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] We can request that the built-in Python numerical types be coerced to Sage objects:: sage: v = Sequence(range(10), use_sage_types=True) sage: v.universe() Integer Ring sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] You can also use seq for "Sequence", which is identical to using Sequence:: sage: v = seq([1,2,1/1]); v [1, 2, 1] sage: v.universe() Rational Field sage: v.parent() Category of sequences in Rational Field sage: v.parent()([3,4/3]) [3, 4/3] Note that assignment coerces if possible,:: sage: v = Sequence(range(10), ZZ) sage: a = QQ(5) sage: v[3] = a sage: parent(v[3]) Integer Ring sage: parent(a) Rational Field sage: v[3] = 2/3 Traceback (most recent call last): ... TypeError: no conversion of this rational to integer Sequences can be used absolutely anywhere lists or tuples can be used:: sage: isinstance(v, list) True Sequence can be immutable, so entries can't be changed:: sage: v = Sequence([1,2,3], immutable=True) sage: v.is_immutable() True sage: v[0] = 5 Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. Only immutable sequences are hashable (unlike Python lists), though the hashing is potentially slow, since it first involves conversion of the sequence to a tuple, and returning the hash of that.:: sage: v = Sequence(range(10), ZZ, immutable=True) sage: hash(v) 1591723448 # 32-bit -4181190870548101704 # 64-bit If you really know what you are doing, you can circumvent the type checking (for an efficiency gain):: sage: list.__setitem__(v, int(1), 2/3) # bad circumvention sage: v [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] sage: list.__setitem__(v, int(1), int(2)) # not so bad circumvention You can make a sequence with a new universe from an old sequence.:: sage: w = Sequence(v, QQ) sage: w [0, 2, 2, 3, 4, 5, 6, 7, 8, 9] sage: w.universe() Rational Field sage: w[1] = 2/3 sage: w [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] Sequences themselves live in a category, the category of all sequences in the given universe.:: sage: w.category() Category of sequences in Rational Field This is also the parent of any sequence:: sage: w.parent() Category of sequences in Rational Field The default universe for any sequence, if no compatible parent structure can be found, is the universe of all Sage objects. This example illustrates how every element of a list is taken into account when constructing a sequence.:: sage: v = Sequence([1,7,6,GF(5)(3)]); v [1, 2, 1, 3] sage: v.universe() Finite Field of size 5 sage: v.parent() Category of sequences in Finite Field of size 5 sage: v.parent()([7,8,9]) [2, 3, 4] """ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal if isinstance(x, Sequence_generic) and universe is None: universe = x.universe() x = list(x) if isinstance(x, MPolynomialIdeal) and universe is None: universe = x.ring() x = x.gens() if universe is None: if not isinstance(x, (list, tuple)): x = list(x) #raise TypeError("x must be a list or tuple") if len(x) == 0: import sage.categories.all universe = sage.categories.all.Objects() else: import sage.structure.element as coerce y = x x = list(x) # make a copy, or we'd change the type of the elements of x, which would be bad. if use_sage_types: # convert any Python built-in numerical types to Sage objects from sage.rings.integer_ring import ZZ from sage.rings.real_double import RDF from sage.rings.complex_double import CDF for i in range(len(x)): if isinstance(x[i], int) or isinstance(x[i], long): x[i] = ZZ(x[i]) elif isinstance(x[i], float): x[i] = RDF(x[i]) elif isinstance(x[i], complex): x[i] = CDF(x[i]) # start the pairwise coercion for i in range(len(x)-1): try: x[i], x[i+1] = coerce.canonical_coercion(x[i],x[i+1]) except TypeError: import sage.categories.all universe = sage.categories.all.Objects() x = list(y) check = False # no point break if universe is None: # no type errors raised. universe = coerce.parent(x[len(x)-1]) from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.quotient_ring import is_QuotientRing from sage.rings.polynomial.pbori import BooleanMonomialMonoid if is_MPolynomialRing(universe) or \ (is_QuotientRing(universe) and is_MPolynomialRing(universe.cover_ring())) or \ isinstance(universe, BooleanMonomialMonoid): from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence try: return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) except (TypeError,AttributeError): return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) else: return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types)
def q_binomial(n, k, q=None, algorithm='auto'): r""" Return the `q`-binomial coefficient. This is also known as the Gaussian binomial coefficient, and is defined by .. MATH:: \binom{n}{k}_q = \frac{(1-q^n)(1-q^{n-1}) \cdots (1-q^{n-k+1})} {(1-q)(1-q^2)\cdots (1-q^k)}. See :wikipedia:`Gaussian_binomial_coefficient`. If `q` is unspecified, then the variable is the generator `q` for a univariate polynomial ring over the integers. INPUT: - ``n, k`` -- the values `n` and `k` defined above - ``q`` -- (default: ``None``) the variable `q`; if ``None``, then use a default variable in `\ZZ[q]` - ``algorithm`` -- (default: ``'auto'``) the algorithm to use and can be one of the following: - ``'auto'`` -- automatically choose the algorithm; see the algorithm section below - ``'naive'`` -- use the naive algorithm - ``'cyclotomic'`` -- use cyclotomic algorithm ALGORITHM: The naive algorithm uses the product formula. The cyclotomic algorithm uses a product of cyclotomic polynomials (cf. [CH2006]_). When the algorithm is set to ``'auto'``, we choose according to the following rules: - If ``q`` is a polynomial: When ``n`` is small or ``k`` is small with respect to ``n``, one uses the naive algorithm. When both ``n`` and ``k`` are big, one uses the cyclotomic algorithm. - If ``q`` is in the symbolic ring, one uses the cyclotomic algorithm. - Otherwise one uses the naive algorithm, unless ``q`` is a root of unity, then one uses the cyclotomic algorithm. EXAMPLES: By default, the variable is the generator of `\ZZ[q]`:: sage: from sage.combinat.q_analogues import q_binomial sage: g = q_binomial(5,1) ; g q^4 + q^3 + q^2 + q + 1 sage: g.parent() Univariate Polynomial Ring in q over Integer Ring The `q`-binomial coefficient vanishes unless `0 \leq k \leq n`:: sage: q_binomial(4,5) 0 sage: q_binomial(5,-1) 0 Other variables can be used, given as third parameter:: sage: p = ZZ['p'].gen() sage: q_binomial(4,2,p) p^4 + p^3 + 2*p^2 + p + 1 The third parameter can also be arbitrary values:: sage: q_binomial(5,1,2) == g.subs(q=2) True sage: q_binomial(5,1,1) 5 sage: q_binomial(4,2,-1) 2 sage: q_binomial(4,2,3.14) 152.030056160000 sage: R = GF(25, 't') sage: t = R.gen(0) sage: q_binomial(6, 3, t) 2*t + 3 We can also do this for more complicated objects such as matrices or symmetric functions:: sage: q_binomial(4,2,matrix([[2,1],[-1,3]])) [ -6 84] [-84 78] sage: Sym = SymmetricFunctions(QQ) sage: s = Sym.schur() sage: q_binomial(4,1, s[2]+s[1]) s[] + s[1] + s[1, 1] + s[1, 1, 1] + 2*s[2] + 4*s[2, 1] + 3*s[2, 1, 1] + 4*s[2, 2] + 3*s[2, 2, 1] + s[2, 2, 2] + 3*s[3] + 7*s[3, 1] + 3*s[3, 1, 1] + 6*s[3, 2] + 2*s[3, 2, 1] + s[3, 3] + 4*s[4] + 6*s[4, 1] + s[4, 1, 1] + 3*s[4, 2] + 3*s[5] + 2*s[5, 1] + s[6] TESTS: One checks that the first two arguments are integers:: sage: q_binomial(1/2,1) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer One checks that `n` is nonnegative:: sage: q_binomial(-4,1) Traceback (most recent call last): ... ValueError: n must be nonnegative This also works for variables in the symbolic ring:: sage: z = var('z') sage: factor(q_binomial(4,2,z)) (z^2 + z + 1)*(z^2 + 1) This also works for complex roots of unity:: sage: q_binomial(6, 1, QQbar(I)) I + 1 Note that the symbolic computation works (see :trac:`14982`):: sage: q_binomial(6, 1, I) I + 1 Check that the algorithm does not matter:: sage: q_binomial(6,3, algorithm='naive') == q_binomial(6,3, algorithm='cyclotomic') True One more test:: sage: q_binomial(4, 2, Zmod(6)(2), algorithm='naive') 5 Check that it works with Python integer for ``q``:: sage: q_binomial(3r, 2r, 1r) 3 REFERENCES: .. [CH2006] William Y.C. Chen and Qing-Hu Hou, *Factors of the Gaussian coefficients*, Discrete Mathematics 306 (2006), 1446-1449. :doi:`10.1016/j.disc.2006.03.031` AUTHORS: - Frederic Chapoton, David Joyner and William Stein """ # sanity checks n = ZZ(n) k = ZZ(k) if n < 0: raise ValueError('n must be nonnegative') # polynomiality test if q is None: from sage.rings.polynomial.polynomial_ring import polygen q = polygen(ZZ, name='q') is_polynomial = True else: from sage.rings.polynomial.polynomial_element import Polynomial is_polynomial = isinstance(q, Polynomial) R = parent(q) try: zero = R.zero() except AttributeError: zero = R('0') try: one = R.one() except AttributeError: one = R('1') if not(0 <= k and k <= n): return zero k = min(n-k,k) # Pick the smallest k # heuristic choice of the fastest algorithm if algorithm == 'auto': from sage.symbolic.ring import SR if is_polynomial: if n <= 70 or k <= n // 4: algorithm = 'naive' else: algorithm = 'cyclo_polynomial' elif q in SR: algorithm = 'cyclo_generic' else: algorithm = 'naive' elif algorithm == 'cyclotomic': if is_polynomial: algorithm = 'cyclo_polynomial' else: algorithm = 'cyclo_generic' elif algorithm != 'naive': raise ValueError("invalid algorithm choice") # the algorithms if algorithm == 'naive': denom = prod(one - q**i for i in range(1, k+1)) if not denom: # q is a root of unity, use the cyclotomic algorithm from sage.rings.polynomial.cyclotomic import cyclotomic_value return cyclotomic_value(n, k, q, algorithm='cyclotomic') else: num = prod(one - q**i for i in range(n-k+1, n+1)) try: try: return num // denom except TypeError: return num / denom except (TypeError, ZeroDivisionError): # use substitution instead return q_binomial(n,k)(q) elif algorithm == 'cyclo_generic': from sage.rings.polynomial.cyclotomic import cyclotomic_value return prod(cyclotomic_value(d,q) for d in range(2,n+1) if (n//d) != (k//d) + ((n-k)//d)) elif algorithm == 'cyclo_polynomial': return prod(R.cyclotomic_polynomial(d) for d in range(2,n+1) if (n//d) != (k//d) + ((n-k)//d))
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``. * ``'normaliz'``: use normaliz (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. * ``'polymake'``: use polymake (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or ``QuadraticField`` 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)) When the input contains elements of a Number Field, they require an embedding:: sage: K = NumberField(x^2-2,'s') sage: s = K.0 sage: L = NumberField(x^3-2,'t') sage: t = L.0 sage: P = Polyhedron(vertices = [[0,s],[t,0]]) Traceback (most recent call last): ... ValueError: invalid base ring .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``base_ring=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. TESTS: Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`):: sage: f = float(1.1) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`):: sage: Polyhedron(vertices=[[int(42)]]) A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`):: sage: from fractions import Fraction sage: f = Fraction(int(6), int(8)) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex Check that input with too many bits of precision returns an error (see :trac:`22552`):: sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)]) Traceback (most recent call last): ... ValueError: for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd' Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`):: sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) Traceback (most recent call last): ... ValueError: no appropriate backend for computations with Real Field with 40 bits of precision sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) Traceback (most recent call last): ... ValueError: no appropriate backend for computations with Real Field with 53 bits of precision """ # 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('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 from sage.structure.element import parent from sage.categories.all import Rings, Fields values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: convert = any(parent(x) is not base_ring for x in values) elif not values: base_ring = ZZ convert = False else: P = parent(values[0]) if any(parent(x) is not P for x in values): from sage.structure.sequence import Sequence P = Sequence(values).universe() convert = True else: convert = False from sage.structure.coerce import py_scalar_parent if isinstance(P, type): base_ring = py_scalar_parent(P) convert = convert or P is not base_ring else: base_ring = P if not got_Vrep and base_ring not in Fields(): base_ring = base_ring.fraction_field() convert = True if base_ring not in Rings(): raise ValueError('invalid base ring') if not base_ring.is_exact(): # TODO: remove this hack? if base_ring is RR: base_ring = RDF convert = True elif base_ring is not RDF: raise ValueError( "for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'" ) # Add the origin if necessary 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 q_jordan(t, q=None): r""" Return the `q`-Jordan number of `t`. If `q` is the power of a prime number, the output is the number of complete flags in `\GF{q}^N` (where `N` is the size of `t`) stable under a linear nilpotent endomorphism `f_t` whose Jordan type is given by `t`, i.e. such that for all `i`: .. MATH:: \dim (\ker f_t^i) = t[0] + \cdots + t[i-1] If `q` is unspecified, then it defaults to using the generator `q` for a univariate polynomial ring over the integers. The result is cached. INPUT: - ``t`` -- an integer partition, or an argument accepted by :class:`Partition` - ``q`` -- (default: ``None``) the variable `q`; if ``None``, then use a default variable in `\ZZ[q]` EXAMPLES:: sage: from sage.combinat.q_analogues import q_jordan sage: [q_jordan(mu, 2) for mu in Partitions(5)] [9765, 1029, 213, 93, 29, 9, 1] sage: [q_jordan(mu, 2) for mu in Partitions(6)] [615195, 40635, 5643, 2331, 1491, 515, 147, 87, 47, 11, 1] sage: q_jordan([3,2,1]) 16*q^4 + 24*q^3 + 14*q^2 + 5*q + 1 sage: q_jordan([2,1], x) 2*x + 1 If the partition is trivial (i.e. has only one part), we get the `q`-factorial (in this case, the nilpotent endomorphism is necessarily `0`):: sage: from sage.combinat.q_analogues import q_factorial sage: q_jordan([5]) == q_factorial(5) True sage: q_jordan([11], 5) == q_factorial(11, 5) True TESTS:: sage: all(multinomial(mu.conjugate()) == q_jordan(mu, 1) for mu in Partitions(6)) True AUTHOR: - Xavier Caruso (2012-06-29) """ if q is None: q = ZZ['q'].gen() if all(part == 0 for part in t): return parent(q)(1) tj = 0 res = parent(q)(0) for i in range(len(t) - 1, -1, -1): ti = t[i] if ti > tj: tp = list(t) tp[i] -= 1 res += q_jordan(tp, q) * q**tj * q_int(ti - tj, q) tj = ti return res
def _element_constructor_(self, *args, **kwds): r""" TESTS:: sage: from flatsurf.geometry.similarity import SimilarityGroup sage: S = SimilarityGroup(QQ) sage: S((1,1)) # translation (x, y) |-> (x + 1, y + 1) sage: V = QQ^2 sage: S(V((1,-1))) (x, y) |-> (x + 1, y - 1) sage: S(vector((1,1))) (x, y) |-> (x + 1, y + 1) """ if len(args) == 1: x = args[0] else: x = args a = self._ring.one() b = s = t = self._ring.zero() sign = ZZ_1 # TODO: 2x2 and 3x3 matrix input if isinstance(x, (tuple, list)): if len(x) == 2: s, t = map(self._ring, x) elif len(x) == 4: a, b, s, t = map(self._ring, x) elif len(x) == 5: a, b, s, t = map(self._ring, x[:4]) sign = ZZ(x[4]) else: raise ValueError( "can not construct a similarity from a list of length {}". format(len(x))) elif is_Matrix(x): # a -sb # b sa if x.nrows() == x.ncols() == 2: a, c, b, d = x.list() if a == d and b == -c: sign = ZZ_1 elif a == -d and b == c: sign = ZZ_m1 else: raise ValueError("not a similarity matrix") elif x.nrows() == x.ncols() == 3: raise NotImplementedError else: raise ValueError("invalid dimension for matrix input") elif isinstance(x, FreeModuleElement): if len(x) == 2: if x.base_ring() is self._ring: s, t = x else: s, t = map(self._ring, x) else: raise ValueError("invalid dimension for vector input") else: p = parent(x) if self._ring.has_coerce_map_from(p): a = self._ring(x) else: raise ValueError( "element in %s cannot be used to create element in %s" % (p, self)) if (a * a + b * b).is_zero(): raise ValueError("not invertible") return self.element_class(self, a, b, s, t, sign)
def n(x): if parent(x) is SR: return x.numerical_approx() else: return x
def __classcall_private__(cls, ogf): r""" Ensures that elements created by :class:`CFiniteSequence` have the same parent than the ones created by the parent itself and follow the category framework (they should be instance of :class:`CFiniteSequences` automatic element class). This method is called before the ``__init__`` method, it checks the o.g.f to create the appropriate parent. INPUT: - ``ogf`` -- a rational function TESTS:: sage: f1 = CFiniteSequence((2-x)/(1-x-x^2)) sage: f1 C-finite sequence, generated by (x - 2)/(x^2 + x - 1) sage: C.<x> = CFiniteSequences(QQ) sage: f2 = CFiniteSequence((2-x)/(1-x-x^2)) sage: f2 C-finite sequence, generated by (x - 2)/(x^2 + x - 1) sage: f3 = C((2-x)/(1-x-x^2)) sage: f3 C-finite sequence, generated by (x - 2)/(x^2 + x - 1) sage: f1 == f2 and f2 == f3 True sage: f1.parent() == f2.parent() and f2.parent() == f3.parent() True sage: type(f1) <class 'sage.rings.cfinite_sequence.CFiniteSequences_generic_with_category.element_class'> sage: type(f1) == type(f2) and type(f2) == type(f3) True sage: CFiniteSequence(log(x)) Traceback (most recent call last): ... TypeError: unable to convert log(x) to a rational sage: CFiniteSequence(pi) Traceback (most recent call last): ... TypeError: unable to convert pi to a rational sage: var('y') y sage: f4 = CFiniteSequence((2-y)/(1-y-y^2)) sage: f4 C-finite sequence, generated by (y - 2)/(y^2 + y - 1) sage: f4 == f1 False sage: f4.parent() == f1.parent() False sage: f4.parent() The ring of C-Finite sequences in y over Rational Field """ br = ogf.base_ring() if not (br in (QQ, ZZ)): br = QQ # if the base ring of the o.g.f is not QQ, we force it to QQ and see if the o.g.f converts nicely # trying to figure out the ogf variables variables = [] if ogf not in br: if hasattr(ogf, 'variables'): variables = ogf.variables() elif hasattr(ogf.parent(), 'gens'): variables = ogf.parent().gens() # for some reason, fraction field elements don't have the variables # method, but symbolic elements don't have the gens method so we check both if not variables: parent = CFiniteSequences( QQ ) # if we cannot find variables, we create the default parent (with x) else: parent = CFiniteSequences(QQ, variables) return parent( ogf ) # if ogf cannot be converted to a fraction field, this will break and raise the proper error
def q_pochhammer(n, a, q=None): r""" Return the `q`-Pochhammer `(a; q)_n`. The `q`-Pochhammer symbol is defined by .. MATH:: (a; q)_n = \prod_{k=0}^{n-1} (1 - aq^k) with `(a; q)_0 = 1` for all `a, q` and `n \in \NN`. By using the identity .. MATH:: (a; q)_n = \frac{(a; q)_{\infty}}{(aq^n; q)_{\infty}}, we can extend the definition to `n < 0` by .. MATH:: (a; q)_n = \frac{1}{(aq^n; q)_{-n}} = \prod_{k=1}^{-n} \frac{1}{1 - a/q^k}. EXAMPLES:: sage: from sage.combinat.q_analogues import q_pochhammer sage: q_pochhammer(3, 1/7) 6/343*q^3 - 6/49*q^2 - 6/49*q + 6/7 sage: q_pochhammer(3, 3) -18*q^3 + 6*q^2 + 6*q - 2 sage: q_pochhammer(3, 1) 0 sage: R.<q> = ZZ[] sage: q_pochhammer(4, q) q^10 - q^9 - q^8 + 2*q^5 - q^2 - q + 1 sage: q_pochhammer(4, q^2) q^14 - q^12 - q^11 - q^10 + q^8 + 2*q^7 + q^6 - q^4 - q^3 - q^2 + 1 sage: q_pochhammer(-3, q) 1/(-q^9 + q^7 + q^6 + q^5 - q^4 - q^3 - q^2 + 1) TESTS:: sage: q_pochhammer(0, 2) 1 sage: q_pochhammer(0, 1) 1 sage: q_pochhammer(0, var('a')) 1 We check that :trac:`25715` is fixed:: sage: q_pochhammer(0, 3r) 1 REFERENCES: - :wikipedia:`Q-Pochhammer_symbol` """ if q is None: q = ZZ['q'].gen() if n not in ZZ: raise ValueError("{} must be an integer".format(n)) R = parent(q) one = R(1) if n < 0: return R.prod(one / (one - a / q**-k) for k in range(1, -n + 1)) return R.prod((one - a * q**k) for k in range(n))
def q_stirling_number1(n, k, q=None): r""" Return the (unsigned) `q`-Stirling number of the first kind. This is a `q`-analogue of :func:`sage.combinat.combinat.stirling_number1` . INPUT: - ``n``, ``k`` -- integers with ``1 <= k <= n`` - ``q`` -- optional variable (default `q`) OUTPUT: a polynomial in the variable `q` These polynomials satisfy the recurrence .. MATH:: s_{n,k} = s_{n-1,k-1} + [n-1]_q s_{n-1, k}. EXAMPLES:: sage: from sage.combinat.q_analogues import q_stirling_number1 sage: q_stirling_number1(4,2) q^3 + 3*q^2 + 4*q + 3 sage: all(stirling_number1(6,k) == q_stirling_number1(6,k)(1) ....: for k in range(1,7)) True sage: x = polygen(QQ['q'],'x') sage: S = sum(q_stirling_number1(5,k)*x**k for k in range(1, 6)) sage: factor(S) x * (x + 1) * (x + q + 1) * (x + q^2 + q + 1) * (x + q^3 + q^2 + q + 1) TESTS:: sage: q_stirling_number1(-1,2) Traceback (most recent call last): ... ValueError: q-Stirling numbers are not defined for n < 0 We check that :trac:`25715` is fixed:: sage: q_stirling_number1(2,1,1r) 1 REFERENCES: - [Ca1948]_ - [Ca1954]_ """ if q is None: q = ZZ['q'].gen() if n < 0: raise ValueError('q-Stirling numbers are not defined for n < 0') if n == 0 == k: return parent(q)(1) if k > n or k < 1: return parent(q)(0) return (q_stirling_number1(n - 1, k - 1, q=q) + q_int(n - 1, q=q) * q_stirling_number1(n - 1, k, q=q))
def safe_ne(a, b): if parent(a) is not parent(b): logger.debug("comparing elements of %s and %s", parent(a), parent(b)) return True else: return a != b
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True): r""" Construct an elliptic curve. In Sage, an elliptic curve is always specified by its a-invariants .. math:: y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6. INPUT: There are several ways to construct an elliptic curve: - ``EllipticCurve([a1,a2,a3,a4,a6])``: Elliptic curve with given a-invariants. The invariants are coerced into the parent of the first element. If all are integers, they are coerced into the rational numbers. - ``EllipticCurve([a4,a6])``: Same as above, but `a_1=a_2=a_3=0`. - ``EllipticCurve(label)``: Returns the elliptic curve over Q from the Cremona database with the given label. The label is a string, such as ``"11a"`` or ``"37b2"``. The letters in the label *must* be lower case (Cremona's new labeling). - ``EllipticCurve(R, [a1,a2,a3,a4,a6])``: Create the elliptic curve over ``R`` with given a-invariants. Here ``R`` can be an arbitrary ring. Note that addition need not be defined. - ``EllipticCurve(j=j0)`` or ``EllipticCurve_from_j(j0)``: Return an elliptic curve with j-invariant ``j0``. - ``EllipticCurve(polynomial)``: Read off the a-invariants from the polynomial coefficients, see :func:`EllipticCurve_from_Weierstrass_polynomial`. In each case above where the input is a list of length 2 or 5, one can instead give a 2 or 5-tuple instead. EXAMPLES: We illustrate creating elliptic curves:: sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We create a curve from a Cremona label:: sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Old Cremona labels are allowed:: sage: EllipticCurve('2400FF') Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field Unicode labels are allowed:: sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field We create curves over a finite field as follows:: sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type "elliptic curve over a finite field":: sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 101 In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type "generic elliptic curve":: sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 95 The following is a curve over the complex numbers:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 We can also create elliptic curves by giving the Weierstrass equation:: sage: x, y = var('x,y') sage: EllipticCurve(y^2 + y == x^3 + x - 9) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5 We can explicitly specify the `j`-invariant:: sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2 See :trac:`6657` :: sage: EllipticCurve(GF(144169),j=1728) Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 By default, when a rational value of `j` is given, the constructed curve is a minimal twist (minimal conductor for curves with that `j`-invariant). This can be changed by setting the optional parameter ``minimal_twist``, which is True by default, to False:: sage: EllipticCurve(j=100) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E =EllipticCurve(j=100); E Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E.conductor() 33129800 sage: E.j_invariant() 100 sage: E =EllipticCurve(j=100, minimal_twist=False); E Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field sage: E.conductor() 298168200 sage: E.j_invariant() 100 Without this option, constructing the curve could take a long time since both `j` and `j-1728` have to be factored to compute the minimal twist (see :trac:`13100`):: sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False) sage: E.j_invariant() == 2^256+1 True TESTS:: sage: R = ZZ['u', 'v'] sage: EllipticCurve(R, [1,1]) Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v over Integer Ring We create a curve and a point over QQbar (see #6879):: sage: E = EllipticCurve(QQbar,[0,1]) sage: E(0) (0 : 1 : 0) sage: E.base_field() Algebraic Field sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: EllipticCurve(CC,[3,4]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See :trac:`6657` :: sage: EllipticCurve(3,j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified sage: EllipticCurve(GF(5),j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object constructed has type EllipticCurve_field. Otherwise it is EllipticCurve_generic. See :trac:`9816` :: sage: E = EllipticCurve([QQbar(1),3]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([RR(1),3]); E Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([i,i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Symbolic Ring sage: SR in Fields() True sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field See :trac:`12517`:: sage: E = EllipticCurve([1..5]) sage: EllipticCurve(E.a_invariants()) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field See :trac:`11773`:: sage: E = EllipticCurve() Traceback (most recent call last): ... TypeError: invalid input to EllipticCurve constructor """ import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes if j is not None: if not x is None: if is_Ring(x): try: j = x(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError, "First parameter must be a ring containing %s" % j else: raise ValueError, "First parameter (if present) must be a ring when j is specified" return EllipticCurve_from_j(j, minimal_twist) if x is None: raise TypeError, "invalid input to EllipticCurve constructor" 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: return EllipticCurve_from_Weierstrass_polynomial(x) else: return EllipticCurve_from_cubic(x, y, morphism=False) if is_Ring(x): if is_RationalField(x): return ell_rational_field.EllipticCurve_rational_field(x, y) elif is_FiniteField(x) or (is_IntegerModRing(x) and x.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_pAdicField(x): return ell_padic_field.EllipticCurve_padic_field(x, y) elif is_NumberField(x): return ell_number_field.EllipticCurve_number_field(x, y) elif x in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y) if isinstance(x, unicode): x = str(x) if isinstance(x, basestring): return ell_rational_field.EllipticCurve_rational_field(x) if is_RingElement(x) and y is None: raise TypeError, "invalid input to EllipticCurve constructor" if not isinstance(x, (list, tuple)): raise TypeError, "invalid input to EllipticCurve constructor" x = Sequence(x) if not (len(x) in [2, 5]): raise ValueError, "sequence of coefficients must have length 2 or 5" R = x.universe() if isinstance(x[0], (rings.Rational, rings.Integer, int, long)): return ell_rational_field.EllipticCurve_rational_field(x, y) elif is_NumberField(R): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_pAdicField(R): return ell_padic_field.EllipticCurve_padic_field(x, y) elif is_FiniteField(R) or (is_IntegerModRing(R) and R.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif R in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y)
def q_subgroups_of_abelian_group(la, mu, q=None, algorithm='birkhoff'): r""" Return the `q`-number of subgroups of type ``mu`` in a finite abelian group of type ``la``. INPUT: - ``la`` -- type of the ambient group as a :class:`Partition` - ``mu`` -- type of the subgroup as a :class:`Partition` - ``q`` -- (default: ``None``) an indeterminate or a prime number; if ``None``, this defaults to `q \in \ZZ[q]` - ``algorithm`` -- (default: ``'birkhoff'``) the algorithm to use can be one of the following: - ``'birkhoff`` -- use the Birkhoff formula from [Bu87]_ - ``'delsarte'`` -- use the formula from [Delsarte48]_ OUTPUT: The number of subgroups of type ``mu`` in a group of type ``la`` as a polynomial in ``q``. ALGORITHM: Let `q` be a prime number and `\lambda = (\lambda_1, \ldots, \lambda_l)` be a partition. A finite abelian `q`-group is of type `\lambda` if it is isomorphic to .. MATH:: \ZZ / q^{\lambda_1} \ZZ \times \cdots \times \ZZ / q^{\lambda_l} \ZZ. The formula from [Bu87]_ works as follows: Let `\lambda` and `\mu` be partitions. Let `\lambda^{\prime}` and `\mu^{\prime}` denote the conjugate partitions to `\lambda` and `\mu`, respectively. The number of subgroups of type `\mu` in a group of type `\lambda` is given by .. MATH:: \prod_{i=1}^{\mu_1} q^{\mu^{\prime}_{i+1} (\lambda^{\prime}_i - \mu^{\prime}_i)} \binom{\lambda^{\prime}_i - \mu^{\prime}_{i+1}} {\mu^{\prime}_i - \mu^{\prime}_{i+1}}_q The formula from [Delsarte48]_ works as follows: Let `\lambda` and `\mu` be partitions. Let `(s_1, s_2, \ldots, s_l)` and `(r_1, r_2, \ldots, r_k)` denote the parts of the partitions conjugate to `\lambda` and `\mu` respectively. Let .. MATH:: \mathfrak{F}(\xi_1, \ldots, \xi_k) = \xi_1^{r_2} \xi_2^{r_3} \cdots \xi_{k-1}^{r_k} \prod_{i_1=r_2}^{r_1-1} (\xi_1-q^{i_1}) \prod_{i_2=r_3}^{r_2-1} (\xi_2-q^{i_2}) \cdots \prod_{i_k=0}^{r_k-1} (\xi_k-q^{-i_k}). Then the number of subgroups of type `\mu` in a group of type `\lambda` is given by .. MATH:: \frac{\mathfrak{F}(q^{s_1}, q^{s_2}, \ldots, q^{s_k})}{\mathfrak{F} (q^{r_1}, q^{r_2}, \ldots, q^{r_k})}. EXAMPLES:: sage: from sage.combinat.q_analogues import q_subgroups_of_abelian_group sage: q_subgroups_of_abelian_group([1,1], [1]) q + 1 sage: q_subgroups_of_abelian_group([3,3,2,1], [2,1]) q^6 + 2*q^5 + 3*q^4 + 2*q^3 + q^2 sage: R.<t> = QQ[] sage: q_subgroups_of_abelian_group([5,3,1], [3,1], t) t^4 + 2*t^3 + t^2 sage: q_subgroups_of_abelian_group([5,3,1], [3,1], 3) 144 sage: q_subgroups_of_abelian_group([1,1,1], [1]) == q_subgroups_of_abelian_group([1,1,1], [1,1]) True sage: q_subgroups_of_abelian_group([5], [3]) 1 sage: q_subgroups_of_abelian_group([1], [2]) 0 sage: q_subgroups_of_abelian_group([2], [1,1]) 0 TESTS: Check the same examples with ``algorithm='delsarte'``:: sage: q_subgroups_of_abelian_group([1,1], [1], algorithm='delsarte') q + 1 sage: q_subgroups_of_abelian_group([3,3,2,1], [2,1], algorithm='delsarte') q^6 + 2*q^5 + 3*q^4 + 2*q^3 + q^2 sage: q_subgroups_of_abelian_group([5,3,1], [3,1], t, algorithm='delsarte') t^4 + 2*t^3 + t^2 sage: q_subgroups_of_abelian_group([5,3,1], [3,1], 3, algorithm='delsarte') 144 sage: q_subgroups_of_abelian_group([1,1,1], [1], algorithm='delsarte') == q_subgroups_of_abelian_group([1,1,1], [1,1]) True sage: q_subgroups_of_abelian_group([5], [3], algorithm='delsarte') 1 sage: q_subgroups_of_abelian_group([1], [2], algorithm='delsarte') 0 sage: q_subgroups_of_abelian_group([2], [1,1], algorithm='delsarte') 0 Check that :trac:`25715` is fixed:: sage: parent(q_subgroups_of_abelian_group([2], [1], algorithm='delsarte')) Univariate Polynomial Ring in q over Integer Ring sage: q_subgroups_of_abelian_group([7,7,1], []) 1 sage: q_subgroups_of_abelian_group([7,7,1], [0,0]) 1 REFERENCES: .. [Bu87] Butler, Lynne M. *A unimodality result in the enumeration of subgroups of a finite abelian group.* Proceedings of the American Mathematical Society 101, no. 4 (1987): 771-775. :doi:`10.1090/S0002-9939-1987-0911049-8` .. [Delsarte48] \S. Delsarte, *Fonctions de Möbius Sur Les Groupes Abeliens Finis*, Annals of Mathematics, second series, Vol. 45, No. 3, (Jul 1948), pp. 600-609. http://www.jstor.org/stable/1969047 AUTHORS: - Amritanshu Prasad (2013-06-07): Implemented the Delsarte algorithm - Tomer Bauer (2013, 2018): Implemented the Birkhoff algorithm and refactoring """ if q is None: q = ZZ['q'].gen() la_c = _Partitions(la).conjugate() mu_c = _Partitions(mu).conjugate() k = mu_c.length() if not mu_c: # There is only one trivial subgroup return parent(q)(1) if not la_c.contains(mu_c): return parent(q)(0) if algorithm == 'delsarte': def F(args): prd = lambda j: prod(args[j] - q**i for i in range(mu_c[j + 1], mu_c[j])) F1 = prod(args[i]**mu_c[i + 1] * prd(i) for i in range(k - 1)) return F1 * prod(args[k - 1] - q**i for i in range(mu_c[k - 1])) return F([q**ss for ss in la_c[:k]]) // F([q**rr for rr in mu_c]) if algorithm == 'birkhoff': fac1 = q**(sum(mu_c[i + 1] * (la_c[i] - mu_c[i]) for i in range(k - 1))) fac2 = prod( q_binomial(la_c[i] - mu_c[i + 1], mu_c[i] - mu_c[i + 1], q=q) for i in range(k - 1)) fac3 = q_binomial(la_c[k - 1], mu_c[k - 1], q=q) return prod([fac1, fac2, fac3]) raise ValueError("invalid algorithm choice")
def _element_constructor_(self, element): """ Coerce ``element`` into ``self`` INPUT: - ``element`` -- any object This default implementation returns ``element`` if ``self`` is a facade for ``parent(element)`. Otherwise it attempts in turn to coerce ``element`` into each parent ``self`` is a facade for. This implementation is only valid for a facade parent which models the full union of the parents it is a facade for. Other facade parents should redefine :meth:`element_constructor` appropriately. EXAMPLES:: sage: S = Sets().Facade().example("union"); S An example of a facade set: the integers completed by +-infinity sage: S(1) 1 sage: S(1/2) Traceback (most recent call last): ... ValueError: Can't coerce `1/2` in any parent `An example of a facade set: the integers completed by +-infinity` is a facade for sage: S(2/1) 2 sage: S(2/1).parent() Integer Ring sage: S(int(1)) 1 sage: S(int(1)).parent() Integer Ring Facade parents that model strict subsets should redefine :meth:`element_constructor`:: sage: S = Sets().Facade().example(); S An example of facade set: the monoid of positive integers sage: S(-1) Traceback (most recent call last): ... ValueError: %s should be positive """ if self.is_parent_of(element): return element else: parents = self.facade_for() if parents is True: raise NotImplementedError for parent in self.facade_for(): try: return parent(element) except Exception: pass raise ValueError( "Can't coerce `%s` in any parent `%s` is a facade for" % (element, self))
def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): r""" Construct a lazy series from ``x``. INPUT: - ``x`` -- data used to the define a series - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - ``degree`` -- (optional) the degree when the series is ``constant`` - ``constant`` -- (optional) the eventual constant of the series - ``coefficients`` -- (optional) a callable that defines the coefficients of the series; must be ``None`` if ``x`` is provided; see note below If ``valuation`` is specified and ``x`` is convertible into an element of the underlying ring corresponding to series with finite support or ``x`` is a lazy series of the same parent, then the data is shifted so that the result has the specified valuation. .. WARNING:: If ``valuation`` is specified and ``x`` is a lazy series, then the valuation will be computed. If the series ``x`` is not known to be zero, then this will run forever. .. NOTE:: When working over a base ring that takes callables as valid input, then passing a function as ``x`` might be converted to the base ring. If instead the input is to be treated as the function giving the coefficients of the lazy series being constructed, then use the ``coefficients`` argument in this case and do not provide ``x``. .. WARNING:: Polynomials, but also :class:`LazyLaurentSeries` and :class:`LazyDirichletSeries` are callable. Therefore, an argument ``x`` which is not convertible into an element of the underlying ring corresponding to series with finite support is interpreted as a function providing the coefficients when evaluated at integers. Examples are provided below. EXAMPLES:: sage: L = LazyLaurentSeriesRing(GF(2), 'z') sage: L(2) 0 sage: L(3) 1 sage: L.<z> = LazyLaurentSeriesRing(ZZ) sage: L(lambda i: i, valuation=5, constant=1, degree=10) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: L(lambda i: i, valuation=5, constant=(1, 10)) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: X = L(constant=5, degree=2); X 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) sage: X.valuation() 2 sage: def g(i): ....: if i < 0: ....: return 1 ....: else: ....: return 1 + sum(k for k in range(i+1)) sage: e = L(g, valuation=-5); e z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) sage: f = e^-1; f z^5 - z^6 - z^11 + O(z^12) sage: f.coefficient(10) 0 sage: f[20] 9 sage: f[30] -219 sage: L(valuation=2, constant=1) z^2 + z^3 + z^4 + O(z^5) sage: L(constant=1) Traceback (most recent call last): ... ValueError: you must specify the degree for the polynomial 0 Alternatively, ``x`` can be a list of elements of the base ring. Then these elements are read as coefficients of the terms of degrees starting from the ``valuation``. In this case, ``constant`` may be just an element of the base ring instead of a tuple or can be simply omitted if it is zero:: sage: f = L([1,2,3,4], valuation=-5) sage: f z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 sage: g = L([1,3,5,7,9], valuation=5, constant=-1) sage: g z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) Finally, ``x`` can be a Laurent polynomial:: sage: P.<x> = LaurentPolynomialRing(QQ) sage: p = x^-2 + 3*x^3 sage: L.<x> = LazyLaurentSeriesRing(ZZ) sage: L(p) x^-2 + 3*x^3 sage: L(p, valuation=0) 1 + 3*x^5 sage: L(p, valuation=1) x + 3*x^6 We construct a lazy Laurent series over another lazy Laurent series:: sage: R.<s> = LazyLaurentSeriesRing(QQ) sage: L.<z> = LazyLaurentSeriesRing(R) sage: e = L(lambda n: 1/factorial(n), 0); e 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) sage: L(lambda n: 1/(1 + s^n), 0) 1/2 + (1 - s + s^2 - s^3 + s^4 - s^5 + s^6 + O(s^7))*z + (1 - s^2 + s^4 - s^6 + O(s^7))*z^2 + (1 - s^3 + s^6 + O(s^7))*z^3 + (1 - s^4 + O(s^7))*z^4 + (1 - s^5 + O(s^7))*z^5 + (1 - s^6 + O(s^7))*z^6 + O(z^7) We note that ``e`` builds correctly because ``R`` additionally requires the valuation to be specified. In the next example the argument is interpreted as a constant polynomial, which happens to be a Dirichlet series:: sage: D = LazyDirichletSeriesRing(QQ, "s") sage: L.<z> = LazyLaurentSeriesRing(D) sage: L(lambda n: 1/factorial(n), valuation=0) (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) We can also specify that the given function should be interpreted as the coefficients of the Laurent series:: sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) When the argument ``x`` is callable and not convertible into an element of the underlying ring of series of finite support, it is evaluated at integers to compute the coefficients:: sage: R.<q> = QQ[] sage: D = LazyDirichletSeriesRing(ZZ, 't') sage: D(1+2*q) 3 + 5/2^t + 7/3^t + 9/4^t + 11/5^t + 13/6^t + 15/7^t + O(1/(8^t)) In this example, the Dirichlet series ``m`` is considered as an element in the base ring:: sage: m = D(moebius) sage: s = L(m, valuation=0) sage: s[0] 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) sage: s[1] 0 TESTS: Checking the valuation is consistent:: sage: L.<z> = LazyLaurentSeriesRing(ZZ) sage: L([0,0,2,3], valuation=-4) 2*z^-4 + 3*z^-3 sage: L(range(5), valuation=-4) z^-4 + 2*z^-3 + 3*z^-2 + 4*z^-1 sage: P.<x> = ZZ[] sage: L(x^2 + x^5, valuation=-4) z^-4 + z^-1 sage: L(1, valuation=-4) z^-4 sage: L(L(1), valuation=-4) z^-4 sage: L(1/(1-z), valuation=-4) z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) sage: L(z^-3/(1-z), valuation=-4) z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) sage: L(z^3/(1-z), valuation=-4) z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) sage: L(z^3/(1-z), valuation=0) 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: L(lambda n: 1/(n+1), degree=3) Traceback (most recent call last): ... ValueError: the valuation must be specified sage: L(5, valuation=3.1) Traceback (most recent call last): ... ValueError: the valuation must be an integer sage: L(5, valuation=6/2) 5*z^3 Checking that series are not interpreted as coefficients when they can be interpreted as series:: sage: P.<s> = ZZ[] sage: L.<z> = LazyLaurentSeriesRing(ZZ) sage: M.<w> = LazyLaurentSeriesRing(QQ) sage: L(M(s^2 + s^5), valuation=-4) z^-4 + z^-1 sage: D = LazyDirichletSeriesRing(ZZ, "s") sage: E = LazyDirichletSeriesRing(QQ, "t") sage: D(E([1,2,3])) 1 + 2/2^s + 3/3^s This gives zero:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: L(lambda n: 0, degree=3, valuation=0) 0 sage: L(L.zero(), degree=3) 0 sage: L(L.zero(), degree=3, valuation=2) 0 sage: L(L.zero(), degree=3, constant=0) 0 sage: L(L.zero(), degree=3, valuation=2, constant=0) 0 This does not:: sage: L(lambda n: 0, degree=3, constant=1, valuation=0) z^3 + z^4 + z^5 + O(z^6) sage: L(L.zero(), degree=-3, constant=1) z^-3 + z^-2 + z^-1 + O(1) sage: L(L.zero(), valuation=2, constant=1) z^2 + z^3 + z^4 + O(z^5) This raises an error:: sage: L(lambda n: 0, valuation=3, constant=1) Traceback (most recent call last): ... ValueError: constant may only be specified if the degree is specified We support the old input format for ``constant``:: sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) sage: g = L(lambda i: i, valuation=-3, constant=(-1,3)) sage: f == g True sage: g = L(lambda i: i, -3, (-1,3)) sage: f == g True .. TODO:: Add a method to change the sparse/dense implementation. """ if valuation is not None and valuation not in ZZ: raise ValueError("the valuation must be an integer") if x is None and coefficients is None: if valuation is None: raise ValueError("the valuation must be specified") return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) if coefficients is not None and (x is not None and (not isinstance(x, int) or x)): raise ValueError("coefficients must be None if x is provided") BR = self.base_ring() if isinstance(constant, (tuple, list)): constant, degree = constant if isinstance(degree, (tuple, list)): constant, degree = degree if constant is not None: constant = BR(constant) if coefficients is None: # Try to build stuff using the internal polynomial ring constructor R = self._internal_poly_ring try: x = R(x) except (TypeError, ValueError): pass # If x has been converted to the internal polynomial ring if parent(x) is R: if not x and not constant: return self.zero() if x and valuation is not None: x = x.shift(valuation - x.valuation()) if degree is None and not x: if valuation is None: raise ValueError("you must specify the degree for the polynomial 0") degree = valuation if x == R.zero(): coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) return self.element_class(self, coeff_stream) initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] coeff_stream = Stream_exact(initial_coefficients, self._sparse, order=x.valuation(), constant=constant, degree=degree) return self.element_class(self, coeff_stream) # Handle when it is a lazy series if isinstance(x, self.Element): if x._coeff_stream._is_sparse is not self._sparse: # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") # If x is known to be 0 if isinstance(x._coeff_stream, Stream_zero): if not constant: if self is parent(x): return x return self.element_class(self, x._coeff_stream) if degree is None: if valuation is None: raise ValueError("you must specify the degree for the polynomial 0") degree = valuation coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) return self.element_class(self, coeff_stream) # Make the result exact if degree is not None: # truncate the series and then possibly make constant x_val = x._coeff_stream.order() if not valuation: valuation = x_val initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] if not any(initial_coefficients): if not constant: return self.zero() # We learned some stuff about x; pass it along x._coeff_stream._approximate_order += len(initial_coefficients) initial_coefficients = [] coeff_stream = Stream_exact(initial_coefficients, self._sparse, order=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) # We are just possibly shifting the result ret = self.element_class(self, x._coeff_stream) if valuation is None: return ret return ret.shift(valuation - x._coeff_stream.order()) else: x = coefficients if callable(x): if valuation is None: raise ValueError("the valuation must be specified") if degree is None: if constant is not None: raise ValueError("constant may only be specified if the degree is specified") coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) return self.element_class(self, coeff_stream) # degree is not None if constant is None: constant = BR.zero() p = [BR(x(i)) for i in range(valuation, degree)] if not any(p) and not constant: return self.zero() coeff_stream = Stream_exact(p, self._sparse, order=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into {self}")
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 _check_parents(a, b): # comparison between different parent may be okay if the elements are # instances of the same class (e.g., balls with different precisions) if parent(a) is not parent(b) and type(a) is not type(b): raise TypeError("unsafe comparison", parent(a), parent(b))
def _element_constructor_(self, x, mon=None): """ EXAMPLES:: sage: L = LaurentPolynomialRing(QQ,2,'x') sage: L(1/2) 1/2 sage: M = LaurentPolynomialRing(QQ, 'x, y') sage: var('x, y') (x, y) sage: M(x/y + 3/x) x*y^-1 + 3*x^-1 :: sage: M(exp(x)) Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) sage: M = LaurentPolynomialRing(QQ, 'c, d') sage: Mc, Md = M.gens() sage: N = LaurentPolynomialRing(M, 'a, b') sage: Na, Nb = N.gens() sage: M(c/d) c*d^-1 sage: N(a*b/c/d) (c^-1*d^-1)*a*b sage: N(c/d) c*d^-1 sage: L(Mc) c sage: L(Nb) b sage: M(L(0)) 0 sage: N(L(0)) 0 sage: L(M(0)) 0 sage: L(N(0)) 0 sage: U = LaurentPolynomialRing(QQ, 'a') sage: Ua = U.gen() sage: V = LaurentPolynomialRing(QQ, 'c') sage: Vc = V.gen() sage: L(Ua) a sage: L(Vc) c sage: N(Ua) a sage: M(Vc) c sage: P = LaurentPolynomialRing(QQ, 'a, b') sage: Q = LaurentPolynomialRing(P, 'c, d') sage: Q(P.0) a :: sage: A.<a> = LaurentPolynomialRing(QQ) sage: B.<b> = LaurentPolynomialRing(A) sage: C = LaurentPolynomialRing(QQ, 'a, b') sage: C(B({1: a})) a*b sage: D.<d, e> = LaurentPolynomialRing(B) sage: F.<f, g> = LaurentPolynomialRing(D) sage: D(F(d*e)) d*e :: sage: from sage.rings.polynomial.polydict import ETuple sage: R.<x,y,z> = LaurentPolynomialRing(QQ) sage: mon = ETuple({}, int(3)) sage: P = R.polynomial_ring() sage: R(sum(P.gens()), mon) x + y + z sage: R(sum(P.gens()), (-1,-1,-1)) y^-1*z^-1 + x^-1*z^-1 + x^-1*y^-1 """ from sage.symbolic.expression import Expression element_class = LaurentPolynomial_mpair if mon is not None: return element_class(self, x, mon) P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple return element_class(self, x, mon=ETuple({}, int(self.ngens()))) elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) elif isinstance( x, (LaurentPolynomial_univariate, LaurentPolynomial_mpair)): if self.variable_names() == P.variable_names(): # No special processing needed here; # handled by LaurentPolynomial_mpair.__init__ pass elif set(self.variable_names()) & set(P.variable_names()): if isinstance(x, LaurentPolynomial_univariate): d = {(k, ): v for k, v in iteritems(x.dict())} else: d = x.dict() x = _split_laurent_polynomial_dict_(self, P, d) elif self.base_ring().has_coerce_map_from(P): from sage.rings.polynomial.polydict import ETuple mz = ETuple({}, int(self.ngens())) return element_class(self, {mz: self.base_ring()(x)}, mz) elif x.is_constant() and self.has_coerce_map_from(P.base_ring()): return self(x.constant_coefficient()) elif len(self.variable_names()) == len(P.variable_names()): x = x.dict() return element_class(self, x)
def safe_eq(a, b): if parent(a) is not parent(b): logger.debug("comparing elements of %s and %s", parent(a), parent(b)) return False else: return a == b