def __init__(self, N, P, p, e): self._N = N self._F = P.number_field() self._p = p from sage.rings.all import Integers f = e // 2 + 1 assert f * 2 - 1 == e R0 = Integers(p**f) R1 = Integers(p**(f - 1)) self._ring = RamifiedProductRing(R0, R1) self._im_gen = self._ring.gen() self._sqrt5 = (self._F.gen() * 2 - 1)**2
def _delta_poly_modulo(N, prec=10): """ Return the q-expansion of `\Delta` modulo `N`. Used internally by the :func:`~delta_qexp` function. See the docstring of :func:`~delta_qexp` for more information. INPUT: - `N` -- positive integer modulo which we want to compute `\Delta` - ``prec`` -- integer; the absolute precision of the output OUTPUT: the polynomial of degree ``prec``-1 which is the truncation of `\Delta` modulo `N`, as an element of the polynomial ring in `q` over the integers modulo `N`. EXAMPLES:: sage: from sage.modular.modform.vm_basis import _delta_poly_modulo sage: _delta_poly_modulo(5, 7) 2*q^6 + 3*q^4 + 2*q^3 + q^2 + q sage: _delta_poly_modulo(10, 12) 2*q^11 + 7*q^9 + 6*q^7 + 2*q^6 + 8*q^4 + 2*q^3 + 6*q^2 + q """ if prec <= 0: raise ValueError("prec must be positive") v = [0] * prec # Let F = \sum_{n >= 0} (-1)^n (2n+1) q^(floor(n(n+1)/2)). # Then delta is F^8. stop = int((-1 + math.sqrt(8 * prec)) / 2.0) for n in xrange(stop + 1): v[n * (n + 1) // 2] = ((N - 1) * (2 * n + 1) if (n & 1) else (2 * n + 1)) from sage.rings.all import Integers P = PolynomialRing(Integers(N), 'q') f = P(v) t = verbose('made series') # fast way of computing f*f truncated at prec f = f._mul_trunc_(f, prec) t = verbose('squared (1 of 3)', t) f = f._mul_trunc_(f, prec) t = verbose('squared (2 of 3)', t) f = f._mul_trunc_(f, prec - 1) t = verbose('squared (3 of 3)', t) f = f.shift(1) t = verbose('shifted', t) return f
def __init__(self, N, P, p, e): self._N = N self._F = P.number_field() self._p = p from sage.rings.all import Integers assert e % 2 == 0 R = Integers(p**(e // 2)) modulus = self._F.defining_polynomial().change_ring(R) S = R['x'] self._ring = S.quotient_by_principal_ideal(modulus) self._im_gen = self._ring.gen()
def solve_mod(eqns, modulus, solution_dict=False): r""" Return all solutions to an equation or list of equations modulo the given integer modulus. Each equation must involve only polynomials in 1 or many variables. By default the solutions are returned as `n`-tuples, where `n` is the number of variables appearing anywhere in the given equations. The variables are in alphabetical order. INPUT: - ``eqns`` - equation or list of equations - ``modulus`` - an integer - ``solution_dict`` - bool (default: False); if True or non-zero, return a list of dictionaries containing the solutions. If there are no solutions, return an empty list (rather than a list containing an empty dictionary). Likewise, if there's only a single solution, return a list containing one dictionary with that solution. EXAMPLES:: sage: var('x,y') (x, y) sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14) [(4, 2), (4, 6), (4, 9), (4, 13)] sage: solve_mod([x^2 == 1, 4*x == 11], 15) [(14,)] Fermat's equation modulo 3 with exponent 5:: sage: var('x,y,z') (x, y, z) sage: solve_mod([x^5 + y^5 == z^5], 3) [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)] We can solve with respect to a bigger modulus if it consists only of small prime factors:: sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict = True) sage: d[x] 12915279 sage: d[y] 8610183 For cases where there are relatively few solutions and the prime factors are small, this can be efficient even if the modulus itself is large:: sage: sorted(solve_mod([x^2 == 41], 10^20)) [(4538602480526452429,), (11445932736758703821,), (38554067263241296179,), (45461397519473547571,), (54538602480526452429,), (61445932736758703821,), (88554067263241296179,), (95461397519473547571,)] We solve a simple equation modulo 2:: sage: x,y = var('x,y') sage: solve_mod([x == y], 2) [(0, 0), (1, 1)] .. warning:: The current implementation splits the modulus into prime powers, then naively enumerates all possible solutions (starting modulo primes and then working up through prime powers), and finally combines the solution using the Chinese Remainder Theorem. The interface is good, but the algorithm is very inefficient if the modulus has some larger prime factors! Sage *does* have the ability to do something much faster in certain cases at least by using Groebner basis, linear algebra techniques, etc. But for a lot of toy problems this function as is might be useful. At least it establishes an interface. TESTS: Make sure that we short-circuit in at least some cases:: sage: solve_mod([2*x==1], 2*next_prime(10^50)) [] Try multi-equation cases:: sage: x, y, z = var("x y z") sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12) [(0, 0), (4, 4), (0, 3), (4, 7)] sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z] sage: solve_mod(eqs, 11) [(8, 5, 6)] Confirm that modulus 1 now behaves as it should:: sage: x, y = var("x y") sage: solve_mod([x==1], 1) [(0,)] sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) [(0, 0)] """ from sage.rings.all import Integer, Integers, crt_basis from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator from sage.modules.all import vector from sage.matrix.all import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] eqns = [eq if is_Expression(eq) else (eq.lhs() - eq.rhs()) for eq in eqns] modulus = Integer(modulus) if modulus < 1: raise ValueError("the modulus must be a positive integer") vars = list(set(sum([list(e.variables()) for e in eqns], []))) vars.sort(key=repr) if modulus == 1: # degenerate case ans = [tuple(Integers(1)(0) for v in vars)] return ans factors = modulus.factor() crt_basis = vector(Integers(modulus), crt_basis([p**i for p, i in factors])) solutions = [] has_solution = True for p, i in factors: solution = _solve_mod_prime_power(eqns, p, i, vars) if len(solution) > 0: solutions.append(solution) else: has_solution = False break ans = [] if has_solution: for solution in cartesian_product_iterator(solutions): solution_mat = matrix(Integers(modulus), solution) ans.append( tuple( c.dot_product(crt_basis) for c in solution_mat.columns())) # if solution_dict == True: # Relaxed form suggested by Mike Hansen (#8553): if solution_dict: sol_dict = [dict(zip(vars, solution)) for solution in ans] return sol_dict else: return ans
def _solve_mod_prime_power(eqns, p, m, vars): r""" Internal help function for solve_mod, does little checking since it expects solve_mod to do that Return all solutions to an equation or list of equations modulo p^m. Each equation must involve only polynomials in 1 or many variables. The solutions are returned as `n`-tuples, where `n` is the number of variables in vars. INPUT: - ``eqns`` - equation or list of equations - ``p`` - a prime - ``i`` - an integer > 0 - ``vars`` - a list of variables to solve for EXAMPLES:: sage: var('x,y') (x, y) sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14) [(4, 2), (4, 6), (4, 9), (4, 13)] sage: solve_mod([x^2 == 1, 4*x == 11], 15) [(14,)] Fermat's equation modulo 3 with exponent 5:: sage: var('x,y,z') (x, y, z) sage: solve_mod([x^5 + y^5 == z^5], 3) [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)] We solve a simple equation modulo 2:: sage: x,y = var('x,y') sage: solve_mod([x == y], 2) [(0, 0), (1, 1)] .. warning:: Currently this constructs possible solutions by building up from the smallest prime factor of the modulus. The interface is good, but the algorithm is horrible if the modulus isn't the product of many small primes! Sage *does* have the ability to do something much faster in certain cases at least by using the Chinese Remainder Theorem, Groebner basis, linear algebra techniques, etc. But for a lot of toy problems this function as is might be useful. At the very least, it establishes an interface. TESTS: Confirm we can reproduce the first few terms of :oeis:`A187719`:: sage: from sage.symbolic.relation import _solve_mod_prime_power sage: [sorted(_solve_mod_prime_power([x^2==41], 10, i, [x]))[0][0] for i in [1..13]] [1, 21, 71, 1179, 2429, 47571, 1296179, 8703821, 26452429, 526452429, 13241296179, 19473547571, 2263241296179] """ from sage.rings.all import Integers, PolynomialRing from sage.modules.all import vector from sage.misc.all import cartesian_product_iterator mrunning = 1 ans = [] for mi in range(m): mrunning *= p R = Integers(mrunning) S = PolynomialRing(R, len(vars), vars) eqns_mod = [S(eq) for eq in eqns] if mi == 0: possibles = cartesian_product_iterator( [range(len(R)) for _ in range(len(vars))]) else: shifts = cartesian_product_iterator( [range(p) for _ in range(len(vars))]) pairs = cartesian_product_iterator([shifts, ans]) possibles = (tuple(vector(t) + vector(shift) * (mrunning // p)) for shift, t in pairs) ans = list(t for t in possibles if all(e(*t) == 0 for e in eqns_mod)) if not ans: return ans return ans
def __startup__(): import sage.algebras.steenrod.steenrod_algebra import types def resolution(self, memory=None, filename=None): """ The minimal resolution of the ground field as a module over 'self'. TESTS:: sage: from yacop.resolutions.minres import MinimalResolution sage: MinimalResolution(SteenrodAlgebra(7)) is SteenrodAlgebra(7).resolution() True """ from yacop.resolutions.minres import MinimalResolution return MinimalResolution(self, memory=memory, filename=filename) setattr( sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic, "resolution", resolution, ) def Ext(algebra, M, N=None, filename=None): """ ``Ext(M,N)`` over ``algebra``. """ from yacop.resolutions.smashres import SmashResolution assert N is None return SmashResolution(M, algebra.resolution(), filename=filename).Homology() setattr(sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic, "Ext", Ext) # there are known issues in Sage with pickling of morphisms # and we don't want to document the same failures in our test # suite. from sage.combinat.free_module import CombinatorialFreeModule def p_test_pickling(self, tester=None, **options): if not hasattr(self, "_can_test_pickling") or self._can_test_pickling(): tester = self._tester(**options) from sage.misc.all import loads, dumps tester.assertEqual(loads(dumps(self)), self) else: tester.info(" (skipped, not picklable) ", newline=False) def e_test_pickling(self, tester=None, **options): if not hasattr(self, "_can_test_pickling") or self._can_test_pickling(): tester = self._tester(**options) from sage.misc.all import loads, dumps tester.assertEqual(loads(dumps(self)), self) else: tester.info(" (skipped, not picklable) ", newline=False) CombinatorialFreeModule._test_pickling = p_test_pickling # CombinatorialFreeModule.Element._test_pickling = e_test_pickling (no longer possible, by ticket/22632) # workaround for Sage Ticket #13814 from sage.sets.family import LazyFamily from sage.rings.all import Integers if LazyFamily(Integers(), lambda i: 2 * i) == LazyFamily(Integers(), lambda i: 2 * i): def noteq(self, other): if self is other: return True return False LazyFamily.__eq__ = noteq try: 16 in LazyFamily(Integers(), lambda i: 2 * i) except: # we need to overwrite _contains_ in our module base to fix # the test suite of SteenrodModuleBase.basis() def __contains__(self, x): try: return self._contains_(x) except AttributeError: return super(LazyFamily, self).__contains__(x) LazyFamily.__contains__ = __contains__ # workaround for #13811 from sage.sets.family import AbstractFamily def __copy__(self): return self AbstractFamily.__copy__ = __copy__ # LazyFamilies cannot be pickled... turn off the resulting noise def _test_pickling(self, tester=None, **options): pass LazyFamily._test_pickling = _test_pickling # workaround for Sage ticket #13833 from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra B = SteenrodAlgebra(2, profile=(3, 2, 1)) A = SteenrodAlgebra(2) id = A.module_morphism(codomain=A, on_basis=lambda x: A.monomial(x)) try: x = id(B.an_element()) except AssertionError: from sage.categories.modules_with_basis import ModuleMorphismByLinearity origcall = ModuleMorphismByLinearity.__call__ def call(self, *args): before = args[0:self._position] after = args[self._position + 1:len(args)] x = args[self._position] nargs = before + (self.domain()(x), ) + after return origcall(self, *nargs) ModuleMorphismByLinearity.__call__ = call # workaround for Sage ticket #18449 from sage.sets.set_from_iterator import EnumeratedSetFromIterator from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.enumerated_sets import EnumeratedSets from sage.rings.integer_ring import ZZ C = CombinatorialFreeModule(ZZ, EnumeratedSetFromIterator(Integers)) if False and sage.categories.tensor.tensor( (C, )).basis() in FiniteEnumeratedSets(): def __init_18449__(self, set, function, name=None): """ patched __init__ function from ticket #18449 """ from sage.combinat.combinat import CombinatorialClass # workaround #12482 from sage.structure.parent import Parent category = EnumeratedSets() if set in FiniteEnumeratedSets(): category = FiniteEnumeratedSets() elif set in InfiniteEnumeratedSets(): category = InfiniteEnumeratedSets() elif isinstance(set, (list, tuple)): category = FiniteEnumeratedSets() elif isinstance(set, CombinatorialClass): try: if set.is_finite(): category = FiniteEnumeratedSets() except NotImplementedError: pass Parent.__init__(self, category=category) from copy import copy self.set = copy(set) self.function = function self.function_name = name LazyFamily.__init__ = __init_18449__ # use a lower max_runs value for the TestSuite from sage.misc.sage_unittest import InstanceTester InstanceTester.__init_original__ = InstanceTester.__init__ def newinit(self, *args, **kwds): self.__init_original__(*args, **kwds) self._max_runs = 40 InstanceTester.__init__ = newinit # fix a problem for __contain__ in Categories_over_base_ring # when more than one base is involved: from sage.categories.category import Category from sage.categories.category_types import Category_over_base_ring from sage.categories.modules import Modules from sage.categories.algebras import Algebras from sage.categories.modules_with_basis import ModulesWithBasis from sage.rings.finite_rings.finite_field_constructor import GF C = CombinatorialFreeModule(GF(5), ZZ, category=(ModulesWithBasis(GF(5)), Algebras(ZZ))) if C not in Modules(ZZ): _sagecode = Category_over_base_ring.__contains__ Category_over_base_ring.__contains_sage__ = _sagecode def __contains_yacop__(self, Z): ans = self.__contains_sage__(Z) if not ans: try: ans = self in Z.categories() except: pass return ans Category_over_base_ring.__contains__ = __contains_yacop__ # Sage insists that Subquotients of CartesianProducts are again CartesianProducts # (and similarly for TensorProducts). We forcefully disagree: from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory @classmethod def default_super_categories_yacop(cls, category, *args): """ TESTS:: sage: import yacop sage: # an earlier version of this hack broke the MRO for quasi symmetric functions: sage: QuasiSymmetricFunctions(GF(3)) Quasisymmetric functions over the Finite Field of size 3 """ sageresult = Category.join([ category, super(RegressiveCovariantConstructionCategory, cls).default_super_categories(category, *args) ]) ans = sageresult if isinstance(ans, sage.categories.category.JoinCategory): j = [ cat for cat in sageresult.super_categories() if not hasattr(cat, "yacop_no_default_inheritance") ] ans = Category.join(j) return ans RegressiveCovariantConstructionCategory.default_super_categories = default_super_categories_yacop