def construct_spx(spx, max=Integer(1280)): for r in range(3, max / 4 + 1): spx[r] = {} s = Integer(1) m = Integer(4) * r while m <= max: c = sum([[(tuple(v), n) for n in Integers(r)] for v in Integers(2)**Integer(s)], []) c = [(v, n, Integer(1)) for v, n in c] + [(v, n, Integer(-1)) for v, n in c] spx[r][s] = Graph([c, spx_adj]) s += 1 m *= 2 print "Finished r = %d, constructed %d graphs" % (r, len(spx[r]))
def __call__(self, n, modulus=0): """ Give the nth term of a binary recurrence sequence, possibly mod some modulus. INPUT: - ``n`` -- an integer (the index of the term in the binary recurrence sequence) - ``modulus`` -- a natural number (optional -- default value is 0) OUTPUT: - An integer (the nth term of the binary recurrence sequence modulo ``modulus``) EXAMPLES:: sage: R = BinaryRecurrenceSequence(3,3,2,1) sage: R(2) 9 sage: R(101) 16158686318788579168659644539538474790082623100896663971001 sage: R(101,12) 9 sage: R(101)%12 9 """ R = Integers(modulus) F = matrix( R, [[0, 1], [self.c, self.b]] ) # F*[u_{n}, u_{n+1}]^T = [u_{n+1}, u_{n+2}]^T (T indicates transpose). v = matrix(R, [[self.u0], [self.u1]]) return list(F**n * v)[0][0]
def __init__(self, n): """ Args: n (int): The number of elements in the finite ring. """ f = Integers(n) operations = {'+': lambda x, y: x + y, '*': lambda x, y: x * y} AlgebraicStructure.__init__(self, set(f), operations)
def construct_spx(r, s, multiedges=None, **kargs): r""" Construct a SPX(2, r, s) graph. Return a tuple containing the data that can be used to construct the requested SPX graph, and a boolean indicating whether the constructed graph should be considered a multigraph. INPUT: - ``r`` - the ``r`` parameter indicating the range of the counter. - ``s`` - the ``s`` parameter indicating the length of the string. - ``multiedges`` - whether the constructed graph should be considered a multigraph. If ``None`` (default), the second element of the output will be set to ``True`` when ``r == 1``. If ``False`` and ``r == 1``, a ``ValueError`` is raised. Otherwise, the second element of the output will be ``multiedges``. - any other named parameters are silently ignored. """ c = [tuple(x) for x in cartesian_product([[tuple(y) for y in Integers(2)**Integer(s)], Integers(r), [Integer(1), Integer(-1)]])] if r == 1: if multiedges is False: raise ValueError("A SPX graph with r = 1 has multiple edges") data = sum([[((v, n, t), (v, n, -t)), ((v, n, t), (v[1:] + (Integer(0),), n, -t)), ((v, n, t), (v[1:] + (Integer(1),), n, -t))] for v, n, t in c if t == 1], []) multiedges = True else: data = [c, spx_adj] return (data, multiedges)
def n_cylinders_edges(self, n): r""" EXAMPLES:: sage: from slabbe.markov_transformation import markov_transformations sage: T = markov_transformations.Selmer() sage: E = T.n_cylinders_edges(1) sage: len(E) 39 """ from sage.rings.finite_rings.integer_mod_ring import Integers edges = set() for w, cyl in self.n_cylinders_iterator(n): cols = cyl.columns() indices = Integers(len(cols)) edges.update(frozenset((cols[i], cols[i + 1])) for i in indices) return edges
def __init__(self, n): """ Args: n (int): The size of the underlying set. """ self.n = n coeffs = product(range(n), repeat=n) polys = frozenset(PolynomialRing(Integers(n), 'x')(r) for r in coeffs) mats = set() element_names = {} for poly in polys: m = matrix(n, sparse=True) for i in range(n): m[i, poly(i) % n] = 1 m.set_immutable() mats.add(m) element_names[m] = poly operation = {'*': lambda x, y: x * y} AlgebraicStructure.__init__(self, mats, operation, element_names)
def n_cylinders_edges(self, n): r""" Return the set of edges of the n-cylinders. EXAMPLES:: sage: from slabbe.matrix_cocycle import cocycles sage: ARP = cocycles.ARP() sage: ARP.n_cylinders_edges(1) {frozenset({(1, 1, 0), (1, 1, 1)}), frozenset({(0, 1, 0), (1, 1, 0)}), frozenset({(1, 1, 1), (2, 1, 1)}), frozenset({(0, 0, 1), (1, 0, 1)}), frozenset({(0, 1, 0), (0, 1, 1)}), frozenset({(0, 1, 1), (1, 0, 1)}), frozenset({(1, 0, 0), (1, 1, 0)}), frozenset({(1, 1, 0), (2, 1, 1)}), frozenset({(1, 0, 1), (1, 1, 2)}), frozenset({(1, 1, 0), (1, 2, 1)}), frozenset({(1, 0, 1), (2, 1, 1)}), frozenset({(0, 0, 1), (0, 1, 1)}), frozenset({(1, 0, 1), (1, 1, 1)}), frozenset({(0, 1, 1), (1, 2, 1)}), frozenset({(0, 1, 1), (1, 1, 2)}), frozenset({(1, 0, 0), (1, 0, 1)}), frozenset({(1, 1, 1), (1, 2, 1)}), frozenset({(1, 0, 1), (1, 1, 0)}), frozenset({(0, 1, 1), (1, 1, 1)}), frozenset({(0, 1, 1), (1, 1, 0)}), frozenset({(1, 1, 1), (1, 1, 2)})} """ from sage.rings.finite_rings.integer_mod_ring import Integers edges = set() for w,cyl in self.n_cylinders_iterator(n): cols = cyl.columns() indices = Integers(len(cols)) edges.update(frozenset((cols[i], cols[i+1])) for i in indices) return edges
def logarithmTable(a, p, base, trace=False): """ Compute the tables of logarithms with base a modulo a prime p for the given factor base, as needed by the Index calculus algorithm. Requires Sage to run. """ from sage.matrix.constructor import Matrix from sage.rings.finite_rings.integer_mod_ring import Integers v = [] s = set() r, l = 0, len(base) M = Matrix(nrows=0, ncols=l) fields = [ Integers(q) for q in totalFactorization(p - 1, trace=descend(trace)) ] while r < l: i = randint(1, p - 1) if i in s: continue s.add(i) x = pow(a, i, p) f = factorizeByBase(int(x), base, p) if not f: continue if trace: print("found factorization %d^%d = %s (mod %d)" % (a, i, ' * '.join("%d^%d" % (q, e) for q, e in zip(base, f) if e != 0), p)) MM = Matrix(list(M) + [f]) if all(Matrix(F, MM).rank() > r for F in fields): M = MM r += 1 v.append(i) elif trace: print("rank not increased, discarding") return [e for e, in M**-1 * Matrix(zip(v)) % (p - 1)]
def _is_p_power_mod(a, p, N): """ Determine if ``a`` is a ``p`` th power modulo ``N``. By the CRT, this is equivalent to the condition that ``a`` be a ``p`` th power mod all distinct prime powers dividing ``N``. For each of these, we use the strong statement of Hensel's lemma to lift ``p`` th powers mod `q` or `q^2` or `q^3` to ``p`` th powers mod `q^e`. INPUT: - ``a`` -- an integer - ``p`` -- a rational prime number - ``N`` -- a positive integer OUTPUT: - True if ``a`` is a ``p`` th power modulo ``N``; False otherwise. EXAMPLES:: sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,7,29) False sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,3,29) True """ #By the chinese remainder theorem, we can answer this question by examining whether #a is a pth power mod q^e, for all distinct prime powers q^e dividing N. for q, e in N.factor(): #If a = q^v*x, with v = a.valuation(q) #then if v>=e, a is congruent to 0 mod q^e and is thus a pth power trivially. if v >= e: continue #otherwise, it can only be a pth power if v is a multiple of p. if v % p != 0: return False #in this cse it is a pth power if x is a pth power mod q^(e-v), so let x = aa, #and (e-v) = ee: aa = a / q**v ee = e - v #The above steps are equivalent to the statement that we may assume a and qq are #relatively prime, if we replace a with aa and e with ee. Now we must determine when #aa is a pth power mod q^ee for (aa,q)=1. #If q != p, then by Hensel's lemma, we may lift a pth power mod q, to a pth power #mod q^2, etc. if q != p: #aa is necessarily a pth power mod q if p does not divide the order of the multiplicative #group mod q, ie if q is not 1 mod p. if q % p == 1: #otherwise aa if a pth power mod q iff aa^(q-1)/p == 1 if GF(q)(aa)**((q - 1) / p) != 1: return False #If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem. elif ee > 1: #We use the strong statement of Hensel's lemma, which implies that if p is odd #and aa is a pth power mod p^2, then aa is a pth power mod any higher power of p if p % 2 == 1: #ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then #aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1. if Integers(p**2)(aa)**(p - 1) != 1: return False #Otherwise, p=2. By the strong statement of Hensel's lemma, if aa is a pth power #mod p^3, then it is a pth power mod higher powers of p. So we need only check if it #is a pth power mod p^2 and p^3. elif ee == 2: #all odd squares a 1 mod 4 if aa % 4 != 1: return False #all odd squares are 1 mod 8 elif aa % 8 != 1: return False return True
def period(self, m): """ Return the period of the binary recurrence sequence modulo an integer ``m``. If `n_1` is congruent to `n_2` modulu ``period(m)``, then `u_{n_1}` is is congruent to `u_{n_2}` modulo ``m``. INPUT: - ``m`` -- an integer (modulo which the period of the recurrence relation is calculated). OUTPUT: - The integer (the period of the sequence modulo m) EXAMPLES: If `p = \\pm 1 \\mod 5`, then the period of the Fibonacci sequence mod `p` is `p-1` (c.f. Lemma 3.3 of [BMS06]). :: sage: R = BinaryRecurrenceSequence(1,1) sage: R.period(31) 30 sage: [R(i) % 4 for i in range(12)] [0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1] sage: R.period(4) 6 This function works for degenerate sequences as well. :: sage: S = BinaryRecurrenceSequence(2,0,1,2) sage: S.is_degenerate() True sage: S.is_geometric() True sage: [S(i) % 17 for i in range(16)] [1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9] sage: S.period(17) 8 Note: the answer is cached. """ #If we have already computed the period mod m, then we return the stored value. if m in self._period_dict: return self._period_dict[m] else: R = Integers(m) A = matrix(R, [[0, 1], [self.c, self.b]]) w = matrix(R, [[self.u0], [self.u1]]) Fac = list(m.factor()) Periods = {} #To compute the period mod m, we compute the least integer n such that A^n*w == w. This necessarily #divides the order of A as a matrix in GL_2(Z/mZ). #We compute the period modulo all distinct prime powers dividing m, and combine via the lcm. #To compute the period mod p^e, we first compute the order mod p. Then the period mod p^e #must divide p^{4e-4}*period(p), as the subgroup of matrices mod p^e, which reduce to #the identity mod p is of order (p^{e-1})^4. So we compute the period mod p^e by successively #multiplying the period mod p by powers of p. for i in Fac: p = i[0] e = i[1] #first compute the period mod p if p in self._period_dict: perp = self._period_dict[p] else: F = A.change_ring(GF(p)) v = w.change_ring(GF(p)) FF = F**(p - 1) p1fac = list((p - 1).factor()) #The order of any matrix in GL_2(F_p) either divides p(p-1) or (p-1)(p+1). #The order divides p-1 if it is diagonalizable. In any case, det(F^(p-1))=1, #so if tr(F^(p-1)) = 2, then it must be triangular of the form [[1,a],[0,1]]. #The order of the subgroup of matrices of this form is p, so the order must divide #p(p-1) -- in fact it must be a multiple of p. If this is not the case, then the #order divides (p-1)(p+1). As the period divides the order of the matrix in GL_2(F_p), #these conditions hold for the period as well. #check if the order divides (p-1) if FF * v == v: M = p - 1 Mfac = p1fac #check if the trace is 2, then the order is a multiple of p dividing p*(p-1) elif (FF).trace() == 2: M = p - 1 Mfac = p1fac F = F**p #replace F by F^p as now we only need to determine the factor dividing (p-1) #otherwise it will divide (p+1)(p-1) else: M = (p + 1) * (p - 1) p2fac = list( (p + 1).factor() ) #factor the (p+1) and (p-1) terms separately and then combine for speed Mfac_dic = {} for i in list(p1fac + p2fac): if i[0] not in Mfac_dic: Mfac_dic[i[0]] = i[1] else: Mfac_dic[i[0]] = Mfac_dic[i[0]] + i[1] Mfac = [(i, Mfac_dic[i]) for i in Mfac_dic] #Now use a fast order algorithm to compute the period. We know that the period divides #M = i_1*i_2*...*i_l where the i_j denote not necessarily distinct prime factors. As #F^M*v == v, for each i_j, if F^(M/i_j)*v == v, then the period divides (M/i_j). After #all factors have been iterated over, the result is the period mod p. Mfac = list(Mfac) C = [] #expand the list of prime factors so every factor is with multiplicity 1 for i in range(len(Mfac)): for j in range(Mfac[i][1]): C.append(Mfac[i][0]) Mfac = C n = M for i in Mfac: b = Integer(n / i) if F**b * v == v: n = b perp = n #Now compute the period mod p^e by stepping up by multiples of p F = A.change_ring(Integers(p**e)) v = w.change_ring(Integers(p**e)) FF = F**perp if FF * v == v: perpe = perp else: tries = 0 while True: tries += 1 FF = FF**p if FF * v == v: perpe = perp * p**tries break Periods[p] = perpe #take the lcm of the periods mod all distinct primes dividing m period = 1 for p in Periods: period = lcm(Periods[p], period) self._period_dict[m] = period #cache the period mod m return period
def residue(self, absprec=1, field=None, check_prec=True): r""" Reduces this element modulo `p^{\mathrm{absprec}}`. INPUT: - ``absprec`` -- a non-negative integer (default: ``1``) - ``field`` -- boolean (default ``None``). Whether to return an element of GF(p) or Zmod(p). - ``check_prec`` -- boolean (default ``True``). Whether to raise an error if this element has insufficient precision to determine the reduction. OUTPUT: This element reduced modulo `p^\mathrm{absprec}` as an element of `\ZZ/p^\mathrm{absprec}\ZZ` EXAMPLES:: sage: R = ZpLC(7,4) sage: a = R(8) sage: a.residue(1) 1 TESTS:: sage: R = ZpLC(7,4) sage: a = R(8) sage: a.residue(0) 0 sage: a.residue(-1) Traceback (most recent call last): ... ValueError: cannot reduce modulo a negative power of p. sage: a.residue(5) Traceback (most recent call last): ... PrecisionError: not enough precision known in order to compute residue. sage: a.residue(5, check_prec=False) 8 sage: a.residue(field=True).parent() Finite Field of size 7 """ if not isinstance(absprec, Integer): absprec = Integer(absprec) if check_prec and absprec > self.precision_absolute(): raise PrecisionError( "not enough precision known in order to compute residue.") elif absprec < 0: raise ValueError("cannot reduce modulo a negative power of p.") if self.valuation() < 0: raise ValueError( "element must have non-negative valuation in order to compute residue." ) if field is None: field = (absprec == 1) elif field and absprec != 1: raise ValueError("field keyword may only be set at precision 1") p = self._parent.prime() if field: from sage.rings.finite_rings.finite_field_constructor import GF ring = GF(p) else: from sage.rings.finite_rings.integer_mod_ring import Integers ring = Integers(p**absprec) return ring(self.value())
def suspenders(self): # from sage.rings import Integers return Integers()