Ejemplo n.º 1
0
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'
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
Archivo: lwe.py Proyecto: sagemath/sage
    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)
Ejemplo n.º 15
0
Archivo: lwe.py Proyecto: sagemath/sage
    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)
Ejemplo n.º 17
0
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