def __init__(self, n, instance='key', m=None): """ Construct LWE instance parameterised by security parameter ``n`` where all other parameters are chosen as in [CGW2013]_. INPUT: - ``n`` - security parameter (integer >= 89) - ``instance`` - one of - "key" - the LWE-instance that hides the secret key is generated - "encrypt" - the LWE-instance that hides the message is generated (default: ``key``) - ``m`` - number of allowed samples or ``None`` in which case ``m`` is chosen as in [CGW2013]_. (default: ``None``) EXAMPLES:: sage: from sage.crypto.lwe import UniformNoiseLWE sage: UniformNoiseLWE(89) LWE(89, 154262477, UniformSampler(0, 351), 'noise', 131) sage: UniformNoiseLWE(89, instance='encrypt') LWE(131, 154262477, UniformSampler(0, 497), 'noise', 181) """ if n<89: raise TypeError("Parameter too small") n2 = n C = 4/sqrt(2*pi) kk = floor((n2-2*log(n2, 2)**2)/5) n1 = floor((3*n2-5*kk)/2) ke = floor((n1-2*log(n1, 2)**2)/5) l = floor((3*n1-5*ke)/2)-n2 sk = ceil((C*(n1+n2))**(3/2)) se = ceil((C*(n1+n2+l))**(3/2)) q = next_prime(max(ceil((4*sk)**((n1+n2)/n1)), ceil((4*se)**((n1+n2+l)/(n2+l))), ceil(4*(n1+n2)*se*sk+4*se+1))) if kk<=0: raise TypeError("Parameter too small") if instance == 'key': D = UniformSampler(0, sk-1) if m is None: m = n1 LWE.__init__(self, n=n2, q=q, D=D, secret_dist='noise', m=m) elif instance == 'encrypt': D = UniformSampler(0, se-1) if m is None: m = n2+l LWE.__init__(self, n=n1, q=q, D=D, secret_dist='noise', m=m) else: raise TypeError("Parameter instance=%s not understood."%(instance))
def holonomy_representation(self): r""" Return the holonomy representation in `SO(2)` as two lists. The first list correspond to cycles around vertices, while the second correspond to a cycle basis that generate homology. EXAMPLES:: sage: from surface_dynamics.all import * sage: e = '(0,1)(2,3)' sage: f = '(0,2,1,3)' sage: a = [1/2,1/2,1/2,1/2] sage: r = RibbonGraphWithAngles(edges=e,faces=f,angles=a) sage: r.holonomy_representation() ([0], [0, 0]) The standard cube:: sage: e = tuple((i,i+1) for i in xrange(0,24,2)) sage: f = '(0,20,7,10)(16,22,19,21)(2,9,5,23)(14,3,17,1)(12,8,15,11)(18,4,13,6)' sage: a = [1/2]*24 sage: r = RibbonGraphWithAngles(edges=e,faces=f,angles=a) sage: r.holonomy_representation() ([3/2, 3/2, 3/2, 3/2, 3/2, 3/2, 3/2, 3/2], []) Two copies of a triangle:: sage: e = '(0,1)(2,3)(4,5)' sage: f = '(0,2,4)(1,5,3)' sage: a = [1/2,1/6,1/3,1/3,1/6,1/2] sage: r = RibbonGraphWithAngles(edges=e,faces=f,angles=a) sage: r.holonomy_representation() ([1, 1/2, 1/2], []) sage: a = [1/3,7/15,1/5,1/5,7/15,1/3] sage: r = RibbonGraphWithAngles(edges=e,faces=f,angles=a) sage: r.holonomy_representation() ([2/3, 2/3, 2/3], []) """ from sage.functions.other import floor l1 = [] for c in xrange(self.num_vertices()): w = self.angle_at_vertex(c) l1.append(w - 2*floor(w/2)) l2 = [] for c in self.cycle_basis(): w = self.winding(c) l2.append(w - 2*floor(w/2)) return l1,l2
def calcPrecisionDimension(B_cF, S): """ When calculating the Fourier expansion `a[S]` of the reduction Elliptic modular form, this gives the maximum precision we can calculate from a Fourier expansion `a` of a Hermitian modular form, where the precision of `a` is given by `B_cF`. See the text for details. Note: This is like the C++ implementation `calcPrecisionDimension()` in `algo_cpp.cpp`. We don't actually need this function in Python, except for testing. INPUT: - `B_cF` -- an integer: the precision of the FE of the Hermitian modular forms. - `S` -- the reduction matrix for `a[S]`. OUTPUT: - an integer: the precision of the FE of the Elliptic modular forms. """ assert S[0,1] == S[1,0].conjugate() s,t,u = S[0,0], S[0,1], S[1,1] s, u = QQ(s), QQ(u) precDim = B_cF * (min(s, u) - 2 * abs(t)) precDim = RR(precDim) if precDim < 0: return 0 precDim = floor(precDim) return precDim
def mod_one(x): """ Return ``x`` mod 1. INPUT: - ``x`` -- a real number OUTPUT: ``x`` mod 1, a number in `[0,1)`. TESTS:: sage: from sage.dynamics.foliations.base import mod_one sage: mod_one(2.5) 0.500000000000000 sage: mod_one(-1.7) 0.300000000000000 sage: mod_one(7/6) 1/6 sage: mod_one(-1/6) 5/6 sage: a = QQbar(sqrt(2)); a 1.414213562373095? sage: mod_one(a) 0.4142135623730951? """ return x - floor(x)
def repr_matrix(coeffs): from sage.functions.other import floor ncols = 0 lengths = [ ] for row in coeffs: l = len(row) if ncols < l: lengths.extend([0] * (l-ncols)) ncols = l for j in range(l): elt = str(row[j]); l = len(elt) if lengths[j] < len(elt)+2: lengths[j] = len(elt)+2 s = "" for row in coeffs: s += "[" for j in range(len(row)): elt = str(row[j]); l = len(elt) nbspace = floor((lengths[j]-l)/2) s += " " * nbspace s += elt s += " " * (lengths[j]-l-nbspace) for j in range(len(row),ncols): s += " " * lengths[j] s += "]\n" return s[:-1]
def iter_positive_forms_with_content(self) : if self.__disc is infinity : raise ValueError, "infinity is not a true filter index" if self.__reduced : for a in xrange(1,isqrt(self.__disc // 3) + 1) : for b in xrange(a+1) : g = gcd(a, b) for c in xrange(a, (b**2 + (self.__disc - 1))//(4*a) + 1) : yield (a,b,c), gcd(g,c) else : maxtrace = floor(5*self.__disc / 15 + sqrt(self.__disc)/2) for a in xrange(1, maxtrace + 1) : for c in xrange(1, maxtrace - a + 1) : g = gcd(a,c) Bu = isqrt(4*a*c - 1) di = 4*a*c - self.__disc if di >= 0 : Bl = isqrt(di) + 1 else : Bl = 0 for b in xrange(-Bu, -Bl + 1) : yield (a,b,c), gcd(g,b) for b in xrange(Bl, Bu + 1) : yield (a,b,c), gcd(g,b) #! if self.__reduced raise StopIteration
def calc_prec(): if self.prec != None: return self.prec iv0 = IntuitiveAbel(self.bsym,self.N-1,iprec=self.iprec,x0=self.x0sym) self.iv0 = iv0 self.err = abs(iv0.sexp(0.5) - self.sexp(0.5)) print "err:", self.err.n(20) self.prec = floor(-log(self.err)/log(2.0))
def normalize_aws(self): """Arizona Winter School filtration (for families) -- reduces the j-th moment modulo p^(floor((N+1-j)*(p-2)/(p-1))""" p=self.p N=self.num_moments() assert self.valuation() >= 0, "moments not integral in normalization" v=vector([self.moment(j)%(p**(floor((N+1-j)*(p-2)/(p-1)))) for j in range(0,self.num_moments())]) return dist(self.p,self.weight,v)
def divmod(self, a, b): """ Returns q,r such that a = q*b + r. This is division with remainder. It holds that `self.euclidean_func(r) < `self.euclidean_func(b)`. """ # Note that this implementation is quite naive! # Later, we can do better with QuadraticForm(...). (TODO) # Also, read here: http://www.fen.bilkent.edu.tr/~franz/publ/survey.pdf if b == 0: raise ZeroDivisionError a1,a2 = self.as_tuple_b(a) b1,b2 = self.as_tuple_b(b) #B = matrix([ # [b1, -b2 * (self.D**2 - self.D)/4], # [b2, b1 + b2*self.D] #]) Bdet = b1*b1 + b1*b2*self.D + b2*b2*(self.D**2 - self.D)/4 Bdet = _simplify(Bdet) assert Bdet > 0 qq1 = (a1*b1 + a1*b2*self.D + a2*b2*(self.D**2 - self.D)/4) / Bdet qq2 = (-a1*b2 + a2*b1) / Bdet assert _simplify(self.from_tuple_b(qq1,qq2) * b - a) == 0 # Not sure on this. # From qq1 and qq2, we want to select q1,q2 \in \Z such that # `r = a - q * b` is minimal with regards to `self.euclidean_func`, # where `q = self.from_tuple_b(q1,q2)`. # Simply using `round` will not work in all cases; neither does `floor`. # Many test cases are (indirectly) in `test_solveR()`. # Now we are just checking multiple possibilities and use # the smallest one. Note that these are not all possible cases. solutions = [] for q1 in [int(floor(qq1)) + i for i in [-1,0,1,2]]: for q2 in [int(floor(qq2)) + i for i in [-1,0,1,2]]: q = self.from_tuple_b(q1,q2) # q * b + r == a r = _simplify(a - q * b) euc_r = self.euclidean_func(r) solutions += [(euc_r, q, r)] euc_b = self.euclidean_func(b) euc_r, q, r = min(solutions) assert euc_r < euc_b, "%r < %r; r=%r, b=%r, a=%r" % (euc_r, euc_b, r, b, a) return q, r
def calc_prec(self): if self.prec != None: return self.prec iv0 = IntuitiveTetration(self.bsym,self.N-1,iprec=self.iprec,x0=self.x0sym) self.iv0 = iv0 d = lambda x: self.slog(x) - iv0.slog(x) maximum = find_maximum_on_interval(d,0,1,maxfun=20) minimum = find_minimum_on_interval(d,0,1,maxfun=20) print "max:", maximum[0].n(20), 'at:', maximum[1] print "min:", minimum[0].n(20), 'at:', minimum[1] self.err = max( abs(maximum[0]), abs(minimum[0])) print "slog err:", self.err.n(20) self.prec = floor(-self.err.log(2)) self.sexp_err = abs(iv0.sexp(0.5) - self.sexp(0.5)) print "sexp err:", self.sexp_err.n(20) self.sexp_prec = floor(-log(self.sexp_err)/log(2.0)) return self
def _transposition_to_reduced_word(self, t): r""" Converts the transposition `t = [r,s]` to a reduced word. INPUT: - a tuple `[r,s]` such that `r` and `s` are not equivalent mod `k` OUTPUT: - a list of integers in `\{0,1,\ldots,k-1\}` representing a reduced word for the transposition `t` EXAMPLE:: sage: c = Core([],4) sage: c._transposition_to_reduced_word([2, 5]) [2, 3, 0, 3, 2] sage: c._transposition_to_reduced_word([2, 5]) == c._transposition_to_reduced_word([5,2]) True sage: c._transposition_to_reduced_word([2, 2]) Traceback (most recent call last): ... ValueError: t_0 and t_1 cannot be equal mod k sage: c = Core([],30) sage: c._transposition_to_reduced_word([4, 12]) [4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4] sage: c = Core([],3) sage: c._transposition_to_reduced_word([4, 12]) [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 1] """ k = self.k() if (t[0] - t[1]) % k == 0: raise ValueError("t_0 and t_1 cannot be equal mod k") if t[0] > t[1]: return self._transposition_to_reduced_word([t[1], t[0]]) else: return [i % k for i in range(t[0], t[1] - floor((t[1] - t[0]) / k))] + [ (t[1] - floor((t[1] - t[0]) / k) - 2 - i) % (k) for i in range(t[1] - floor((t[1] - t[0]) / k) - t[0] - 1) ]
def __init__(self, n, delta=0.01, m=None): """ Construct LWE instance parameterised by security parameter ``n`` where the modulus ``q`` and the ``stddev`` of the noise is chosen as in [LP2011]_. INPUT: - ``n`` - security parameter (integer > 0) - ``delta`` - error probability per symbol (default: 0.01) - ``m`` - number of allowed samples or ``None`` in which case ``m=2*n + 128`` as in [LP2011]_ (default: ``None``) EXAMPLES:: sage: from sage.crypto.lwe import LindnerPeikert sage: LindnerPeikert(n=20) LWE(20, 2053, Discrete Gaussian sampler over the Integers with sigma = 3.600954 and c = 0, 'noise', 168) """ if m is None: m = 2*n + 128 # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # (c*exp((1-c**2)/2))**(2*n) == 2**-40 # log((c*exp((1-c**2)/2))**(2*n)) == -40*log(2) # (2*n)*log(c*exp((1-c**2)/2)) == -40*log(2) # 2*n*(log(c)+log(exp((1-c**2)/2))) == -40*log(2) # 2*n*(log(c)+(1-c**2)/2) == -40*log(2) # 2*n*log(c)+n*(1-c**2) == -40*log(2) # 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) # Upper bound on s**2/t s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ s = sqrt(s_t_bound*floor(q/4)) # Transform s into stddev stddev = s/sqrt(2*pi.n()) D = DiscreteGaussianDistributionIntegerSampler(stddev) LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m)
def find_integral_max(real_max, f): """Given a real (local) maximum of a function `f`, return that of the integers around `real_max` which gives the (local) integral maximum, and the value of at that point.""" if real_max in ZZ: int_max = Integer(real_max) return (int_max, f(int_max)) else: x_f = floor(real_max) x_c = x_f + 1 f_f, f_c = f(x_f), f(x_c) return (x_f, f_f) if f_f >= f_c else (x_c, f_c)
def calc_diff(self,iv0,debug=0): self.prec=None iv0.prec=None d = lambda x: self.abel(x) - iv0.abel(x) a = find_root(lambda x: (self.f(x)+x)/2-self.x0,self.x0-100,self.f(self.x0)) maximum = find_maximum_on_interval(d,self.x0-a,self.x0+self.f(a),maxfun=20) minimum = find_minimum_on_interval(d,self.x0-a,self.x0+self.f(a),maxfun=20) if debug>=1: print "max:", maximum[0].n(20), 'at:', maximum[1] if debug>=1: print "min:", minimum[0].n(20), 'at:', minimum[1] self.err = max( abs(maximum[0]), abs(minimum[0])) print "err:", self.err.n(20) self.prec = floor(-self.err.log(2))
def log(self,workprec=Infinity): from sage.functions.log import log from sage.functions.other import floor if workprec is Infinity: raise ApproximationError("unable to compute log to infinite precision") parent = self.parent() pow = parent(-1) res = parent(0) t = parent(1) - self iter = workprec + floor(log(workprec)/log(parent._p)) + 1 for i in range(1,iter): pow *= t res += pow / parent(i) res = res.truncate(workprec) return res
def __init__(self, N, delta=0.01, m=None): """ Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where the modulus ``q`` and the ``stddev`` of the noise is chosen as in [LP2011]_. INPUT: - ``N`` - index of cyclotomic polynomial (integer > 0, must be power of 2) - ``delta`` - error probability per symbol (default: 0.01) - ``m`` - number of allowed samples or ``None`` in which case ``3*n`` is used (default: ``None``) EXAMPLES:: sage: from sage.crypto.lwe import RingLindnerPeikert sage: RingLindnerPeikert(N=16) RingLWE(16, 1031, Discrete Gaussian sampler for polynomials of degree < 8 with σ=2.803372 in each component, x^8 + 1, 'noise', 24) """ n = euler_phi(N) if m is None: m = 3*n # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # i.e c>=1 such that 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) # Upper bound on s**2/t s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ s = sqrt(s_t_bound*floor(q/4)) # Transform s into stddev stddev = s/sqrt(2*pi.n()) D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev) RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m)
def ligt(x): r""" Returns the least integer greater than ``x``. EXAMPLES:: sage: from sage.coding.guruswami_sudan.utils import ligt sage: ligt(41) 42 It works with any type of numbers (not only integers):: sage: ligt(41.041) 42 """ return floor(x+1)
def trunc(i): """ Truncates to the integer closer to zero EXAMPLES:: sage: from sage.combinat.crystals.tensor_product import trunc sage: trunc(-3/2), trunc(-1), trunc(-1/2), trunc(0), trunc(1/2), trunc(1), trunc(3/2) (-1, -1, 0, 0, 0, 1, 1) sage: isinstance(trunc(3/2), Integer) True """ if i>= 0: return floor(i) else: return ceil(i)
def P(self, x, y): """ Returns the Kazhdan-Lusztig P polynomial. If the rank is large, this runs slowly at first but speeds up as you do repeated calculations due to the caching. INPUT: - ``x``, ``y`` -- elements of the underlying Coxeter group .. SEEALSO:: :mod:`~sage.libs.coxeter3.coxeter_group.CoxeterGroup.kazhdan_lusztig_polynomial` for a faster implementation using Fokko Ducloux's Coxeter3 C++ library. EXAMPLES :: sage: R.<q>=QQ[] sage: W = WeylGroup("A3", prefix="s") sage: [s1,s2,s3]=W.simple_reflections() sage: KL = KazhdanLusztigPolynomial(W, q) sage: KL.P(s2,s2*s1*s3*s2) q + 1 """ if x == 1: x = self._one if y == 1: y = self._one if x == y: return self._base_ring.one() if not x.bruhat_le(y): return self._base_ring.zero() if y.length() == 0: if x.length() == 0: return self._base_ring.one() else: return self._base_ring.zero() p = sum(-self.R(x,t)*self.P(t,y) for t in self._coxeter_group.bruhat_interval(x,y) if t != x) tr = floor((y.length()-x.length()+1)/2) try: ret = p.truncate(tr) except StandardError: ret = laurent_polynomial_truncate(p, tr) if self._trace: print " P(%s,%s)=%s"%(x, y, ret) return ret
def __call__(self, x): """ Returns `self(x)` INPUT: - ``x`` -- a real number OUTPUT: The value of this Newton polygon at abscissa `x` EXAMPLES: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (3,6) ]); NP Finite Newton polygon with 3 vertices: (0, 0), (1, 1), (3, 6) sage: [ NP(i) for i in range(4) ] [0, 1, 7/2, 6] """ # complexity: O(log(n)) from sage.functions.other import floor vertices = self.vertices() lastslope = self.last_slope() if len(vertices) == 0 or x < vertices[0][0]: return Infinity if x == vertices[0][0]: return vertices[0][1] if x == vertices[-1][0]: return vertices[-1][1] if x > vertices[-1][0]: return vertices[-1][1] + lastslope * (x - vertices[-1][0]) a = 0; b = len(vertices) while b - a > 1: c = floor((a+b)/2) if vertices[c][0] < x: a = c else: b = c (xg,yg) = vertices[a] (xd,yd) = vertices[b] return ((x-xg)*yd + (xd-x)*yg) / (xd-xg)
def gilt(x): r""" Returns the greatest integer smaller than ``x``. EXAMPLES:: sage: from sage.coding.guruswami_sudan.utils import gilt sage: gilt(43) 42 It works with any type of numbers (not only integers):: sage: gilt(43.041) 43 """ if x in ZZ: return Integer(x-1) else: return floor(x)
def _repr_(self,model): from sage.functions.other import floor l = [ ] maxlen = self.ncols() * [0] for i in range(self.nrows()): lp = [ ] for j in range(self.ncols()): s = self[i,j].__repr__() if len(s) > maxlen[j]: maxlen[j] = len(s) lp.append(s) l.append(lp) s = "" for i in range(self.nrows()): s += "[" lp = l[i] for j in range(self.ncols()): length = len(lp[j]) nbspace = floor((maxlen[j]-length) / 2) s += (nbspace + 1)*" " + lp[j] + (maxlen[j] - length - nbspace + 1)*" " s += "]\n" return s[:-1]
def segment_index_at_parameter(self, s): r"""Returns the index of the complex path segment located at the given parameter :math:`s \in [0,1]`. Parameters ---------- s : float Path parameter in the interval [0,1]. Returns ------- index : int The index `k` of the path segment :math:`\gamma_k`. """ # the following is a fast way to divide the interval [0,1] into n # partitions and determine which partition s lies in. since this is # done often it needs to be fast k = floor(s * self._nsegments) diff = (self._nsegments - 1) - k dsgn = diff >> 31 return k + (diff & dsgn)
def segment_index_at_parameter(self, s): r"""Returns the index of the complex path segment located at the given parameter :math:`s \in [0,1]`. Parameters ---------- s : float Path parameter in the interval [0,1]. Returns ------- index : int The index `k` of the path segment :math:`\gamma_k`. """ # the following is a fast way to divide the interval [0,1] into n # partitions and determine which partition s lies in. since this is # done often it needs to be fast k = floor(s*self._nsegments) diff = (self._nsegments - 1) - k dsgn = diff >> 31 return k + (diff & dsgn)
def P(self, x, y): """ Returns the Kazhdan-Lusztig P polynomial. If the rank is large, this runs slowly at first but speeds up as you do repeated calculations due to the caching. EXAMPLES :: sage: R.<q>=QQ[] sage: W = WeylGroup("A3", prefix="s") sage: [s1,s2,s3]=W.simple_reflections() sage: KL = KazhdanLusztigPolynomial(W, q) sage: KL.P(s2,s2*s1*s3*s2) q + 1 """ if x == 1: x = self._one if y == 1: y = self._one if x == y: return 1 if not x.bruhat_le(y): return 0 if y.length() == 0: if x.length() == 0: return 1 else: return 0 p = sum(-self.R(x, t) * self.P(t, y) for t in self._coxeter_group.bruhat_interval(x, y) if t != x) tr = floor((y.length() - x.length() + 1) / 2) try: ret = p.truncate(tr) except: ret = laurent_polynomial_truncate(p, tr) if self._trace: print " P(%s,%s)=%s" % (x, y, ret) return ret
def __iter__(self): if self.__disc is infinity: raise ValueError("infinity is not a true filter index") if self.__reduced: for c in range(0, self._indefinite_content_bound()): yield (0, 0, c) for a in range(1, isqrt(self.__disc // 3) + 1): for b in range(a + 1): for c in range(a, (b**2 + (self.__disc - 1)) // (4 * a) + 1): yield (a, b, c) else: ##FIXME: These are not all matrices for a in range(0, self._indefinite_content_bound()): yield (a, 0, 0) for c in range(1, self._indefinite_content_bound()): yield (0, 0, c) maxtrace = floor(5 * self.__disc / 15 + sqrt(self.__disc) / 2) for a in range(1, maxtrace + 1): for c in range(1, maxtrace - a + 1): Bu = isqrt(4 * a * c - 1) di = 4 * a * c - self.__disc if di >= 0: Bl = isqrt(di) + 1 else: Bl = 0 for b in range(-Bu, -Bl + 1): yield (a, b, c) for b in range(Bl, Bu + 1): yield (a, b, c) #! if self.__reduced raise StopIteration
def __iter__(self) : if self.__disc is infinity : raise ValueError, "infinity is not a true filter index" if self.__reduced : for c in xrange(0, self._indefinite_content_bound()) : yield (0,0,c) for a in xrange(1,isqrt(self.__disc // 3) + 1) : for b in xrange(a+1) : for c in xrange(a, (b**2 + (self.__disc - 1))//(4*a) + 1) : yield (a,b,c) else : ##FIXME: These are not all matrices for a in xrange(0, self._indefinite_content_bound()) : yield (a,0,0) for c in xrange(1, self._indefinite_content_bound()) : yield (0,0,c) maxtrace = floor(5*self.__disc / 15 + sqrt(self.__disc)/2) for a in xrange(1, maxtrace + 1) : for c in xrange(1, maxtrace - a + 1) : Bu = isqrt(4*a*c - 1) di = 4*a*c - self.__disc if di >= 0 : Bl = isqrt(di) + 1 else : Bl = 0 for b in xrange(-Bu, -Bl + 1) : yield (a,b,c) for b in xrange(Bl, Bu + 1) : yield (a,b,c) #! if self.__reduced raise StopIteration
def P(self, x, y): """ Returns the Kazhdan-Lusztig P polynomial. If the rank is large, this runs slowly at first but speeds up as you do repeated calculations due to the caching. EXAMPLES :: sage: R.<q>=QQ[] sage: W = WeylGroup("A3", prefix="s") sage: [s1,s2,s3]=W.simple_reflections() sage: KL = KazhdanLusztigPolynomial(W, q) sage: KL.P(s2,s2*s1*s3*s2) q + 1 """ if x == 1: x = self._one if y == 1: y = self._one if x == y: return 1 if not x.bruhat_le(y): return 0 if y.length() == 0: if x.length() == 0: return 1 else: return 0 p = sum(-self.R(x,t)*self.P(t,y) for t in self._coxeter_group.bruhat_interval(x,y) if t != x) tr = floor((y.length()-x.length()+1)/2) try: ret = p.truncate(tr) except: ret = laurent_polynomial_truncate(p, tr) if self._trace: print " P(%s,%s)=%s"%(x, y, ret) return ret
def __init__(self, bleachermark, runs): from sage.parallel.decorate import parallel from sage.functions.other import ceil, floor self._benchmarks = bleachermark._benchmarks # profiling we run each benchmark once self._totaltime = reduce(lambda a,b: a+b, [r[0] for bm in self._benchmarks for r in bm.run(runs[0])[1:]]) #divide the runs in chunks self._chunksize = ceil(2.0 / self._totaltime) self._nchunks = floor(len(runs)/self._chunksize) self._chunks = [runs[i*self._chunksize:(i+1)*self._chunksize] for i in range(self._nchunks)] if (self._nchunks)*self._chunksize < len(runs): self._chunks.append(runs[(self._nchunks)*self._chunksize:]) # we define the parallel function @parallel def f(indices): results = [] for frun in indices: for i in range(len(self._benchmarks)): bm = self._benchmarks[i] res = bm.run(frun) results.append((i, res)) return results self._getchunks = f(self._chunks) self._currentchunk = []
def frac(x): r""" Return the fractional part of real number x. Not always perfect... EXAMPLES:: sage: from slabbe.diophantine_approx import frac sage: frac(3.2) 0.200000000000000 sage: frac(-3.2) 0.800000000000000 sage: frac(pi) pi - 3 sage: frac(pi).n() 0.141592653589793 This looks suspicious...:: sage: frac(pi*10**15).n() 0.000000000000000 """ return x - floor(x)
def _dismantle(self, r): """ Return parameters for an r-part dismantlement of a Q-antipodal association scheme. """ if r == self._.r: return self elif r == 1: return self.antipodalFraction() if self._.d == 1: scheme = QPolyParameters((r-1, ), (Integer(1), )) elif self._.d == 2: m = self._.m[1] * r / self._.r scheme = QPolyParameters((m, r-1), (Integer(1), m)) else: m = floor(self._.d / 2) b, c = (list(t) for t in self.kreinArray()) c[self._.d - m - 1] *= self._.r / r b[m] = (r-1) * c[self._.d - m - 1] scheme = QPolyParameters(b, c) r = min(len(scheme._.dismantled_schemes), len(self._.dismantled_schemes)) scheme._.dismantled_schemes[:r] = self._.dismantled_schemes[:r] return scheme
def dirichlet_convergents_dependance(v, n, verbose=False): r""" INPUT: - ``v`` -- list of real numbers - ``n`` -- integer, number of iterations - ``verbose`` -- bool (default: ``False``), OUTPUT: - table of linear combinaisons of dirichlet approximations in terms of previous dirichlet approximations EXAMPLES:: sage: from slabbe.diophantine_approx import dirichlet_convergents_dependance sage: dirichlet_convergents_dependance([e,pi], 4) i vi lin. rec. remainder +---+-----------------------+-------------+-----------+ 0 (3, 3, 1) [] (3, 3, 1) 1 (19, 22, 7) [6] (1, 4, 1) 2 (1843, 2130, 678) [96, 6] (1, 0, 0) 3 (51892, 59973, 19090) [28, 15, 1] (0, 0, 0) The last 3 seems enough:: sage: dirichlet_convergents_dependance([e,pi], 8) i vi lin. rec. remainder +---+--------------------------+-------------+-----------+ 0 (3, 3, 1) [] (3, 3, 1) 1 (19, 22, 7) [6] (1, 4, 1) 2 (1843, 2130, 678) [96, 6] (1, 0, 0) 3 (51892, 59973, 19090) [28, 15, 1] (0, 0, 0) 4 (113018, 130618, 41577) [2, 5, 1] (0, 0, 0) 5 (114861, 132748, 42255) [1, 0, 1] (0, 0, 0) 6 (166753, 192721, 61345) [1, 0, 1] (0, 0, 0) 7 (446524, 516060, 164267) [2, 0, 1] (0, 0, 0) But not in this case:: sage: dirichlet_convergents_dependance([pi,sqrt(3)], 12) i vi lin. rec. remainder +----+-----------------------+--------------------------+-----------+ 0 (3, 2, 1) [] (3, 2, 1) 1 (22, 12, 7) [6] (4, 0, 1) 2 (47, 26, 15) [2, 1] (0, 0, 0) 3 (69, 38, 22) [1, 1] (0, 0, 0) 4 (176, 97, 56) [2, 0, 1, 4] (4, 1, 1) 5 (223, 123, 71) [1, 0, 1] (0, 0, 0) 6 (399, 220, 127) [1, 1] (0, 0, 0) 7 (1442, 795, 459) [3, 1, 0, 0, 0, 1] (0, 0, 0) 8 (6390, 3523, 2034) [4, 1, 1] (0, 0, 0) 9 (26603, 14667, 8468) [4, 0, 2, 1, 0, 0, 0, 1] (0, 0, 0) 10 (32993, 18190, 10502) [1, 1] (0, 0, 0) 11 (40825, 22508, 12995) [1, 0, 1, 1] (0, 0, 0) The v4 is not a lin. comb. of the previous four:: sage: dirichlet_convergents_dependance([e,pi,sqrt(3)], 5) i vi lin. rec. remainder +---+---------------------------------+----------------+--------------+ 0 (3, 3, 2, 1) [] (3, 3, 2, 1) 1 (19, 22, 12, 7) [6] (1, 4, 0, 1) 2 (193, 223, 123, 71) [10, 1] (0, 0, 1, 0) 3 (5529, 6390, 3523, 2034) [28, 6, 3] (2, 5, 1, 1) 4 (163067, 188461, 103904, 59989) [29, 14, 1, 1] (2, 4, 1, 1) """ L = [] it = best_simultaneous_convergents(v) rows = [] for i in range(n): vi = vector(next(it)) t = vi M = [] for u in reversed(L): m = floor(min(a / b for a, b in zip(t, u))) M.append(m) t -= m * u if t == 0: if verbose: c = ','.join("v{}".format(len(L) - j) for j in range(len(M))) print "v{} = {} = <{}>.<{}>".format(i, vi, M, c) break else: if verbose: print "v{} = {} = <{}>.<v{}, ..., v0> + {}".format( i, vi, M, i - 1, t) L.append(vi) row = [i, vi, M, t] rows.append(row) header_row = ['i', 'vi', 'lin. rec.', 'remainder'] from sage.misc.table import table return table(rows=rows, header_row=header_row)
def _sanitise_rootfinding_input(Q, maxd, precision): r""" Verifies, converts and sanitises legal input to the root-finding procedures, as well as returning relevant helper variables. INPUT: - ``Q`` -- a bivariate polynomial, represented either over `F[x,y]`, `F[x][y]` or `F[x]` list. - ``maxd``, an integer, the maximal degree of a root of ``Q`` that we're interested in, possibly ``None``. - ``precision``, an integer, the precision asked for modular roots of ``Q``, possibly ``None``. OUTPUT: - ``Q``, a modified version of ``Q``, where all monomials have been truncated to ``precision``. Represented as an `F[x]` list. - ``Qinp``, the original ``Q`` passed in input, represented as an `F[x]` list. - ``F``, the base ring of the coefficients in ``Q``'s first variable. - ``Rx``, the polynomial ring `F[x]`. - ``x``, the generator of ``Rx``. - ``maxd``, the maximal degree of a root of ``Q`` that we're interested in, possibly inferred according ``precision``. EXAMPLES:: sage: from sage.coding.guruswami_sudan.rootfinding import _sanitise_rootfinding_input sage: F = GF(17) sage: Px.<x> = F[] sage: Pxy.<y> = Px[] sage: Q = (y - (x**2 + x + 1)) * (y**2 - x + 1) * (y - (x**3 + 4*x + 16)) sage: _sanitise_rootfinding_input(Q, None, None) ([16*x^6 + 13*x^4 + 2*x^3 + 4*x + 16, x^4 + 4*x^2 + 12*x, x^5 + x^4 + 5*x^3 + 3*x^2 + 2*x, 16*x^3 + 16*x^2 + 12*x, 1], [16*x^6 + 13*x^4 + 2*x^3 + 4*x + 16, x^4 + 4*x^2 + 12*x, x^5 + x^4 + 5*x^3 + 3*x^2 + 2*x, 16*x^3 + 16*x^2 + 12*x, 1], Finite Field of size 17, Univariate Polynomial Ring in x over Finite Field of size 17, x, 3) """ (Q, Rx) = _convert_Q_representation(Q) if Q == []: return ([], [], None, Rx, None, 0) # Q == 0 so just bail Qinp = Q F = Rx.base_ring() x = Rx.gen() if not maxd: if precision: maxd = precision - 1 else: #The maximal degree of a root is at most #(di-dl)/(l-i) d being the degree of a monomial maxd = 0 l = len(Q) - 1 dl = Q[l].degree() for i in range(l): qi = Q[i] if not qi.is_zero(): tmp = floor((qi.degree() - dl) / (l - i)) if tmp > maxd: maxd = tmp if precision: for t in range(len(Q)): if Q[t].degree >= precision: Q[t] = Q[t].truncate(precision) return (Q, Qinp, F, Rx, x, maxd)
def dimension_new_cusp_forms(self, k=2, p=0): r""" Return the dimension of the space of new (or `p`-new) weight `k` cusp forms for this congruence subgroup. INPUT: - `k` -- an integer (default: 2), the weight. Not fully implemented for `k = 1`. - `p` -- integer (default: 0); if nonzero, compute the `p`-new subspace. OUTPUT: Integer ALGORITHM: This comes from the formula given in Theorem 1 of http://www.math.ubc.ca/~gerg/papers/downloads/DSCFN.pdf EXAMPLES:: sage: Gamma0(11000).dimension_new_cusp_forms() 240 sage: Gamma0(11000).dimension_new_cusp_forms(k=1) 0 sage: Gamma0(22).dimension_new_cusp_forms(k=4) 3 sage: Gamma0(389).dimension_new_cusp_forms(k=2,p=17) 32 TESTS:: sage: L = [1213, 1331, 2169, 2583, 2662, 2745, 3208, ....: 3232, 3465, 3608, 4040, 4302, 4338] sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L) True """ from sage.arith.all import moebius from sage.functions.other import floor N = self.level() k = ZZ(k) if not (p == 0 or N % p): return (self.dimension_cusp_forms(k) - 2 * self.restrict(N // p).dimension_new_cusp_forms(k)) if k < 2 or k % 2: return ZZ.zero() factors = list(N.factor()) def s0(q, a): # function s_0^# if a == 1: return 1 - 1 / q elif a == 2: return 1 - 1 / q - 1 / q**2 else: return (1 - 1 / q) * (1 - 1 / q**2) def vinf(q, a): # function v_oo^# if a % 2: return 0 elif a == 2: return q - 2 else: return q**(a / 2 - 2) * (q - 1)**2 def v2(q, a): # function v_2^# if q % 4 == 1: if a == 2: return -1 else: return 0 elif q % 4 == 3: if a == 1: return -2 elif a == 2: return 1 else: return 0 elif a in (1, 2): return -1 elif a == 3: return 1 else: return 0 def v3(q, a): # function v_3^# if q % 3 == 1: if a == 2: return -1 else: return 0 elif q % 3 == 2: if a == 1: return -2 elif a == 2: return 1 else: return 0 elif a in (1, 2): return -1 elif a == 3: return 1 else: return 0 res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors) res -= prod(vinf(q, a) for q, a in factors) / ZZ(2) res += ( (1 - k) / 4 + floor(k / 4)) * prod(v2(q, a) for q, a in factors) res += ( (1 - k) / 3 + floor(k / 3)) * prod(v3(q, a) for q, a in factors) if k == 2: res += moebius(N) return res
def _suitable_parameters_given_tau(tau, C=None, n_k=None): r""" Return quite good multiplicity and list size parameters for the code parameters and the decoding radius. These parameters are not guaranteed to be the best ones possible for the provided ``tau``, but arise from easily-evaluated closed expressions and are very good approximations of the best ones. See [Nie2013]_ pages 53-54, proposition 3.11 for details. INPUT: - ``tau`` -- an integer, number of errors one wants the Guruswami-Sudan algorithm to correct - ``C`` -- (default: ``None``) a :class:`GeneralizedReedSolomonCode` - ``n_k`` -- (default: ``None``) a pair of integers, respectively the length and the dimension of the :class:`GeneralizedReedSolomonCode` OUTPUT: - ``(s, l)`` -- a pair of integers, where: - ``s`` is the multiplicity parameter, and - ``l`` is the list size parameter. .. NOTE:: One has to provide either ``C`` or ``(n, k)``. If neither or both are given, an exception will be raised. EXAMPLES: The following is an example where the parameters are optimal:: sage: tau = 98 sage: n, k = 250, 70 sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) (2, 3) sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) (2, 3) This is an example where they are not:: sage: tau = 97 sage: n, k = 250, 70 sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) (2, 3) sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) (1, 2) We can provide a GRS code instead of `n` and `k` directly:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, C = C) (2, 3) Another one with a bigger ``tau``:: sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(118, C = C) (47, 89) """ n, k = n_k_params(C, n_k) w = k - 1 atau = n - tau smin = tau * w / (atau**2 - n * w) s = floor(1 + smin) D = (s - smin) * (atau**2 - n * w) * s + (w**2) / 4 l = floor(atau / w * s + 0.5 - sqrt(D) / w) return (s, l)
def _contained_discriminant_bound(self) : return floor( (self.index() / ( Integer(1) + self.__level + self.__level**2) )**2 )
def guess(self, sequence, algorithm='sage'): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by -1/2/(x - 1/2) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by -1/2/(x - 1/2) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == 'bm': from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError('Sequence too short for guessing.') R = PowerSeriesRing(QQ, 'x') if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == 'pari': global _gp if len(sequence) < 6: raise ValueError('Sequence too short for guessing.') if _gp is None: _gp = Gp() _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") _gp.set('gf', sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import floor, ceil from numpy import trim_zeros l = len(sequence) while l > 0 and sequence[l - 1] == 0: l -= 1 sequence = sequence[:l] if l == 0: return 0 if l < 6: raise ValueError('Sequence too short for guessing.') hl = ceil(ZZ(l) / 2) A = matrix([sequence[k:k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, 'x') den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x != 0), None) S = PowerSeriesRing(QQ, 'x', default_prec=l - offset) num = S(R(sequence) * den).add_bigoh(floor(ZZ(l) / 2 + 1)).truncate() if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
def my_log(number): return floor(log(abs(number), 10.))
def amortized_padic_H_values_interval(self, ans, t, start, end, pclass, fixbreak, testp=None, use_c=False): r""" Return a dictionary p -> M[p] (0, P_m0)*A[p] = A[p][0,0] (S, P_m1) where P_m = t^m \prod_i (alpha_i)_m ^* / (beta_i)_m ^* mod p, m0 = floor(start(p-1)) + 1, m1 = floor(end(p-1)), S = \sum_{m = m0} ^{m1 - 1} P_m EXAMPLES:: sage: for cyca, cycb, start, end, p, t in [ ....: ([6], [1, 1], 0, 1/6, 97, 1), ....: ([4, 2, 2], [3, 1, 1], 1/3, 1/2, 97, 1), ....: ([22], [1, 1, 20], 3/20, 5/22, 1087, 1), ....: ([22], [1, 1, 20], 3/20, 5/22, 1087, 1337/507734), ....: ([22], [1, 1, 20], 3/20, 5/22, 1019, 1337/507734)]: ....: H = AmortizingHypergeometricData(p+40, cyclotomic=(cyca, cycb)) ....: pclass = p % start.denominator() ....: shift, offset = H._starts_to_rationals[start][pclass] ....: amortized = H.amortized_padic_H_values_interval(t=t, start=start, end=end, pclass=pclass) ....: t = GF(p)(t) ....: naive_sum = 0 ....: for k in range(floor(start*(p-1))+1, floor(end * (p-1))): ....: naive_sum += t**k * H.pochhammer_quotient(p, k) ....: naive_res = vector(GF(p), (naive_sum, t**floor(end * (p-1)) * H.pochhammer_quotient(p, floor(end * (p-1) )))) ....: M = matrix(GF(p), amortized[p]) ....: res = (vector(GF(p), [0,t**(floor(start*(p-1))+1) * H.pochhammer_quotient(p, floor(start*(p-1))+1 )])*M/M[0,0]) ....: if naive_res != res: ....: print(cyca, cycb, start, end, p, t, naive_res, res) """ d = start.denominator() shift, offset = self._starts_to_rationals[start][pclass] def mbound(p): # FIXME # in practice we are getting # prod up mbound - 1 # there is something wrong with the Tree # once we fix that, we should fix the bound here return max((end * (p - 1)).floor() - (start * (p - 1)).floor(), 1) f, g, mats = self._matrices(t=t, start=start, shift=shift, offset=offset) if use_c: k = f.parent().gen() y = self.interval_mults[start] M = matrix([[g, 0], [y * g, f]]) indices = self._prime_range(t)[d][pclass] remainder_forest( M, lambda p: p, #lambda p: mbound_c(p,start,end), mbound_dict_c(indices, start, end), kbase=1, indices=indices, V=fixbreak, ans=ans) else: forest = AccRemForest( self.N, cut_functions={None: mbound}, bottom_generator=mats, prec=1, primes=self._prime_range(t)[d][pclass], ) bottom = forest.tree_bottom() # Now we have a formula for # (0, P_m0)*A[p] = A[p][0,0] (\sum_{m = m0} ^{m1 - 1} P_m, P_m1) # with # m0 = floor(start * (p-1)) + 1 # m1 = floor(end * (p-1)) if testp in bottom: print( "amortized_padic_H_values_interval(t=%s, start=%s, end=%s, pclass=%s)" % (t, start, end, pclass)) p = testp R = GF(p) if bottom[testp] != 1: M = bottom[testp].change_ring(R) # FIXME why the -1? Probably because partial_factorial doesn't include right endpoint assert M == prod( elt.change_ring(GF(R)) for elt in mats( floor(end * (p - 1)) - floor(start * (p - 1)) - 1)) t = R(t) naive_sum = 0 pmult = self.interval_mults[start] for k in range( floor(start * (p - 1)) + 1, floor(end * (p - 1))): naive_sum += t**k * self.pochhammer_quotient(p, k) naive_sum *= pmult naive_res = vector( R, (naive_sum, t**floor(end * (p - 1)) * self.pochhammer_quotient(p, floor(end * (p - 1))))) res = vector(R, [ 0, t**(floor(start * (p - 1)) + 1) * self.pochhammer_quotient(p, floor(start * (p - 1)) + 1) ]) * M / M[0, 0] assert naive_res == res, "%s != %s, M = %s" % (naive_res, res, M) # set ans for k, M in bottom.items(): ans[k] = ans[k] * fixbreak * M
def _init_frob(self, desired_prec=None): """ Initialise everything for Frobenius polynomial computation. TESTS:: sage: p = 4999 sage: x = PolynomialRing(GF(p),"x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._init_frobQ True sage: C._plarge True sage: C._sqrtp True """ def _N0_RH(): return ceil( log(2 * binomial(2 * self._genus, self._genus), self._p) + self._genus * self._n / ZZ(2)) def _find_N0(): if self._nodenominators: return _N0_nodenominators(self._p, self._genus, self._n) else: return _N0_RH() + self._extraprec def _find_N_43(): """ Find the precision used for thm 4.3 in Goncalves for p >> 0, N = N0 + 2 """ p = self._p r = self._r d = self._d delta = self._delta N0 = self._N0 left_side = N0 + floor(log((d * p * (r - 1) + r) / delta) / log(p)) def right_side_log(n): return floor(log(p * (r * n - 1) - r) / log(p)) n = left_side while n <= left_side + right_side_log(n): n += 1 return n if not self._init_frobQ or self._N0 != desired_prec: if self._r < 2 or self._d < 2: raise NotImplementedError( "Only implemented for r, f.degree() >= 2") self._init_frobQ = True self._Fq = self._f.base_ring() self._p = self._Fq.characteristic() self._q = self._Fq.cardinality() self._n = self._Fq.degree() self._epsilon = 0 if self._delta == 1 else 1 # our basis choice doesn't always give an integral matrix if self._epsilon == 0: self._extraprec = floor( log(self._r, self._p) + log((2 * self._genus + (self._delta - 2)) / self._delta, self._p)) else: self._extraprec = floor(log(self._r * 2 - 1, self._p)) self._nodenominators = self._extraprec == 0 if desired_prec is None: self._N0 = _find_N0() else: self._N0 = desired_prec self._plarge = self._p > self._d * self._r * (self._N0 + self._epsilon) # working prec if self._plarge: self._N = self._N0 + 1 else: self._N = _find_N_43() # we will use the sqrt(p) version? self._sqrtp = self._plarge and self._p == self._q self._extraworkingprec = self._extraprec if not self._plarge: # we might have some denominators showing up during horizontal # and vertical reductions self._extraworkingprec += 2 * ceil( log(self._d * self._r * (self._N0 + self._epsilon), self._p)) # Rings if self._plarge and self._nodenominators: if self._n == 1: # IntegerModRing is significantly faster than Zq self._Zq = IntegerModRing(self._p**self._N) if self._sqrtp: self._Zq0 = IntegerModRing(self._p**(self._N - 1)) self._Qq = Qq(self._p, prec=self._N, type="capped-rel") self._w = 1 else: self._Zq = Zq( self._q, names="w", modulus=self._Fq.polynomial(), prec=self._N, type="capped-abs", ) self._w = self._Zq.gen() self._Qq = self._Zq.fraction_field() else: self._Zq = Qq( self._q, names="w", modulus=self._Fq.polynomial(), prec=self._N + self._extraworkingprec, ) self._w = self._Zq.gen() self._Qq = self._Zq self._Zp = Zp(self._p, prec=self._N + self._extraworkingprec) self._Zqx = PolynomialRing(self._Zq, "x") # Want to take a lift of f from Fq to Zq if self._n == 1: # When n = 1, can lift from Fp[x] to Z[x] and then to Zp[x] self._flift = self._Zqx([elt.lift() for elt in self._f.list()]) self._frobf = self._Zqx(self._flift.list()) else: # When n > 1, need to be more careful with the lift self._flift = self._Zqx([ elt.polynomial().change_ring(ZZ)(self._Zq.gen()) for elt in self._f.list() ]) self._frobf = self._Zqx( [elt.frobenius() for elt in self._flift.list()]) self._dflift = self._flift.derivative() # Set up local cache for Frob(f)^s # This variable will store the powers of frob(f) frobpow = [None] * (self._N0 + 2) frobpow[0] = self._Zqx(1) for k in range(self._N0 + 1): frobpow[k + 1] = self._frobf * frobpow[k] # We don't make it a polynomials as we need to keep track that the # ith coefficient represents (i*p)-th self._frobpow_list = [elt.list() for elt in frobpow] if self._sqrtp: # precision of self._Zq0 N = self._N - 1 vandermonde = matrix(self._Zq0, N, N) for i in range(N): vandermonde[i, 0] = 1 for j in range(1, N): vandermonde[i, j] = vandermonde[i, j - 1] * (i + 1) self._vandermonde = vandermonde.inverse() self._horizontal_fat_s = {} self._vertical_fat_s = {}
def right_side_log(n): return floor(log(p * (r * n - 1) - r) / log(p))
def iter_positive_forms(self) : if self.__disc is infinity : raise ValueError, "infinity is not a true filter index" if self.__reduced : for (l, (u,x)) in enumerate(self.__p1list) : if u == 0 : for a in xrange(self.__level, isqrt(self.__disc // 4) + 1, self.__level) : for b in xrange(a+1) : for c in xrange(a, (b**2 + (self.__disc - 1))//(4*a) + 1) : yield ((a,b,c), l) else : for a in xrange(1, isqrt(self.__disc // 3) + 1) : for b in xrange(a+1) : ## We need x**2 * a + x * b + c % N == 0 h = (-((x**2 + 1) * a + x * b)) % self.__level for c in xrange( a + h, (b**2 + (self.__disc - 1))//(4*a) + 1, self.__level ) : yield ((a,b,c), l) #! if self.__reduced else : maxtrace = floor(self.__disc / Integer(3) + sqrt(self.__disc / Integer(3))) for (l, (u,x)) in enumerate(self.__p1list) : if u == 0 : for a in xrange(self.__level, maxtrace + 1, self.__level) : for c in xrange(1, maxtrace - a + 1) : Bu = isqrt(4*a*c - 1) di = 4*a*c - self.__disc if di >= 0 : Bl = isqrt(di) + 1 else : Bl = 0 for b in xrange(-Bu, -Bl + 1) : yield ((a,b,c), l) for b in xrange(Bl, Bu + 1) : yield ((a,b,c), l) else : for a in xrange(1, maxtrace + 1) : for c in xrange(1, maxtrace - a + 1) : Bu = isqrt(4*a*c - 1) di = 4*a*c - self.__disc if di >= 0 : Bl = isqrt(di) + 1 else : Bl = 0 h = (-x * a - int(Mod(x, self.__level)**-1) * c - Bu) % self.__level \ if x != 0 else \ (-Bu) % self.__level for b in xrange(-Bu + self.__level - h, -Bl + 1, self.__level) : yield ((a,b,c), l) h = (-x * a - int(Mod(x, self.__level)**-1) * c + Bl) % self.__level \ if x !=0 else \ Bl % self.__level for b in xrange(Bl + self.__level - h, Bu + 1, self.__level) : yield ((a,b,c), l) #! else self.__reduced raise StopIteration
def _borcherds_product_polyhedron(self, pole_order, prec, verbose=False): r""" Construct a polyhedron representing a cone of Heegner divisors. For internal use in the methods borcherds_input_basis() and borcherds_input_Qbasis(). INPUT: - ``pole_order`` -- pole order - ``prec`` -- precision OUTPUT: a tuple consisting of an integral matrix M, a Polyhedron p, and a WeilRepModularFormsBasis X """ K = self.weilrep().base_field() O_K = K.maximal_order() S = self.gram_matrix() wt = self.input_wt() w = self.weilrep() rds = w.rds() norm_dict = w.norm_dict() X = w.nearly_holomorphic_modular_forms_basis(wt, pole_order, prec, verbose=verbose) N = len([g for g in rds if not norm_dict[tuple(g)]]) v_list = w.coefficient_vector_exponents(0, 1, starting_from=-pole_order, include_vectors=True) exp_list = [v[1] for v in v_list] d = w._ds_to_hds() v_list = [vector(d[tuple(v[0])]) for v in v_list] d = K.discriminant() positive = [] zero = vector([0] * (len(exp_list) + 1)) M = Matrix([ x.coefficient_vector(starting_from=-pole_order, ending_with=0)[:-N] for x in X ]) vs = M.transpose().kernel().basis() prec = floor(min(exp_list) / max(filter(bool, exp_list))) norm_list = w._norm_form().short_vector_list_up_to_length(prec + 1) units = w._units() _w = w._w() norm_list = [[a + b * _w for a, b in x] for x in norm_list] excluded_list = set([]) if d >= -4: if d == -4: f = w.multiplication_by_i() f2 = None else: f = w.multiplication_by_zeta() f2 = f * f ys = [] mult = len(units) // 2 for i, n in enumerate(exp_list): if i not in excluded_list: ieq = copy(zero) ieq[i + 1] = 1 v1 = v_list[i] if d >= -4: v2 = f(v1) j = next(j for j, x in enumerate(v_list) if exp_list[i] == exp_list[j] and (all( t in O_K for t in x - v2) or all(t in O_K for t in x + v2))) ieq[j + 1] += 1 if i != j: excluded_list.add(j) y = copy(zero) y[i + 1] = 1 y[j + 1] = -1 ys.append(y) if f2 is not None: v2 = f2(v1) j = next(j for j, x in enumerate(v_list) if exp_list[i] == exp_list[j] and (all( t in O_K for t in x - v2) or all(t in O_K for t in x + v2))) ieq[j + 1] += 1 if i != j: excluded_list.add(j) y = copy(zero) y[i + 1] = 1 y[j + 1] = -1 ys.append(y) for j, m in enumerate(exp_list[:i]): if j not in excluded_list: N = m / n if N in ZZ and N > 1: v2 = v_list[j] ieq[j + 1] = mult * any( all(t in O_K for t in x * v1 + u * v2) for x in norm_list[N] for u in units) positive.append(ieq) # * denominator(ieq) p = Polyhedron(ieqs=positive, eqns=[vector([0] + list(v)) for v in vs] + ys) return M, p, X
def guess(self, sequence, algorithm="sage"): """ Return the minimal CFiniteSequence that generates the sequence. Assume the first value has index 0. INPUT: - ``sequence`` -- list of integers - ``algorithm`` -- string - 'sage' - the default is to use Sage's matrix kernel function - 'pari' - use Pari's implementation of LLL - 'bm' - use Sage's Berlekamp-Massey algorithm OUTPUT: - a CFiniteSequence, or 0 if none could be found With the default kernel method, trailing zeroes are chopped off before a guessing attempt. This may reduce the data below the accepted length of six values. EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: C.guess([1,2,4,8,16,32]) C-finite sequence, generated by 1/(-2*x + 1) sage: r = C.guess([1,2,3,4,5]) Traceback (most recent call last): ... ValueError: Sequence too short for guessing. With Berlekamp-Massey, if an odd number of values is given, the last one is dropped. So with an odd number of values the result may not generate the last value:: sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r C-finite sequence, generated by 1/(-2*x + 1) sage: r[0:5] [1, 2, 4, 8, 16] """ S = self.polynomial_ring() if algorithm == "bm": from sage.matrix.berlekamp_massey import berlekamp_massey if len(sequence) < 2: raise ValueError("Sequence too short for guessing.") R = PowerSeriesRing(QQ, "x") if len(sequence) % 2 == 1: sequence = sequence[:-1] l = len(sequence) - 1 denominator = S(berlekamp_massey(sequence).list()[::-1]) numerator = R(S(sequence) * denominator, prec=l).truncate() return CFiniteSequence(numerator / denominator) elif algorithm == "pari": global _gp if len(sequence) < 6: raise ValueError("Sequence too short for guessing.") if _gp is None: _gp = Gp() _gp( "ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q" ) _gp.set("gf", sequence) _gp("gf=ggf(gf)") num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) if num == 0: return 0 else: return CFiniteSequence(num / den) else: from sage.matrix.constructor import matrix from sage.functions.other import floor, ceil from numpy import trim_zeros l = len(sequence) while l > 0 and sequence[l - 1] == 0: l -= 1 sequence = sequence[:l] if l == 0: return 0 if l < 6: raise ValueError("Sequence too short for guessing.") hl = ceil(ZZ(l) / 2) A = matrix([sequence[k : k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 R = PolynomialRing(QQ, "x") den = R(trim_zeros(K.basis()[-1].list()[::-1])) if den == 1: return 0 offset = next((i for i, x in enumerate(sequence) if x != 0), None) S = PowerSeriesRing(QQ, "x", default_prec=l - offset) num = S(R(sequence) * den).add_bigoh(floor(ZZ(l) / 2 + 1)).truncate() if num == 0 or sequence != S(num / den).list(): return 0 else: return CFiniteSequence(num / den)
def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): r""" Creation of hypergeometric motives. INPUT: three possibilities are offered, each describing a quotient of products of cyclotomic polynomials. - ``cyclotomic`` -- a pair of lists of nonnegative integers, each integer `k` represents a cyclotomic polynomial `\Phi_k` - ``alpha_beta`` -- a pair of lists of rationals, each rational represents a root of unity - ``gamma_list`` -- a pair of lists of nonnegative integers, each integer `n` represents a polynomial `x^n - 1` In the last case, it is also allowed to send just one list of signed integers where signs indicate to which part the integer belongs to. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: Hyp(cyclotomic=([2],[1])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/2],[0])) Hypergeometric data for [1/2] and [0] sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5],[1,1,1,1,1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] """ if gamma_list is not None: if isinstance(gamma_list[0], (list, tuple)): pos, neg = gamma_list gamma_list = pos + [-u for u in neg] cyclotomic = gamma_list_to_cyclotomic(gamma_list) if cyclotomic is not None: cyclo_up, cyclo_down = cyclotomic if any(x in cyclo_up for x in cyclo_down): raise ValueError('overlapping parameters not allowed') deg = sum(euler_phi(x) for x in cyclo_down) up_deg = sum(euler_phi(x) for x in cyclo_up) if up_deg != deg: msg = 'not the same degree: {} != {}'.format(up_deg, deg) raise ValueError(msg) cyclo_up.sort() cyclo_down.sort() alpha = cyclotomic_to_alpha(cyclo_up) beta = cyclotomic_to_alpha(cyclo_down) elif alpha_beta is not None: alpha, beta = alpha_beta if len(alpha) != len(beta): raise ValueError('alpha and beta not of the same length') alpha = sorted(u - floor(u) for u in alpha) beta = sorted(u - floor(u) for u in beta) cyclo_up = alpha_to_cyclotomic(alpha) cyclo_down = alpha_to_cyclotomic(beta) deg = sum(euler_phi(x) for x in cyclo_down) self._cyclo_up = tuple(cyclo_up) self._cyclo_down = tuple(cyclo_down) self._alpha = tuple(alpha) self._beta = tuple(beta) self._deg = deg self._gamma_array = cyclotomic_to_gamma(cyclo_up, cyclo_down) self._trace_coeffs = {} up = QQ.prod(capital_M(d) for d in cyclo_up) down = QQ.prod(capital_M(d) for d in cyclo_down) self._M_value = up / down if 0 in alpha: self._swap = HypergeometricData(alpha_beta=(beta, alpha)) if self.weight() % 2: self._sign_param = 1 else: if (deg % 2) != (0 in alpha): self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_down) else: self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_up)
def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, parameters = None , parameter_values = None, dig = 20, tolrel=1e-16, tolabs=1e-16, output = ''): r""" Generate the needed files for the mpfr module of the tides library. INPUT: - ``integrator`` -- the name of the integrator file. - ``driver`` -- the name of the driver file. - ``f`` -- the function that determines the differential equation. - ``ics`` -- a list or tuple with the initial conditions. - ``initial`` -- the initial time for the integration. - ``final`` -- the final time for the integration. - ``delta`` -- the step of the output. - ``parameters`` -- the variables inside the function that should be treated as parameters. - ``parameter_values`` -- the values of the parameters for the particular initial value problem. - ``dig`` -- the number of digits of precission that will be used in the integration - ``tolrel`` -- the relative tolerance. - ``tolabs`` -- the absolute tolerance. - ``output`` -- the name of the file that the compiled integrator will write to This function creates two files, integrator and driver, that can be used later with the tides library ([TI]_). TESTS:: sage: from tempfile import mkdtemp sage: from sage.interfaces.tides import genfiles_mpfr sage: import os sage: import shutil sage: from sage.misc.temporary_file import tmp_dir sage: tempdir = tmp_dir() sage: intfile = os.path.join(tempdir, 'integrator.c') sage: drfile = os.path.join(tempdir ,'driver.c') sage: var('t,x,y,X,Y') (t, x, y, X, Y) sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)] sage: genfiles_mpfr(intfile, drfile, f, [1,0, 0, 0.2], 0, 10, 0.1, output = 'out', dig = 50) sage: fileint = open(intfile) sage: l = fileint.readlines() sage: fileint.close() sage: l[5] ' #include "mp_tides.h"\n' sage: l[15] '\tstatic int PARAMETERS = 0;\n' sage: l[25] '\t\tmpfrts_var_t(itd, link[5], var[3], i);\n' sage: l[30] '\t\tmpfrts_pow_t_c(itd, link[2], "-1.500000000000000000000000000000000000000000000000000", link[3], i);\n' sage: l[35] '\n' sage: l[36] ' }\n' sage: l[37] ' write_mp_solution();\n' sage: filedr = open(drfile) sage: l = filedr.readlines() sage: filedr.close() sage: l[6] ' #include "mpfr.h"\n' sage: l[16] ' int nfun = 0;\n' sage: l[26] '\tmpfr_set_str(v[2], "0.0000000000000000000000000000000000000000000000000000", 10, TIDES_RND);\n' sage: l[30] '\tmpfr_init2(tolabs, TIDES_PREC); \n' sage: l[34] '\tmpfr_init2(tini, TIDES_PREC); \n' sage: l[40] '\tmp_tides_delta(function_iteration, NULL, nvar, npar, nfun, v, p, tini, dt, nipt, tolrel, tolabs, NULL, fd);\n' sage: shutil.rmtree(tempdir) Check that ticket :trac:`17179` is fixed (handle expressions like `\\pi`):: sage: from sage.interfaces.tides import genfiles_mpfr sage: import os sage: import shutil sage: from sage.misc.temporary_file import tmp_dir sage: tempdir = tmp_dir() sage: intfile = os.path.join(tempdir, 'integrator.c') sage: drfile = os.path.join(tempdir ,'driver.c') sage: var('t,x,y,X,Y') (t, x, y, X, Y) sage: f(t,x,y,X,Y)=[X, Y, -x/(x^2+y^2)^(3/2), -y/(x^2+y^2)^(3/2)] sage: genfiles_mpfr(intfile, drfile, f, [pi, 0, 0, 0.2], 0, 10, 0.1, output = 'out', dig = 50) sage: fileint = open(intfile) sage: l = fileint.readlines() sage: fileint.close() sage: l[30] '\t\tmpfrts_pow_t_c(itd, link[2], "-1.500000000000000000000000000000000000000000000000000", link[3], i);\n' sage: filedr = open(drfile) sage: l = filedr.readlines() sage: filedr.close() sage: l[24] '\tmpfr_set_str(v[0], "3.141592653589793238462643383279502884197169399375101", 10, TIDES_RND);\n' sage: shutil.rmtree(tempdir) """ if parameters == None: parameters = [] if parameter_values == None: parameter_values = [] RR = RealField(ceil(dig * 3.3219)) l1, l2 = subexpressions_list(f, parameters) remove_repeated(l1, l2) remove_constants(l1, l2) l3=[] var = f[0].arguments() l0 = map(str, l1) lv = map(str, var) lp = map(str, parameters) for i in l2: oper = i[0] if oper in ["log", "exp", "sin", "cos", "atan", "asin", "acos"]: a = i[1] if str(a) in lv: l3.append((oper, 'var[{}]'.format(lv.index(str(a))))) elif str(a) in lp: l3.append((oper, 'par[{}]'.format(lp.index(str(a))))) else: l3.append((oper, 'link[{}]'.format(l0.index(str(a))))) else: a=i[1] b=i[2] sa = str(a) sb = str(b) consta=False constb=False if sa in lv: aa = 'var[{}]'.format(lv.index(sa)) elif sa in l0: aa = 'link[{}]'.format(l0.index(sa)) elif sa in lp: aa = 'par[{}]'.format(lp.index(sa)) else: consta=True aa = RR(a).str(truncate=False) if sb in lv: bb = 'var[{}]'.format(lv.index(sb)) elif sb in l0: bb = 'link[{}]'.format(l0.index(sb)) elif sb in lp: bb = 'par[{}]'.format(lp.index(sb)) else: constb=True bb = RR(b).str(truncate=False) if consta: oper += '_c' if not oper=='div': bb, aa = aa,bb elif constb: oper += '_c' l3.append((oper, aa, bb)) n = len(var) code = [] l0 = lv + l0 indices = [l0.index(str(i(*var)))+n for i in f] for i in range (1, n): aux = indices[i-1]-n if aux < n: code.append('mpfrts_var_t(itd, var[{}], var[{}], i);'.format(aux, i)) else: code.append('mpfrts_var_t(itd, link[{}], var[{}], i);'.format(aux-n, i)) for i in range(len(l3)): el = l3[i] string = "mpfrts_" if el[0] == 'add': string += 'add_t(itd, ' + el[1] + ', ' + el[2] + ', link[{}], i);'.format(i) elif el[0] == 'add_c': string += 'add_t_c(itd, "' + el[2] + '", ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'mul': string += 'mul_t(itd, ' + el[1] + ', ' + el[2] + ', link[{}], i);'.format(i) elif el[0] == 'mul_c': string += 'mul_t_c(itd, "' + el[2] + '", ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'pow_c': string += 'pow_t_c(itd, ' + el[1] + ', "' + el[2] + '", link[{}], i);'.format(i) elif el[0] == 'div': string += 'div_t(itd, ' + el[2] + ', ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'div_c': string += 'div_t_cv(itd, "' + el[2] + '", ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'log': string += 'log_t(itd, ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'exp': string += 'exp_t(itd, ' + el[1] + ', link[{}], i);'.format(i) elif el[0] == 'sin': string += 'sin_t(itd, ' + el[1] + ', link[{}], link[{}], i);'.format(i+1, i) elif el[0] == 'cos': string += 'cos_t(itd, ' + el[1] + ', link[{}], link[{}], i);'.format(i-1, i) elif el[0] == 'atan': indarg = l0.index(str(1+l2[i][1]**2))-n string += 'atan_t(itd, ' + el[1] + ', link[{}], link[{}], i);'.format(indarg, i) elif el[0] == 'asin': indarg = l0.index(str(sqrt(1-l2[i][1]**2)))-n string += 'asin_t(itd, ' + el[1] + ', link[{}], link[{}], i);'.format(indarg, i) elif el[0] == 'acos': indarg = l0.index(str(-sqrt(1-l2[i][1]**2)))-n string += 'acos_t(itd, ' + el[1] + ', link[{}], link[{}], i);'.format(indarg, i) code.append(string) VAR = n-1 PAR = len(parameters) TT = len(code)+1-VAR outfile = open(integrator, 'a') auxstring = """ /**************************************************************************** This file has been created by Sage for its use with TIDES *****************************************************************************/ #include "mp_tides.h" long function_iteration(iteration_data *itd, mpfr_t t, mpfr_t v[], mpfr_t p[], int ORDER, mpfr_t *cvfd) { int i; int NCONST = 0; mpfr_t ct[0]; """ outfile.write(auxstring) outfile.write("\n\tstatic int VARIABLES = {};\n".format(VAR)) outfile.write("\tstatic int PARAMETERS = {};\n".format(PAR)) outfile.write("\tstatic int LINKS = {};\n".format(TT)) outfile.write('\tstatic int FUNCTIONS = 0;\n') outfile.write('\tstatic int POS_FUNCTIONS[1] = {0};\n') outfile.write('\n\tinitialize_mp_case();\n') outfile.write('\n\tfor(i=0; i<=ORDER; i++) {\n') for i in code: outfile.write('\t\t'+i+'\n') auxstring = """ } write_mp_solution(); clear_vpl(); clear_cts(); return NUM_COLUMNS; } """ outfile.write(auxstring) outfile.close() npar = len(parameter_values) outfile = open(driver, 'a') auxstring = """ /**************************************************************************** Driver file of the mp_tides program This file has been created automatically by Sage *****************************************************************************/ #include "mpfr.h" #include "mp_tides.h" long function_iteration(iteration_data *itd, mpfr_t t, mpfr_t v[], mpfr_t p[], int ORDER, mpfr_t *cvfd); int main() { int i; int nfun = 0; """ outfile.write(auxstring) outfile.write('\tset_precision_digits({});'.format(dig)) outfile.write('\n\tint npar = {};\n'.format(npar)) outfile.write('\tmpfr_t p[npar];\n') outfile.write('\tfor(i=0; i<npar; i++) mpfr_init2(p[i], TIDES_PREC);\n') for i in range(npar): outfile.write('\tmpfr_set_str(p[{}], "{}", 10, TIDES_RND);\n'.format(i,RR(parameter_values[i]).str(truncate=False))) outfile.write('\tint nvar = {};\n\tmpfr_t v[nvar];\n'.format(VAR)) outfile.write('\tfor(i=0; i<nvar; i++) mpfr_init2(v[i], TIDES_PREC);\n') for i in range(len(ics)): outfile.write('\tmpfr_set_str(v[{}], "{}", 10, TIDES_RND);\n'.format(i,RR(ics[i]).str(truncate=False))) outfile.write('\tmpfr_t tolrel, tolabs;\n') outfile.write('\tmpfr_init2(tolrel, TIDES_PREC); \n') outfile.write('\tmpfr_init2(tolabs, TIDES_PREC); \n') outfile.write('\tmpfr_set_str(tolrel, "{}", 10, TIDES_RND);\n'.format(RR(tolrel).str(truncate=False))) outfile.write('\tmpfr_set_str(tolabs, "{}", 10, TIDES_RND);\n'.format(RR(tolabs).str(truncate=False))) outfile.write('\tmpfr_t tini, dt; \n') outfile.write('\tmpfr_init2(tini, TIDES_PREC); \n') outfile.write('\tmpfr_init2(dt, TIDES_PREC); \n') outfile.write('\tmpfr_set_str(tini, "{}", 10, TIDES_RND);;\n'.format(RR(initial).str(truncate=False))) outfile.write('\tmpfr_set_str(dt, "{}", 10, TIDES_RND);\n'.format(RR(delta).str(truncate=False))) outfile.write('\tint nipt = {};\n'.format(floor((final-initial)/delta))) outfile.write('\tFILE* fd = fopen("' + output + '", "w");\n') outfile.write('\tmp_tides_delta(function_iteration, NULL, nvar, npar, nfun, v, p, tini, dt, nipt, tolrel, tolabs, NULL, fd);\n') outfile.write('\tfclose(fd);\n\treturn 0;\n}') outfile.close()
def floor(self): result = floor(self.val()) result <= self < result + 1 return result
def e_phipsi(phi, psi, k, t=1, prec=5, mat=Matrix([[1, 0], [0, 1]]), base_ring=None): r""" Computes the Eisenstein series attached to the characters psi, phi as defined on p129 of Diamond--Shurman hit by mat \in \SL_2(\Z) INPUT: - psi, a primitive Dirichlet character - phi, a primitive Dirichlet character - k, int -- the weight - t, int -- the shift - prec, the desired absolute precision, can be fractional. The expansion will be up to O(q_w^(floor(w*prec))), where w is the width of the cusp. - mat, a matrix - typically taking $i\infty$ to some other cusp - base_ring, a ring - the ring in which the modular forms are defined OUTPUT: - an instance of QExpansion """ chi2 = phi chi1 = psi try: assert (QQ(chi1(-1)) * QQ(chi2(-1)) == (-1)**k) except AssertionError: print("Parity of characters must match parity of weight") return None N1 = chi1.level() N2 = chi2.level() N = t * N1 * N2 mat2, Tn = find_correct_matrix(mat, N) #By construction gamma = mat2 * Tn * mat**(-1) is in Gamma0(N) so if E is our Eisenstein series we can evaluate E|mat = chi(gamma) * E|mat2*Tn. #Since E|mat2 has a Fourier expansion in qN, the matrix Tn acts as a a twist. The value c_gamma = chi(gamma) is calculated below. #The point of swapping mat with mat2 is that mat2 satisfies C|N, C>0, (A,N)=1 and N|B and our formulas for the coefficients require this condition. A, B, C, D = mat2.list() gamma = mat2 * Tn * mat**(-1) if base_ring == None: Nbig = lcm(N, euler_phi(N1 * N2)) base_ring = CyclotomicField(Nbig, 'zeta' + str(Nbig)) zetaNbig = base_ring.gen() zetaN = zetaNbig**(Nbig / N) else: zetaN = base_ring.zeta(N) g = gcd(t, C) g1 = gcd(N1 * g, C) g2 = gcd(N2 * g, C) #Resulting Eisenstein series will have Fourier expansion in q_N**(g1g2)=q_(N/gcd(N,g1g2))**(g1g2/gcd(N,g1g2)) Q = PowerSeriesRing(base_ring, 'q' + str(N / gcd(N, g1 * g2))) qN = Q.gen() zeta_Cg = zetaN**(N / (C / g)) zeta_tmp = zeta_Cg**(inverse_mod(-A * ZZ(t / g), C / g)) #Calculating a few values that will be used repeatedly chi1bar_vals = [base_ring(chi1.bar()(i)) for i in range(N1)] cp_list1 = [i for i in range(N1) if gcd(i, N1) == 1] chi2bar_vals = [base_ring(chi2.bar()(i)) for i in range(N2)] cp_list2 = [i for i in range(N2) if gcd(i, N2) == 1] #Computation of the Fourier coefficients ser = O(qN**floor(prec * N / gcd(N, g1 * g2))) for n in range(1, ceil(prec * N / QQ(g1 * g2)) + 1): f = 0 for m in divisors(n) + list(map(lambda x: -x, divisors(n))): a = 0 for r1 in cp_list1: b = 0 if ((C / g1) * r1 - QQ(n) / QQ(m)) % ((N1 * g) / g1) == 0: for r2 in cp_list2: if ((C / g2) * r2 - m) % ((N2 * g) / g2) == 0: b += chi2bar_vals[r2] * zeta_tmp**( (n / m - (C / g1) * r1) / ((N1 * g) / g1) * (m - (C / g2) * r2) / ((N2 * g) / g2)) a += chi1bar_vals[r1] * b a *= sign(m) * m**(k - 1) f += a f *= zetaN**(inverse_mod(A, N) * (g1 * g2) / C * n) #The additional factor zetaN**(n*Tn[0][1]) comes from the twist by Tn ser += zetaN**(n * g1 * g2 * Tn[0][1]) * f * qN**(n * ( (g1 * g2) / gcd(N, g1 * g2))) #zk(chi1, chi2, c) gauss1 = base_ring(gauss_sum_corr(chi1.bar())) gauss2 = base_ring(gauss_sum_corr(chi2.bar())) zk = 2 * (N2 * t / QQ(g2))**(k - 1) * (t / g) * gauss1 * gauss2 #The following is a temporary fix for a bug in sage if base_ring == CC: G = DirichletGroup(N1 * N2, CC) G[0] #Otherwise chi1.bar().extend(N1*N2).base_extend(CC) or chi2.bar().extend(N1*N2).base_extend(CC) will produce an error #Constant term #c_gamma comes from replacing mat with mat2. c_gamma = chi1bar_vals[gamma[1][1] % N1] * chi2bar_vals[gamma[1][1] % N2] if N1.divides(C) and ZZ(C / N1).divides(t) and gcd(t / (C / N1), N1) == 1: ser += (-1)**(k - 1) * gauss2 / QQ( N2 * (g2 / g)**(k - 1)) * chi1bar_vals[(-A * t / g) % N1] * Sk( chi1.bar().extend(N1 * N2).base_extend(base_ring) * chi2.extend(N1 * N2).base_extend(base_ring), k) elif k == 1 and N2.divides(C) and ZZ(C / N2).divides(t) and gcd( t / (C / N2), N2) == 1: ser += gauss1 / QQ(N1) * chi2bar_vals[(-A * t / g) % N2] * Sk( chi1.extend(N1 * N2).base_extend(base_ring) * chi2.bar().extend(N1 * N2).base_extend(base_ring), k) return QExpansion( N, k, 2 / zk * c_gamma * ser + O(qN**floor(prec * N / gcd(N, g1 * g2))), N / gcd(N, g1 * g2))
def _suitable_parameters_given_tau(tau, C = None, n_k = None): r""" Return quite good multiplicity and list size parameters for the code parameters and the decoding radius. These parameters are not guaranteed to be the best ones possible for the provided ``tau``, but arise from easily-evaluated closed expressions and are very good approximations of the best ones. See [Nie2013]_ pages 53-54, proposition 3.11 for details. INPUT: - ``tau`` -- an integer, number of errors one wants the Guruswami-Sudan algorithm to correct - ``C`` -- (default: ``None``) a :class:`GeneralizedReedSolomonCode` - ``n_k`` -- (default: ``None``) a pair of integers, respectively the length and the dimension of the :class:`GeneralizedReedSolomonCode` OUTPUT: - ``(s, l)`` -- a pair of integers, where: - ``s`` is the multiplicity parameter, and - ``l`` is the list size parameter. .. NOTE:: One has to provide either ``C`` or ``(n, k)``. If neither or both are given, an exception will be raised. EXAMPLES: The following is an example where the parameters are optimal:: sage: tau = 98 sage: n, k = 250, 70 sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) (2, 3) sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) (2, 3) This is an example where they are not:: sage: tau = 97 sage: n, k = 250, 70 sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, n_k = (n, k)) (2, 3) sage: codes.decoders.GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k = (n, k)) (1, 2) We can provide a GRS code instead of `n` and `k` directly:: sage: C = codes.GeneralizedReedSolomonCode(GF(251).list()[:250], 70) sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(tau, C = C) (2, 3) Another one with a bigger ``tau``:: sage: codes.decoders.GRSGuruswamiSudanDecoder._suitable_parameters_given_tau(118, C = C) (47, 89) """ n,k = n_k_params(C, n_k) w = k - 1 atau = n - tau smin = tau * w / (atau ** 2 - n * w) s = floor(1 + smin) D = (s - smin) * (atau ** 2 - n * w) * s + (w**2) /4 l = floor(atau / w * s + 0.5 - sqrt(D)/w) return (s, l)
def random_dist(p,k,M): """Returns a random distribution with prime p, weight k, and M moments""" moments=vector([ZZ(floor(random()*(p**M))) for i in range(1,M+1)]) return dist(p,k,moments)
def kneading_sequence(theta): r""" Determines the kneading sequence for an angle theta in RR/ZZ which is periodic under doubling. We use the definition for the kneading sequence given in Definition 3.2 of [LS1994]_. INPUT: - ``theta`` -- a rational number with odd denominator OUTPUT: a string representing the kneading sequence of theta in RR/ZZ REFERENCES: [LS1994]_ EXAMPLES:: sage: kneading_sequence(0) '*' :: sage: kneading_sequence(1/3) '1*' Since 1/3 and 7/3 are the same in RR/ZZ, they have the same kneading sequence:: sage: kneading_sequence(7/3) '1*' We can also use (finite) decimal inputs, as long as the denominator in reduced form is odd:: sage: kneading_sequence(1.2) '110*' Since rationals with even denominator are not periodic under doubling, we have not implemented kneading sequences for such rationals:: sage: kneading_sequence(1/4) Traceback (most recent call last): ... ValueError: input must be a rational number with odd denominator """ if theta not in QQ: raise TypeError('input must be a rational number with odd denominator') elif QQ(theta).valuation(2) < 0: raise ValueError( 'input must be a rational number with odd denominator') else: theta = QQ(theta) theta = theta - floor(theta) KS = [] not_done = True left = theta / 2 right = (theta + 1) / 2 y = theta while not_done: if ((y < left) or (y > right)): KS.append('0') elif ((y > left) and (y < right)): KS.append('1') else: not_done = False y = 2 * y - floor(2 * y) KS_str = ''.join(KS) + '*' return KS_str
def e(self, i, power=1, to_string_end=False, length_only=False): r""" Returns the `i`-th crystal raising operator on ``self``. INPUT: - ``i`` -- element of the index set of the underlying root system - ``power`` -- positive integer; specifies the power of the raising operator to be applied (default: 1) - ``to_string_end`` -- boolean; if set to True, returns the dominant end of the `i`-string of ``self``. (default: False) - ``length_only`` -- boolean; if set to True, returns the distance to the dominant end of the `i`-string of ``self``. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: c = C[2]; c (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) sage: c.e(1) sage: c.e(2) (-Lambda[1] + 2*Lambda[2],) sage: c.e(2,to_string_end=True) (-Lambda[1] + 2*Lambda[2],) sage: c.e(1,to_string_end=True) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) sage: c.e(1,length_only=True) 0 """ assert i in self.index_set() data = self._string_data(i) # compute the minimum i-height M on the path if len(data) == 0: M = 0 else: M = data[-1][1] max_raisings = floor(-M) if length_only: return max_raisings # set the power of e_i to apply if to_string_end: p = max_raisings else: p = power if p > max_raisings: return None # copy the vector sequence into a working vector sequence ws #!!! ws only needs to be the actual vector sequence, not some #!!! fancy crystal graph element ws = self.parent()(self.value) ix = len(data)-1 while ix >= 0 and data[ix][1] < M + p: # get the index of the current step to be processed j = data[ix][0] # find the i-height where the current step might need to be split if ix == 0: prev_ht = M + p else: prev_ht = min(data[ix-1][1],M+p) # if necessary split the step. Then reflect the wet part. if data[ix][1] - data[ix][2] > prev_ht: ws = ws.split_step(j,1-(prev_ht-data[ix][1])/(-data[ix][2])) ws = ws.reflect_step(j+1,i) else: ws = ws.reflect_step(j,i) ix = ix - 1 #!!! at this point we should return the fancy crystal graph element #!!! corresponding to the humble vector sequence ws return self.parent()(ws.compress())
def best_simultaneous_convergents_upto(v, Q, start=1, verbose=False): r""" Return a list of all best simultaneous diophantine approximations p,q of vector ``v`` at distance ``|qv-p|<=1/Q`` such that `1<=q<Q^d`. INPUT: - ``v`` -- list of real numbers - ``Q`` -- real number, Q>1 - ``start`` -- integer (default: ``1``), starting value to check - ``verbose`` -- boolean (default: ``False``) EXAMPLES:: sage: from slabbe.diophantine_approx import best_simultaneous_convergents_upto sage: best_simultaneous_convergents_upto([e,pi], 2) [((3, 3, 1), 3.549646778303845)] sage: best_simultaneous_convergents_upto([e,pi], 4) [((19, 22, 7), 35.74901433260719)] sage: best_simultaneous_convergents_upto([e,pi], 36, start=4**2) [((1843, 2130, 678), 203.23944293852406)] sage: best_simultaneous_convergents_upto([e,pi], 204, start=36**2) [((51892, 59973, 19090), 266.16775098010373), ((113018, 130618, 41577), 279.18598227531174)] sage: best_simultaneous_convergents_upto([e,pi], 280, start=204**2) [((114861, 132748, 42255), 412.7859137824949), ((166753, 192721, 61345), 749.3634909055199)] sage: best_simultaneous_convergents_upto([e,pi], 750, start=280**2) [((446524, 516060, 164267), 896.4734658499202), ((1174662, 1357589, 432134), 2935.314937919726)] sage: best_simultaneous_convergents_upto([e,pi], 2936, start=750**2) [((3970510, 4588827, 1460669), 3654.2989332956854), ((21640489, 25010505, 7961091), 6257.014011585661)] TESTS:: sage: best_simultaneous_convergents_upto([e,pi], 102300.1, start=10^9) # not tested (1 min) [((8457919940, 9775049397, 3111494861), 194686.19839453633)] """ from slabbe.diophantine_approx_pyx import good_simultaneous_convergents_upto from sage.parallel.decorate import parallel from sage.parallel.ncpus import ncpus step = ncpus() @parallel def F(shift): return good_simultaneous_convergents_upto(v, Q, start + shift, step=step) shifts = range(step) goods = [] for (arg, kwds), output in F(shifts): if output == 'NO DATA': print( "problem with v={}, Q={}, start={}, shift={}" " because output={}".format(v, Q, start, arg[0], output)) else: goods.extend(output) if not goods: raise ValueError( "Did not find an approximation p,q to v={} s.t. |p-qv|<=1/Q" " where Q={}".format(v, Q)) goods.sort() bests = [] best_error_inv = 0 # keep only the best ones for q in goods: q_v = [q * a for a in v] frac_q_v = [a - floor(a) for a in q_v] error = max((a if a < .5 else 1 - a) for a in frac_q_v) error_inv = 1. / error.n(digits=50) if verbose: print "q={}, error_inv={}, best_error_inv={}".format( q, error_inv, best_error_inv) if error_inv > best_error_inv: p = [round(a) for a in q_v] p.append(q) bests.append((tuple(p), error_inv)) best_error_inv = error_inv return bests