def complex2str(g, digits=10): real = round(g.real(), digits) imag = round(g.imag(), digits) if imag == 0.: return str(real) elif real == 0.: return str(imag) + 'i' else: return str(real) + '+' + str(imag) + 'i'
def _round_(self, var): r""" Round a number based on the epsilon. INPUT: - ``var`` -- the variable to be rounded EXAMPLES:: sage: from sage_numerical_interactive_mip.clean_dictionary \ import LPCleanDictionary sage: p = MixedIntegerLinearProgram(names=['m'], solver="GLPK") sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: lp, basis = p.interactive_lp_problem() sage: d = lp.dictionary(*basis) sage: clean = LPCleanDictionary(d, epsilon=1e-4) sage: clean._round_(0.1) 0.100000000000000 sage: clean._round_(0.00001) 0 """ nearest_int = ZZ(round(var)) if abs(var - nearest_int) <= self._epsilon: var = nearest_int return var
def discrete_curve(nb_equipes, max_points=100, K=1, R=2, base=2, verbose=False): r""" INPUT: - ``nb_equipes`` -- integer - ``max_points`` -- integer - ``K`` -- the value at ``p = nb_equipes`` - ``R`` -- real (default: ``2``), curve parameter - ``base`` -- 2 - ``verbose`` - bool EXEMPLES:: sage: from slabbe.ranking_scale import discrete_curve sage: A = discrete_curve(64, 100,verbose=True) First difference sequence is [1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3, 4, 4, 4] :: sage: A = discrete_curve(64, 100) sage: B = discrete_curve(32, 50) sage: C = discrete_curve(16, 25) :: sage: A [100, 96, 92, 88, 85, 82, 79, 77, 74, 71, 69, 67, 64, 62, 60, 58, 56, 54, 52, 50, 49, 47, 45, 44, 42, 41, 39, 38, 36, 35, 33, 32, 31, 29, 28, 27, 26, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 4, 3, 2, 2, 1] sage: B [50, 46, 43, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1] sage: C [25, 22, 19, 17, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1] :: sage: A = discrete_curve(64+2, 100) #Movember, Bye Bye, Cdf, MA sage: B = discrete_curve(32+2, 70) # la flotte sage: C = discrete_curve(16+2, 40) # october fest, funenuf, la viree """ from sage.misc.functional import round from sage.rings.integer_ring import ZZ from sage.combinat.words.word import Word fn_normalise = curve(nb_equipes, max_points, K=K, R=R, base=base) L = [ZZ(round(fn_normalise(p=i))) for i in range(1, nb_equipes + 1)] if verbose: print "First difference sequence is" print list(Word(L).reversal().finite_differences()) return L
def discrete_curve_2(nb_equipes, max_points=100): r""" """ from sage.misc.functional import round from sage.functions.log import log from sage.rings.integer_ring import ZZ f = lambda p: (max_points - 1) * (1 - log(p) / log(nb_equipes)) + 1 L = [ZZ(round(f(p=i))) for i in range(1, nb_equipes + 1)] return L
def discrete_curve_2(nb_equipes, max_points=100): r""" """ from sage.misc.functional import round from sage.functions.log import log from sage.rings.integer_ring import ZZ f = lambda p:(max_points-1)*(1-log(p)/log(nb_equipes))+1 L = [ZZ(round(f(p=i))) for i in range(1,nb_equipes+1)] return L
def discrete_curve(nb_equipes, max_points=100, K=1, R=2, base=2, verbose=False): r""" INPUT: - ``nb_equipes`` -- integer - ``max_points`` -- integer - ``K`` -- the value at ``p = nb_equipes`` - ``R`` -- real (default: ``2``), curve parameter - ``base`` -- 2 - ``verbose`` - bool EXEMPLES:: sage: from slabbe.ranking_scale import discrete_curve sage: A = discrete_curve(64, 100,verbose=True) First difference sequence is [1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3, 4, 4, 4] :: sage: A = discrete_curve(64, 100) sage: B = discrete_curve(32, 50) sage: C = discrete_curve(16, 25) :: sage: A [100, 96, 92, 88, 85, 82, 79, 77, 74, 71, 69, 67, 64, 62, 60, 58, 56, 54, 52, 50, 49, 47, 45, 44, 42, 41, 39, 38, 36, 35, 33, 32, 31, 29, 28, 27, 26, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 4, 3, 2, 2, 1] sage: B [50, 46, 43, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1] sage: C [25, 22, 19, 17, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1] :: sage: A = discrete_curve(64+2, 100) #Movember, Bye Bye, Cdf, MA sage: B = discrete_curve(32+2, 70) # la flotte sage: C = discrete_curve(16+2, 40) # october fest, funenuf, la viree """ from sage.misc.functional import round from sage.rings.integer_ring import ZZ from sage.combinat.words.word import Word fn_normalise = curve(nb_equipes, max_points, K=K, R=R, base=base) L = [ZZ(round(fn_normalise(p=i))) for i in range(1,nb_equipes+1)] if verbose: print("First difference sequence is") print(list(Word(L).reversal().finite_differences())) return L
def round_to_half_int(num, fraction=2): """ Rounds input `num` to the nearest half-integer. The optional kwarg `fraction` is used to round to the nearest `fraction`-part of an integer. Examples: >>> round_to_half_int(1.1) 1 >>> round_to_half_int(-0.9) -1 >>> round_to_half_int(0.5) 1/2 """ return round(num * 1.0 * fraction) / fraction
def RankingScale_CQU4_2011(): r""" EXEMPLES:: sage: from slabbe.ranking_scale import RankingScale_CQU4_2011 sage: R = RankingScale_CQU4_2011() sage: R.table() Position Grand Chelem Mars Attaque La Flotte Petit Chelem 1 1000 1000 800 400 2 938 938 728 355 3 884 884 668 317 4 835 835 614 285 5 791 791 566 256 6 750 750 522 230 7 711 711 482 206 8 675 675 444 184 9 641 641 409 164 10 609 609 377 146 ... 95 0 11 0 0 96 0 10 0 0 97 0 9 0 0 98 0 8 0 0 99 0 7 0 0 100 0 6 0 0 101 0 4 0 0 102 0 3 0 0 103 0 2 0 0 104 0 1 0 0 """ from sage.rings.integer_ring import ZZ serieA = [0] + discrete_curve(50, 1000, K=1, R=sqrt(2), base=e) #Movember, Bye Bye, Cdf, MA la_flotte = [0] + discrete_curve(32, 800, K=1, R=sqrt(2), base=e) # la flotte serieB = [0] + discrete_curve(24, 400, K=1, R=sqrt(2), base=e) # october fest, funenuf, la viree nb_ma = 104 pivot_x = 40 pivot_y = serieA[pivot_x] slope = (1 - pivot_y) / (nb_ma - pivot_x) L = [pivot_y + slope * (p - pivot_x) for p in range(pivot_x, nb_ma + 1)] L = [ZZ(round(_)) for _ in L] mars_attaque = serieA[:pivot_x] + L scales = serieA, mars_attaque, la_flotte, serieB names = ["Grand Chelem", "Mars Attaque", "La Flotte", "Petit Chelem"] return RankingScale(names, scales)
def RankingScale_CQU4_2011(): r""" EXEMPLES:: sage: from slabbe.ranking_scale import RankingScale_CQU4_2011 sage: R = RankingScale_CQU4_2011() sage: R.table() Position Grand Chelem Mars Attaque La Flotte Petit Chelem 1 1000 1000 800 400 2 938 938 728 355 3 884 884 668 317 4 835 835 614 285 5 791 791 566 256 6 750 750 522 230 7 711 711 482 206 8 675 675 444 184 9 641 641 409 164 10 609 609 377 146 ... 95 0 11 0 0 96 0 10 0 0 97 0 9 0 0 98 0 8 0 0 99 0 7 0 0 100 0 6 0 0 101 0 4 0 0 102 0 3 0 0 103 0 2 0 0 104 0 1 0 0 """ from sage.rings.integer_ring import ZZ serieA = [0] + discrete_curve(50, 1000, K=1, R=sqrt(2), base=e) #Movember, Bye Bye, Cdf, MA la_flotte = [0] + discrete_curve(32, 800, K=1, R=sqrt(2), base=e) # la flotte serieB = [0] + discrete_curve(24, 400, K=1, R=sqrt(2), base=e) # october fest, funenuf, la viree nb_ma = 104 pivot_x = 40 pivot_y = serieA[pivot_x] slope = (1-pivot_y) / (nb_ma-pivot_x) L = [pivot_y + slope * (p-pivot_x) for p in range(pivot_x, nb_ma+1)] L = [ZZ(round(_)) for _ in L] mars_attaque = serieA[:pivot_x] + L scales = serieA, mars_attaque, la_flotte, serieB names = ["Grand Chelem", "Mars Attaque", "La Flotte", "Petit Chelem"] return RankingScale(names, scales)
def random_interior_point_simplex(self, integer=False): r""" Return a random interior point of a simplex. This method was based on the code ``P.center()`` of sage. INPUT: - ``integer`` -- bool, whether the output must be with integer coordinates EXEMPLES:: sage: from slabbe.combinat import random_interior_point_simplex sage: P = 10 * polytopes.simplex(3) sage: random_interior_point_simplex(P) # random (2.8787864522849462, 5.302173919578364, 1.7059355910006113, 0.11310403713607808) sage: a = random_interior_point_simplex(P, integer=True) sage: a # random (0, 7, 1, 2) sage: a in P True """ from sage.modules.free_module_element import vector from sage.misc.functional import round from sage.functions.generalized import sign assert self.is_simplex(), "input is not a simplex" d = self.n_vertices() R = random_simplex_point(d) vertex_sum = vector(self.base_ring(), [0]*self.ambient_dim()) for v,r in zip(self.vertex_generator(), R): vertex_sum += r*v.vector() if integer: v = vector(map(round, vertex_sum)) r = round(sum(vertex_sum) - sum(v)) s = sign(r) for _ in range(abs(r)): v[randrange(len(v))] += s v.set_immutable() return v else: vertex_sum.set_immutable() return vertex_sum
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 random_interior_point_simplex(self, integer=False): r""" Return a random interior point of a simplex. This method was based on the code ``P.center()`` of sage. INPUT: - ``integer`` -- bool, whether the output must be with integer coordinates EXEMPLES:: sage: from slabbe.combinat import random_interior_point_simplex sage: P = 10 * polytopes.simplex(3) sage: random_interior_point_simplex(P) # random (2.8787864522849462, 5.302173919578364, 1.7059355910006113, 0.11310403713607808) sage: a = random_interior_point_simplex(P, integer=True) sage: a # random (0, 7, 1, 2) sage: a in P True """ from sage.modules.free_module_element import vector from sage.misc.functional import round from sage.functions.generalized import sign assert self.is_simplex(), "input is not a simplex" d = self.n_vertices() R = random_simplex_point(d) vertex_sum = vector(self.base_ring(), [0] * self.ambient_dim()) for v, r in zip(self.vertex_generator(), R): vertex_sum += r * v.vector() if integer: v = vector(map(round, vertex_sum)) r = round(sum(vertex_sum) - sum(v)) s = sign(r) for _ in range(abs(r)): v[randrange(len(v))] += s v.set_immutable() return v else: vertex_sum.set_immutable() return vertex_sum
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 __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 __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 diophantine_approx(alpha, Q): r""" Return a diophantine approximation p/q to real number alpha following Dirichlet Theorem (1842). .. NOTES:: This function is very slow compared to using continued fractions. It tests all of the possible values of q. INPUT: - `alpha` -- real number - `Q` -- real number > 1 OUTPUT: - a tuple of integers (p,q) such that `|\alpha q-p|<1/Q`. EXAMPLES:: sage: from sage_sample import diophantine_approx sage: diophantine_approx(pi, 10) (22, 7) sage: diophantine_approx(pi, 100) (22, 7) sage: diophantine_approx(pi, 200) (355, 113) sage: diophantine_approx(pi, 1000) (355, 113) sage: diophantine_approx(pi, 35000) # not tested, code is very slow """ for q in range(1, Q): if frac(alpha * q) <= 1. / Q or 1 - 1. / Q <= frac(alpha * q): p = round(alpha * q) return (p, q)
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