Exemplo n.º 1
0
    def random_element(self):
        r"""
        Return a random parking function of size `n`.

        The algorithm uses a circular parking space with `n+1`
        spots. Then all `n` cars can park and there remains one empty
        spot. Spots are then renumbered so that the empty spot is `0`.

        The probability distribution is uniform on the set of
        `(n+1)^{n-1}` parking functions of size `n`.

        EXAMPLES::

            sage: pf = ParkingFunctions(8)
            sage: a = pf.random_element(); a  # random
            [5, 7, 2, 4, 2, 5, 1, 3]
            sage: a in pf
            True
        """
        n = self.n
        Zm = Zmod(n + 1)
        fun = [Zm(randint(0, n)) for i in range(n)]
        free = [Zm(j) for j in range(n + 1)]
        for car in fun:
            position = car
            while not (position in free):
                position += Zm.one()
            free.remove(position)
        return ParkingFunction([(i - free[0]).lift() for i in fun])
Exemplo n.º 2
0
    def random_element(self):
        r"""
        Return a random parking function of size `n`.

        The algorithm uses a circular parking space with `n+1`
        spots. Then all `n` cars can park and there remains one empty
        spot. Spots are then renumbered so that the empty spot is `0`.

        The probability distribution is uniform on the set of
        `(n+1)^{n-1}` parking functions of size `n`.

        EXAMPLES::

            sage: pf = ParkingFunctions(8)
            sage: a = pf.random_element(); a  # random
            [5, 7, 2, 4, 2, 5, 1, 3]
            sage: a in pf
            True
        """
        n = self.n
        Zm = Zmod(n + 1)
        fun = [Zm(randint(0, n)) for i in range(n)]
        free = [Zm(j) for j in range(n + 1)]
        for car in fun:
            position = car
            while not(position in free):
                position += Zm.one()
            free.remove(position)
        return ParkingFunction([(i - free[0]).lift() for i in fun])
Exemplo n.º 3
0
def accept(p, n, r, l, e, s):
    '''
    This function is passed down to `sieve`. It accepts only if:

    (1)  the order t of p in ℤ/l^e is a multiple of s;
    (2)  gcd(nlcm, t / gcd(t, ngcd)) = 1.
    (3)  gcd(s, φ(m)/s) = 1.
    (4)  gcd(t/s, p) = 1.

    These three conditions imply the conditions (1)-(3) above assuming
    l is prime.
    '''
    # Degrees of the ambient fields
    ngcd, nlcm = n

    # Generic case
    if l != 2 and p != l:
        m = l**e
        phi = (l - 1) * l**(e - 1)
        ord = Zmod(m)(p).multiplicative_order()
        return (ord % s.expand() == 0
                and (phi // s.expand()).gcd(s.expand()) == 1
                and (ord // (ord.gcd(ngcd))).gcd(nlcm) == 1
                and (ord // s.expand()).gcd(p) == 1)

    # Special treatement for ℤ/2^x
    elif l == 2:
        return NotImplementedError

    else:
        return False
Exemplo n.º 4
0
def accept(p, n, r, l, e, s):
    '''
    This function is passed down to `sieve`. It accepts only if:

    (1)  the order t of p in ℤ/l^e is a multiple of s;
    (2)  gcd(nlcm, t / gcd(t, ngcd)) = 1.
    (3)  gcd(s, φ(m)/s) = 1.
    (4)  gcd(t/s, p) = 1.

    These three conditions imply the conditions (1)-(3) above assuming
    l is prime.
    '''
    # Degrees of the ambient fields
    ngcd, nlcm = n

    # Generic case
    if l != 2 and p != l:
        m = l**e
        phi = (l - 1) * l**(e-1)
        ord = Zmod(m)(p).multiplicative_order()
        return (ord % s.expand() == 0 and
                (phi // s.expand()).gcd(s.expand()) == 1 and
                (ord // (ord.gcd(ngcd))).gcd(nlcm) == 1 and
                (ord // s.expand()).gcd(p) == 1)

    # Special treatement for ℤ/2^x
    elif l == 2:
        return NotImplementedError

    else:
        return False
Exemplo n.º 5
0
def accept_noglue(p, n, r, l, e, s):
    '''
    This function is passed down to `sieve`. It accepts only if:

    (1)  the order of p in ℤ/l^e is a multiple of s;
    (3') λ(l^e) / s is coprime to s (λ is the Carmichael function).

    These two conditions imply the conditions (1)-(3) above assuming
    l is prime.
    No gluing can be performed on accepted values if condition (2) above
    has to be preserved.
    '''
    # Generic case
    if l != 2 and p != l:
        m = l**e
        ord = (l - 1) * l**(e - 1)
        return ((ord // s.expand()).gcd(s.expand()) == 1 and  # (3')
                all(Zmod(m)(p)**(ord // ell) != 1 for (ell, _) in s))  # (1)

    # Special treatement for ℤ/2^x
    elif l == 2:
        return ((e == 2 and p % 4 == 3)
                or (p != 2 and e - s[0][1] == 2 and  # (3')
                    Zmod(2**e)(p)**(s.expand() // 2)))  # (1)

    else:
        return False
Exemplo n.º 6
0
    def image_mod_n(self):
        r"""
        Return the image of this group in `SL(2, \ZZ / N\ZZ)`.

        EXAMPLE::

            sage: Gamma0(3).image_mod_n()
            Matrix group over Ring of integers modulo 3 with 2 generators:
             [[[2, 0], [0, 2]], [[1, 1], [0, 1]]]

        TEST::

            sage: for n in [2..20]:
            ...     for g in Gamma0(n).gamma_h_subgroups():
            ...       G = g.image_mod_n()
            ...       assert G.order() == Gamma(n).index() / g.index()
        """
        N = self.level()
        if N == 1:
            raise NotImplementedError, "Matrix groups over ring of integers modulo 1 not implemented"
        gens = [
            matrix(Zmod(N), 2, 2, [x, 0, 0, Zmod(N)(1) / x])
            for x in self._generators_for_H()
        ]
        gens += [matrix(Zmod(N), 2, [1, 1, 0, 1])]
        return MatrixGroup(gens)
Exemplo n.º 7
0
def _make_integral_poly(exact_modulus, p, prec):
    """
    Convert a defining polynomial into one with integral coefficients.

    INPUT:

    - ``exact_modulus`` -- a univariate polynomial

    - ``p`` -- a prime

    - ``prec`` -- the precision

    EXAMPLES::

        sage: from sage.rings.padics.padic_extension_leaves import _make_integral_poly
        sage: R.<x> = QQ[]
        sage: f = _make_integral_poly(x^2 - 2, 5, 3); f
        x^2 - 2
        sage: f.parent()
        Univariate Polynomial Ring in x over Integer Ring
        sage: f = _make_integral_poly(x^2 - 2/7, 5, 3); f
        x^2 + 89
        sage: f.parent()
        Univariate Polynomial Ring in x over Integer Ring
    """
    try:
        return exact_modulus.change_ring(ZZ)
    except TypeError:
        return exact_modulus.change_ring(Zmod(p**prec)).change_ring(ZZ)
Exemplo n.º 8
0
def _make_integral_poly(prepoly, p, prec):
    """
    Converts a defining polynomial into one with integral coefficients.

    INPUTS:

    - ``prepoly`` - a univariate polynomial or symbolic expression

    - ``p`` -- a prime

    - ``prec`` -- the precision

    EXAMPLES::

        sage: from sage.rings.padics.padic_extension_leaves import _make_integral_poly
        sage: R.<x> = QQ[]
        sage: f = _make_integral_poly(x^2 - 2, 5, 3); f
        x^2 - 2
        sage: f.parent()
        Univariate Polynomial Ring in x over Integer Ring
        sage: f = _make_integral_poly(x^2 - 2/7, 5, 3); f
        x^2 + 89
        sage: f.parent()
        Univariate Polynomial Ring in x over Integer Ring
    """
    try:
        Zpoly = prepoly.change_ring(ZZ)
    except AttributeError:
        # should be a symoblic expression
        Zpoly = prepoly.polynomial(QQ)
    except (TypeError, ValueError):
        Zpoly = prepoly.change_ring(QQ)
    if Zpoly.base_ring() is not ZZ:
        Zpoly = Zpoly.change_ring(Zmod(p**prec)).change_ring(ZZ)
    return Zpoly
Exemplo n.º 9
0
def blift(LF, Li, p, S=None):
    r"""
    Search for a solution to the given list of inequalities.

    If found, lift the solution to
    an appropriate valuation. See Lemma 3.3.6 in [Molnar]_

    INPUT:

    - ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients)

    - ``Li`` -- an integer, the bound on coefficients

    - ``p`` -- a prime

    OUTPUT:

    - boolean -- whether or not the lift is successful

    - integer -- the lift

    EXAMPLES::

        sage: R.<b> = PolynomialRing(QQ)
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import blift
        sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341, -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3)
        (True, 4)
    """

    P = LF[0].parent()
    #Determine which inequalities are trivial, and scale the rest, so that we only lift
    #as many times as needed.
    keepScaledIneqs = [scale(P(coeff), Li, p) for coeff in LF if coeff != 0]
    keptVals = [i[2] for i in keepScaledIneqs if i[0]]
    if keptVals != []:
        #Determine the valuation to lift until.
        liftval = max(keptVals)
    else:
        #All inequalities are satisfied.
        return True, 1
    if S is None:
        S = PolynomialRing(Zmod(p), 'b')
    keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]]
    #We need a solution for each polynomial on the left hand side of the inequalities,
    #so we need only find a solution for their gcd.
    g = gcd(keptScaledIneqs)
    rts = g.roots(multiplicities=False)
    for r in rts:
        #Recursively try to lift each root
        r_initial = QQ(r)
        newInput = P([r_initial, p])
        LG = [F(newInput) for F in LF]
        lift, lifted = blift(LG, Li, p, S=S)
        if lift:
            #Lift successful.
            return True, r_initial + p * lifted
    #Lift non successful.
    return False, 0
Exemplo n.º 10
0
def cyclotomic_cosets(q, n, t=None):
    r"""
    This method is deprecated.

    See the documentation in
    :func:`~sage.categories.rings.Rings.Finite.ParentMethods.cyclotomic_cosets`.

    INPUT: q,n,t positive integers (or t=None) Some type-checking of
    inputs is performed.

    OUTPUT: q-cyclotomic cosets mod n (or, if t is not None, the q-cyclotomic
    coset mod n containing t)

    EXAMPLES::

        sage: cyclotomic_cosets(2,11)
        doctest:...: DeprecationWarning: cyclotomic_cosets(q,n,t) is deprecated.
        Use Zmod(n).cyclotomic_cosets(q) or Zmod(n).cyclotomic_cosets(q,[t])
        instead. Be careful that this method returns elements of Zmod(n).
        See http://trac.sagemath.org/16464 for details.
        [[0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]

        sage: Zmod(11).cyclotomic_cosets(2)
        [[0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]

        sage: cyclotomic_cosets(5,11)
        [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]]
        sage: cyclotomic_cosets(5,11,3)
        [1, 3, 4, 5, 9]
    """
    from sage.misc.superseded import deprecation
    deprecation(
        16464, """cyclotomic_cosets(q,n,t) is deprecated. Use
                          Zmod(n).cyclotomic_cosets(q) or
                          Zmod(n).cyclotomic_cosets(q,[t]) instead. Be careful
                          that this method returns elements of Zmod(n).""")

    from sage.rings.finite_rings.integer_mod_ring import Zmod
    if t is None:
        return [[x.lift() for x in cos]
                for cos in Zmod(n).cyclotomic_cosets(q)]
    else:
        return [x.lift() for x in Zmod(n).cyclotomic_cosets(q, [t])[0]]
Exemplo n.º 11
0
    def residue_ring(self, n):
        """
        Returns the quotient of the ring of integers by the nth power of the maximal ideal.

        EXAMPLES::

            sage: R = Zp(11)
            sage: R.residue_ring(3)
            Ring of integers modulo 1331
        """
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        return Zmod(self.prime()**n)
Exemplo n.º 12
0
def _GammaH_coset_helper(N, H):
    r"""
    Return a list of coset representatives for H in (Z / NZ)^*.

    EXAMPLE::

        sage: from sage.modular.arithgroup.congroup_gammaH import _GammaH_coset_helper
        sage: _GammaH_coset_helper(108, [1, 107])
        [1, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53]
    """
    t = [Zmod(N)(1)]
    W = [Zmod(N)(h) for h in H]
    HH = [Zmod(N)(h) for h in H]
    k = euler_phi(N)

    for i in xrange(1, N):
        if gcd(i, N) != 1: continue
        if not i in W:
            t.append(t[0] * i)
            W = W + [i * h for h in HH]
            if len(W) == k: break
    return t
Exemplo n.º 13
0
 def linear_relation_new(self, List, Psi):
     # ~40% increase in speed for Npk = 2, 11, 0 sign = 0
     for Phi in List:
         assert Phi.valuation() >= 0
     assert Psi.valuation() >= 0
     R = self.base()
     d = len(List)
     if d == 0:
         if Psi.is_zero():
             return [None, R(1)]
         else:
             return [None, 0]
     M = Psi.precision_absolute()
     p = self.prime()
     V = R**d
     pM = p**M
     A = Matrix(Zmod(pM), [Phi.list_of_total_measures() for Phi in List])
     b = vector(Zmod(pM), Psi.list_of_total_measures())
     try:
         x = A.solve_left(b)
         return [V(x), R(-1)]
     except:
         return [V(0), 0]
Exemplo n.º 14
0
def intmod_gap_to_sage(x):
    r"""
    INPUT:

    - x -- Gap integer mod ring element

    EXAMPLES::

        sage: a = gap(Mod(3, 18)); a
        ZmodnZObj( 3, 18 )
        sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
        3
        sage: b.parent()
        Ring of integers modulo 18

        sage: a = gap(Mod(3, 17)); a
        Z(17)
        sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
        3
        sage: b.parent()
        Ring of integers modulo 17

        sage: a = gap(Mod(0, 17)); a
        0*Z(17)
        sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
        0
        sage: b.parent()
        Ring of integers modulo 17

        sage: a = gap(Mod(3, 65537)); a
        ZmodpZObj( 3, 65537 )
        sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
        3
        sage: b.parent()
        Ring of integers modulo 65537
    """
    from sage.rings.finite_rings.integer_mod import Mod
    from sage.rings.finite_rings.integer_mod_ring import Zmod
    s = str(x)
    m = re.search(r'Z\(([0-9]*)\)', s)
    if m:
        return gfq_gap_to_sage(x, Zmod(m.group(1)))
    m = re.match(r'Zmod[np]ZObj\( ([0-9]*), ([0-9]*) \)', s)
    if m:
        return Mod(m.group(1), m.group(2))
    raise ValueError, "Unable to convert Gap element '%s'" % s
Exemplo n.º 15
0
    def list(self):
        """
        Return a list of all the elements of self (for which the domain
        is a cyclotomic field).

        EXAMPLES::

            sage: K.<z> = CyclotomicField(12)
            sage: G = End(K); G
            Automorphism group of Cyclotomic Field of order 12 and degree 4
            sage: [g(z) for g in G]
            [z, z^3 - z, -z, -z^3 + z]
            sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1])
            sage: L
            Number Field in a with defining polynomial x^2 + x + 1 over its base field
            sage: Hom(CyclotomicField(12), L)[3]
            Ring morphism:
              From: Cyclotomic Field of order 12 and degree 4
              To:   Number Field in a with defining polynomial x^2 + x + 1 over its base field
              Defn: zeta12 |--> -b^2*a
            sage: list(Hom(CyclotomicField(5), K))
            []
            sage: Hom(CyclotomicField(11), L).list()
            []
        """
        try:
            return self.__list
        except AttributeError:
            pass

        D = self.domain()
        C = self.codomain()
        z = D.gen()
        n = z.multiplicative_order()
        if not n.divides(C.zeta_order()):
            v =[]
        else:
            if D == C:
                w = z
            else:
                w = C.zeta(n)
            v = [self([w**k], check=False) for k in Zmod(n) if k.is_unit()]
        v = Sequence(v, universe=self, check=False, immutable=True, cr=v!=[])
        self.__list = v
        return v
Exemplo n.º 16
0
    def __mod__(self, other):
        """
        TESTS::

            sage: R.<a,b,c> = PowerSeriesRing(ZZ)
            sage: f = -a^3*b*c^2 + a^2*b^2*c^4 - 12*a^3*b^3*c^3 + R.O(10)
            sage: g = f % 2; g
            a^3*b*c^2 + a^2*b^2*c^4 + O(a, b, c)^10
            sage: g in R
            False
            sage: g in R.base_extend(Zmod(2))
            True
            sage: g.polynomial() == f.polynomial() % 2
            True
        """
        if isinstance(other, (int, Integer, long)):
            return self.change_ring(Zmod(other))
        raise NotImplementedError(
            "Mod on multivariate power series ring elements not defined except modulo an integer."
        )
Exemplo n.º 17
0
    def __init__(self, n, R, depth=None, basis=None):
        Module.__init__(self, base=R)
        if basis is not None:
            self._basis = copy(basis)
        self._n = n
        self._R = R
        if R.is_exact():
            self._Rmod = self._R
        else:
            self._Rmod = Zmod(self._R.prime()**(self._R.precision_cap()))

        if depth is None:
            depth = n + 1
        if depth != n + 1:
            if R.is_exact():
                raise ValueError, "Trying to construct an over-convergent module with exact coefficients, how do you store p-adics ??"
        self._depth = depth
        self._PowerSeries = PowerSeriesRing(self._Rmod,
                                            default_prec=self._depth,
                                            name='z')
        self._powers = dict()
        self._populate_coercion_lists_()
Exemplo n.º 18
0
Arquivo: tests.py Projeto: yjjcc/sage
    def __init__(self, index=20, index_max=50, odd_probability=0.5):
        r"""
        Create an arithmetic subgroup testing object.

        INPUT:

        - ``index`` - the index of random subgroup to test

        - ``index_max`` - the maximum index for congruence subgroup to test

        EXAMPLES::

            sage: from sage.modular.arithgroup.tests import Test
            sage: Test()
            Arithmetic subgroup testing class
        """
        self.congroups = []
        i = 1
        self.odd_probability = odd_probability
        if index % 4:
            self.odd_probability = 0
        while Gamma(i).index() < index_max:
            self.congroups.append(Gamma(i))
            i += 1
        i = 1
        while Gamma0(i).index() < index_max:
            self.congroups.append(Gamma0(i))
            i += 1
        i = 2
        while Gamma1(i).index() < index_max:
            self.congroups.append(Gamma1(i))
            M = Zmod(i)
            U = [x for x in M if x.is_unit()]
            for j in range(1, len(U) - 1):
                self.congroups.append(GammaH(i, prandom.sample(U, j)))
            i += 1

        self.index = index
Exemplo n.º 19
0
def RandomBicubicPlanar(n):
    """
    Return the graph of a random bipartite cubic map with `3 n` edges.

    INPUT:

    `n` -- an integer (at least `1`)

    OUTPUT:

    a graph with multiple edges (no embedding is provided)

    The algorithm used is described in [Schaeffer99]_. This samples
    a random rooted bipartite cubic map, chosen uniformly at random.

    First one creates a random binary tree with `n` vertices. Next one
    turns this into a blossoming tree (at random) and reads the
    contour word of this blossoming tree.

    Then one performs a rotation on this word so that this becomes a
    balanced word. There are three ways to do that, one is picked at
    random. Then a graph is build from the balanced word by iterated
    closure (adding edges).

    In the returned graph, the three edges incident to any given
    vertex are colored by the integers 0, 1 and 2.

    .. SEEALSO:: the auxiliary method :func:`blossoming_contour`

    EXAMPLES::

        sage: n = randint(200, 300)
        sage: G = graphs.RandomBicubicPlanar(n)
        sage: G.order() == 2*n
        True
        sage: G.size() == 3*n
        True
        sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)
        True
        sage: dic = {'red':[v for v in G.vertices() if v[0] == 'n'],
        ....:        'blue': [v for v in G.vertices() if v[0] != 'n']}
        sage: G.plot(vertex_labels=False,vertex_size=20,vertex_colors=dic)
        Graphics object consisting of ... graphics primitives

    .. PLOT::
        :width: 300 px

        G = graphs.RandomBicubicPlanar(200)
        V0 = [v for v in G.vertices() if v[0] == 'n']
        V1 = [v for v in G.vertices() if v[0] != 'n']
        dic = {'red': V0, 'blue': V1}
        sphinx_plot(G.plot(vertex_labels=False,vertex_colors=dic))

    REFERENCES:

    .. [Schaeffer99] Gilles Schaeffer, *Random Sampling of Large Planar Maps and Convex Polyhedra*,
       Annual ACM Symposium on Theory of Computing (Atlanta, GA, 1999)
    """
    from sage.combinat.binary_tree import BinaryTrees
    from sage.rings.finite_rings.integer_mod_ring import Zmod
    if not n:
        raise ValueError("n must be at least 1")
    # first pick a random binary tree
    t = BinaryTrees(n).random_element()

    # next pick a random blossoming of this tree, compute its contour
    contour = blossoming_contour(t) + [('xb',)]   # adding the final xb

    # first step : rotate the contour word to one of 3 balanced
    N = len(contour)
    double_contour = contour + contour
    pile = []
    not_touched = [i for i in range(N) if contour[i][0] in ['x', 'xb']]
    for i, w in enumerate(double_contour):
        if w[0] == 'x' and i < N:
            pile.append(i)
        elif w[0] == 'xb' and (i % N) in not_touched:
            if pile:
                j = pile.pop()
                not_touched.remove(i % N)
                not_touched.remove(j)

    # random choice among 3 possibilities for a balanced word
    idx = not_touched[randint(0, 2)]
    w = contour[idx + 1:] + contour[:idx + 1]

    # second step : create the graph by closure from the balanced word
    G = Graph(multiedges=True)

    pile = []
    Z3 = Zmod(3)
    colour = Z3.zero()
    not_touched = [i for i, v in enumerate(w) if v[0] in ['x', 'xb']]
    for i, v in enumerate(w):
        # internal edges
        if v[0] == 'i':
            colour += 1
            if w[i + 1][0] == 'n':
                G.add_edge((w[i], w[i + 1], colour))
        elif v[0] == 'n':
            colour += 2
        elif v[0] == 'x':
            pile.append(i)
        elif v[0] == 'xb' and i in not_touched:
            if pile:
                j = pile.pop()
                G.add_edge((w[i + 1], w[j - 1], colour))
                not_touched.remove(i)
                not_touched.remove(j)

    # there remains to add three edges to elements of "not_touched"
    # from a new vertex labelled "n"
    for i in not_touched:
        taken_colours = [edge[2] for edge in G.edges_incident(w[i - 1])]
        colour = [u for u in Z3 if u not in taken_colours][0]
        G.add_edge((('n', -1), w[i - 1], colour))

    return G
Exemplo n.º 20
0
def difference_family(v, k, l=1, existence=False, check=True):
    r"""
    Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``.

    Let `G` be a finite Abelian group. For a given subset `D` of `G`, we define
    `\Delta D` to be the multi-set of differences `\Delta D = \{x - y; x \in D,
    y \in D, x \not= y\}`. A `(G,k,\lambda)`-*difference family* is a collection
    of `k`-subsets of `G`, `D = \{D_1, D_2, \ldots, D_b\}` such that the union
    of the difference sets `\Delta D_i` for `i=1,...b`, seen as a multi-set,
    contains each element of `G \backslash \{0\}` exactly `\lambda`-times.

    When there is only one block, i.e. `\lambda(v - 1) = k(k-1)`, then a
    `(G,k,\lambda)`-difference family is also called a *difference set*.

    See also :wikipedia:`Difference_set`.

    If there is no such difference family, an ``EmptySetError`` is raised and if
    there is no construction at the moment ``NotImplementedError`` is raised.

    EXAMPLES::

        sage: K,D = designs.difference_family(73,4)
        sage: D
        [[0, 1, 8, 64],
         [0, 25, 54, 67],
         [0, 41, 36, 69],
         [0, 3, 24, 46],
         [0, 2, 16, 55],
         [0, 50, 35, 61]]

        sage: K,D = designs.difference_family(337,7)
        sage: D
        [[1, 175, 295, 64, 79, 8, 52],
         [326, 97, 125, 307, 142, 249, 102],
         [121, 281, 310, 330, 123, 294, 226],
         [17, 279, 297, 77, 332, 136, 210],
         [150, 301, 103, 164, 55, 189, 49],
         [35, 59, 215, 218, 69, 280, 135],
         [289, 25, 331, 298, 252, 290, 200],
         [191, 62, 66, 92, 261, 180, 159]]

    For `k=6,7` we look at the set of small prime powers for which a
    construction is available::

        sage: def prime_power_mod(r,m):
        ....:     k = m+r
        ....:     while True:
        ....:         if is_prime_power(k):
        ....:             yield k
        ....:         k += m

        sage: from itertools import islice
        sage: l6 = {True:[], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,30), 60):
        ....:     l6[designs.difference_family(q,6,existence=True)].append(q)
        sage: l6[True]
        [31, 121, 151, 181, 211, ...,  3061, 3121, 3181]
        sage: l6[Unknown]
        [61]
        sage: l6[False]
        []

        sage: l7 = {True: [], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,42), 60):
        ....:     l7[designs.difference_family(q,7,existence=True)].append(q)
        sage: l7[True]
        [337, 421, 463, 883, 1723, 3067, 3319, 3529, 3823, 3907, 4621, 4957, 5167]
        sage: l7[Unknown]
        [43, 127, 169, 211, ..., 4999, 5041, 5209]
        sage: l7[False]
        []

    Other constructions for `\lambda > 1`::

        sage: for v in xrange(2,100):
        ....:     constructions = []
        ....:     for k in xrange(2,10):
        ....:         for l in xrange(2,10):
        ....:             if designs.difference_family(v,k,l,existence=True):
        ....:                 constructions.append((k,l))
        ....:                 _ = designs.difference_family(v,k,l)
        ....:     if constructions:
        ....:         print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions))
         2: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         3: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         4: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         5: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         7: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         8: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
         9: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        11: (3,2), (4,3), (4,6), (5,2), (5,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        13: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
        15: (4,6), (5,6), (7,3)
        16: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        17: (3,2), (4,3), (5,4), (5,5), (6,5), (7,6), (8,7), (9,8)
        19: (3,2), (4,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,4), (9,5), (9,6), (9,7), (9,8)
        21: (4,3), (6,3), (6,5)
        22: (4,2), (6,5), (7,4), (8,8)
        23: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        25: (3,2), (4,3), (5,4), (6,5), (7,6), (7,7), (8,7), (9,8)
        27: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        28: (3,2), (6,5)
        29: (3,2), (4,3), (5,4), (6,5), (7,3), (7,6), (8,4), (8,6), (8,7), (9,8)
        31: (3,2), (4,2), (4,3), (5,2), (5,4), (6,5), (7,6), (8,7), (9,8)
        32: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        33: (5,5), (6,5)
        34: (4,2)
        35: (5,2), (8,4)
        37: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,2), (9,3), (9,8)
        39: (6,5)
        40: (3,2)
        41: (3,2), (4,3), (5,4), (6,3), (6,5), (7,6), (8,7), (9,8)
        43: (3,2), (4,2), (4,3), (5,4), (6,5), (7,2), (7,3), (7,6), (8,4), (8,7), (9,8)
        46: (4,2), (6,2)
        47: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        49: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)
        51: (5,2), (6,3)
        53: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        55: (9,4)
        57: (7,3)
        59: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        61: (3,2), (4,3), (5,4), (6,2), (6,3), (6,5), (7,6), (8,7), (9,8)
        64: (3,2), (4,3), (5,4), (6,5), (7,2), (7,6), (8,7), (9,8)
        67: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        71: (3,2), (4,3), (5,2), (5,4), (6,5), (7,3), (7,6), (8,4), (8,7), (9,8)
        73: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        75: (5,2)
        79: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        81: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        83: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        85: (7,2), (7,3), (8,2)
        89: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,8)
        97: (3,2), (4,3), (5,4), (6,5), (7,6), (8,7), (9,3), (9,8)

    TESTS:

    Check more of the Wilson constructions from [Wi72]_::

        sage: Q5 = [241, 281,421,601,641, 661, 701, 821,881]
        sage: Q9 = [73, 1153, 1873, 2017]
        sage: Q15 = [76231]
        sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457]
        sage: Q8 = [1009, 3137, 3697]
        sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]:
        ....:     for q in Q:
        ....:         assert designs.difference_family(q,k,1,existence=True) is True
        ....:         _ = designs.difference_family(q,k,1)

    Check Singer difference sets::

        sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1))

        sage: for q in range(2,10):
        ....:     if is_prime_power(q):
        ....:         for d in [2,3,4]:
        ....:           v,k,l = sgp(q,d)
        ....:           assert designs.difference_family(v,k,l,existence=True) is True
        ....:           _ = designs.difference_family(v,k,l)

    Check twin primes difference sets::

        sage: for p in [3,5,7,9,11]:
        ....:     v = p*(p+2); k = (v-1)/2;  lmbda = (k-1)/2
        ....:     G,D = designs.difference_family(v,k,lmbda)

    Check the database:

        sage: from sage.combinat.designs.database import DF
        sage: for v,k,l in DF:
        ....:     df = designs.difference_family(v,k,l,check=True)

    .. TODO::

        Implement recursive constructions from Buratti "Recursive for difference
        matrices and relative difference families" (1998) and Jungnickel
        "Composition theorems for difference families and regular planes" (1978)
    """
    from block_design import are_hyperplanes_in_projective_geometry_parameters

    from database import DF

    if (v, k, l) in DF:
        if existence:
            return True

        vv, blocks = DF[v, k, l].iteritems().next()

        # Build the group
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        if len(vv) == 1:
            G = Zmod(vv[0])
        else:
            from sage.categories.cartesian_product import cartesian_product
            G = cartesian_product([Zmod(i) for i in vv])

        df = [[G(i) for i in b] for b in blocks]

        if check:
            assert is_difference_family(
                G, df, v=v, k=k,
                l=l), "Sage built an invalid ({},{},{})-DF!".format(v, k, l)

        return G, df

    e = k * (k - 1)
    t = l * (v - 1) // e  # number of blocks

    D = None

    factorization = arith.factor(v)

    if len(factorization) == 1:  # i.e. is v a prime power
        from sage.rings.finite_rings.constructor import GF
        G = K = GF(v, 'z')
        x = K.multiplicative_generator()

        if l == (k - 1):
            if existence:
                return True
            return K, K.cyclotomic_cosets(x**((v - 1) // k))[1:]

        if t == 1:
            # some of the difference set constructions VI.18.48 from the
            # Handbook of combinatorial designs
            # q = 3 mod 4
            if v % 4 == 3 and k == (v - 1) // 2:
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**2, [1])

            # q = 4t^2 + 1, t odd
            elif v % 8 == 5 and k == (v - 1) // 4 and arith.is_square(
                (v - 1) // 4):
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**4, [1])

            # q = 4t^2 + 9, t odd
            elif v % 8 == 5 and k == (v + 3) // 4 and arith.is_square(
                (v - 9) // 4):
                if existence:
                    return True
                D = K.cyclotomic_cosets(x**4, [1])
                D[0].insert(0, K.zero())

        if D is None and l == 1:
            one = K.one()

            # Wilson (1972), Theorem 9
            if k % 2 == 1:
                m = (k - 1) // 2
                xx = x**m
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(m) for j in xrange((v - 1) / m)
                }
                r = x**((v - 1) // k)  # primitive k-th root of unity
                if len(set(to_coset[r**j - one]
                           for j in xrange(1, m + 1))) == m:
                    if existence:
                        return True
                    B = [r**j for j in xrange(k)
                         ]  # = H^((k-1)t) whose difference is
                    # H^(mt) (r^i - 1, i=1,..,m)
                    # Now pick representatives a translate of R for by a set of
                    # representatives of H^m / H^(mt)
                    D = [[x**(i * m) * b for b in B] for i in xrange(t)]

            # Wilson (1972), Theorem 10
            else:
                m = k // 2
                xx = x**m
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(m) for j in xrange((v - 1) / m)
                }
                r = x**((v - 1) // (k - 1))  # primitive (k-1)-th root of unity
                if (all(to_coset[r**j - one] != 0 for j in xrange(1, m))
                        and len(set(to_coset[r**j - one]
                                    for j in xrange(1, m))) == m - 1):
                    if existence:
                        return True
                    B = [K.zero()] + [r**j for j in xrange(k - 1)]
                    D = [[x**(i * m) * b for b in B] for i in xrange(t)]

            # Wilson (1972), Theorem 11
            if D is None and k == 6:
                r = x**((v - 1) // 3)  # primitive cube root of unity
                r2 = r * r
                xx = x**5
                to_coset = {
                    x**i * xx**j: i
                    for i in xrange(5) for j in xrange((v - 1) / 5)
                }
                for c in to_coset:
                    if c == 1 or c == r or c == r2:
                        continue
                    if len(
                            set(to_coset[elt]
                                for elt in (r - 1, c * (r - 1), c - 1, c - r,
                                            c - r**2))) == 5:
                        if existence:
                            return True
                        B = [one, r, r**2, c, c * r, c * r**2]
                        D = [[x**(i * 5) * b for b in B] for i in xrange(t)]
                        break

    # Twin prime powers construction (see :wikipedia:`Difference_set`)
    #
    # i.e. v = p(p+2) where p and p+2 are prime powers
    #      k = (v-1)/2
    #      lambda = (k-1)/2
    elif (len(factorization) == 2
          and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2
          and k == (v - 1) // 2 and (l is None or 2 * l == (v - 1) // 2 - 1)):

        # A difference set can be built from the set of elements
        # (x,y) in GF(p) x GF(p+2) such that:
        #
        # - either y=0
        # - x and y with x and y     squares
        # - x and y with x and y non-squares
        if existence:
            return True

        from sage.rings.finite_rings.constructor import FiniteField
        from sage.categories.cartesian_product import cartesian_product
        from itertools import product
        p, q = pow(*factorization[0]), pow(*factorization[1])
        if p > q:
            p, q = q, p
        Fp = FiniteField(p, 'x')
        Fq = FiniteField(q, 'x')
        Fpset = set(Fp)
        Fqset = set(Fq)
        Fp_squares = set(x**2 for x in Fpset)
        Fq_squares = set(x**2 for x in Fqset)

        # Pairs of squares, pairs of non-squares
        d = []
        d.extend(
            product(Fp_squares.difference([0]), Fq_squares.difference([0])))
        d.extend(
            product(Fpset.difference(Fp_squares),
                    Fqset.difference(Fq_squares)))

        # All (x,0)
        d.extend((x, 0) for x in Fpset)

        G = cartesian_product([Fp, Fq])
        D = [d]

    if D is None and are_hyperplanes_in_projective_geometry_parameters(
            v, k, l):
        _, (q, d) = are_hyperplanes_in_projective_geometry_parameters(
            v, k, l, True)
        if existence:
            return True
        else:
            G, D = singer_difference_set(q, d)

    if D is None:
        if existence:
            return Unknown
        raise NotImplementedError("No constructions for these parameters")

    if check and not is_difference_family(G, D, verbose=False):
        raise RuntimeError

    return G, D
Exemplo n.º 21
0
def singer_difference_set(q, d):
    r"""
    Return a difference set associated to the set of hyperplanes in a projective
    space of dimension `d` over `GF(q)`.

    A Singer difference set has parameters:

    .. MATH::

        v = \frac{q^{d+1}-1}{q-1}, \quad
        k = \frac{q^d-1}{q-1}, \quad
        \lambda = \frac{q^{d-1}-1}{q-1}.

    The idea of the construction is as follows. One consider the finite field
    `GF(q^{d+1})` as a vector space of dimension `d+1` over `GF(q)`. The set of
    `GF(q)`-lines in `GF(q^{d+1})` is a projective plane and its set of
    hyperplanes form a balanced incomplete block design.

    Now, considering a multiplicative generator `z` of `GF(q^{d+1})`, we get a
    transitive action of a cyclic group on our projective plane from which it is
    possible to build a difference set.

    The construction is given in details in [Stinson2004]_, section 3.3.

    EXAMPLES::

        sage: from sage.combinat.designs.difference_family import singer_difference_set, is_difference_family
        sage: G,D = singer_difference_set(3,2)
        sage: is_difference_family(G,D,verbose=True)
        It is a (13,4,1)-difference family
        True

        sage: G,D = singer_difference_set(4,2)
        sage: is_difference_family(G,D,verbose=True)
        It is a (21,5,1)-difference family
        True

        sage: G,D = singer_difference_set(3,3)
        sage: is_difference_family(G,D,verbose=True)
        It is a (40,13,4)-difference family
        True

        sage: G,D = singer_difference_set(9,3)
        sage: is_difference_family(G,D,verbose=True)
        It is a (820,91,10)-difference family
        True
    """
    q = Integer(q)
    assert q.is_prime_power()
    assert d >= 2

    from sage.rings.finite_rings.constructor import GF
    from sage.rings.finite_rings.conway_polynomials import conway_polynomial
    from sage.rings.finite_rings.integer_mod_ring import Zmod

    # build a polynomial c over GF(q) such that GF(q)[x] / (c(x)) is a
    # GF(q**(d+1)) and such that x is a multiplicative generator.
    p, e = q.factor()[0]
    c = conway_polynomial(p, e * (d + 1))
    if e != 1:  # i.e. q is not a prime, so we factorize c over GF(q) and pick
        # one of its factor
        K = GF(q, 'z')
        c = c.change_ring(K).factor()[0][0]
    else:
        K = GF(q)
    z = c.parent().gen()

    # Now we consider the GF(q)-subspace V spanned by (1,z,z^2,...,z^(d-1)) inside
    # GF(q^(d+1)). The multiplication by z is an automorphism of the
    # GF(q)-projective space built from GF(q^(d+1)). The difference family is
    # obtained by taking the integers i such that z^i belong to V.
    powers = [0]
    i = 1
    x = z
    k = (q**d - 1) // (q - 1)
    while len(powers) < k:
        if x.degree() <= (d - 1):
            powers.append(i)
        x = (x * z).mod(c)
        i += 1

    return Zmod((q**(d + 1) - 1) // (q - 1)), [powers]
Exemplo n.º 22
0
def difference_family(v, k, l=1, existence=False, explain_construction=False, check=True):
    r"""
    Return a (``k``, ``l``)-difference family on an Abelian group of cardinality ``v``.

    Let `G` be a finite Abelian group. For a given subset `D` of `G`, we define
    `\Delta D` to be the multi-set of differences `\Delta D = \{x - y; x \in D,
    y \in D, x \not= y\}`. A `(G,k,\lambda)`-*difference family* is a collection
    of `k`-subsets of `G`, `D = \{D_1, D_2, \ldots, D_b\}` such that the union
    of the difference sets `\Delta D_i` for `i=1,...b`, seen as a multi-set,
    contains each element of `G \backslash \{0\}` exactly `\lambda`-times.

    When there is only one block, i.e. `\lambda(v - 1) = k(k-1)`, then a
    `(G,k,\lambda)`-difference family is also called a *difference set*.

    See also :wikipedia:`Difference_set`.

    If there is no such difference family, an ``EmptySetError`` is raised and if
    there is no construction at the moment ``NotImplementedError`` is raised.

    INPUT:

    - ``v,k,l`` -- parameters of the difference family. If ``l`` is not provided
      it is assumed to be ``1``.

    - ``existence`` -- if ``True``, then return either ``True`` if Sage knows
      how to build such design, ``Unknown`` if it does not and ``False`` if it
      knows that the design does not exist.

    - ``explain_construction`` -- instead of returning a difference family,
      returns a string that explains the construction used.

    - ``check`` -- boolean (default: ``True``). If ``True`` then the result of
      the computation is checked before being returned. This should not be
      needed but ensures that the output is correct.

    OUTPUT:

    A pair ``(G,D)`` made of a group `G` and a difference family `D` on that
    group. Or, if ``existence`` is ``True`` a troolean or if
    ``explain_construction`` is ``True`` a string.

    EXAMPLES::

        sage: G,D = designs.difference_family(73,4)
        sage: G
        Finite Field of size 73
        sage: D
        [[0, 1, 5, 18],
         [0, 3, 15, 54],
         [0, 9, 45, 16],
         [0, 27, 62, 48],
         [0, 8, 40, 71],
         [0, 24, 47, 67]]

        sage: print designs.difference_family(73, 4, explain_construction=True)
        The database contains a (73,4)-evenly distributed set

        sage: G,D = designs.difference_family(15,7,3)
        sage: G
        The cartesian product of (Finite Field of size 3, Finite Field of size 5)
        sage: D
        [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]]
        sage: print designs.difference_family(15,7,3,explain_construction=True)
        Twin prime powers difference family

        sage: print designs.difference_family(91,10,1,explain_construction=True)
        Singer difference set

    For `k=6,7` we look at the set of small prime powers for which a
    construction is available::

        sage: def prime_power_mod(r,m):
        ....:     k = m+r
        ....:     while True:
        ....:         if is_prime_power(k):
        ....:             yield k
        ....:         k += m

        sage: from itertools import islice
        sage: l6 = {True:[], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,30), 60):
        ....:     l6[designs.difference_family(q,6,existence=True)].append(q)
        sage: l6[True]
        [31, 121, 151, 181, 211, ...,  3061, 3121, 3181]
        sage: l6[Unknown]
        [61]
        sage: l6[False]
        []

        sage: l7 = {True: [], False: [], Unknown: []}
        sage: for q in islice(prime_power_mod(1,42), 60):
        ....:     l7[designs.difference_family(q,7,existence=True)].append(q)
        sage: l7[True]
        [169, 337, 379, 421, 463, 547, 631, 673, 757, 841, 883, 967, ...,  4621, 4957, 5167]
        sage: l7[Unknown]
        [43, 127, 211, 2017, 2143, 2269, 2311, 2437, 2521, 2647, ..., 4999, 5041, 5209]
        sage: l7[False]
        []

    List available constructions::

        sage: for v in xrange(2,100):
        ....:     constructions = []
        ....:     for k in xrange(2,10):
        ....:         for l in xrange(1,10):
        ....:             if designs.difference_family(v,k,l,existence=True):
        ....:                 constructions.append((k,l))
        ....:                 _ = designs.difference_family(v,k,l)
        ....:     if constructions:
        ....:         print "%2d: %s"%(v, ', '.join('(%d,%d)'%(k,l) for k,l in constructions))
         3: (2,1)
         4: (3,2)
         5: (2,1), (4,3)
         6: (5,4)
         7: (2,1), (3,1), (3,2), (4,2), (6,5)
         8: (7,6)
         9: (2,1), (4,3), (8,7)
        10: (9,8)
        11: (2,1), (4,6), (5,2), (5,4), (6,3)
        13: (2,1), (3,1), (3,2), (4,1), (4,3), (5,5), (6,5)
        15: (3,1), (4,6), (5,6), (7,3)
        16: (3,2), (5,4), (6,2)
        17: (2,1), (4,3), (5,5), (8,7)
        19: (2,1), (3,1), (3,2), (4,2), (6,5), (9,4), (9,8)
        21: (3,1), (4,3), (5,1), (6,3), (6,5)
        22: (4,2), (6,5), (7,4), (8,8)
        23: (2,1)
        25: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (7,7), (8,7)
        27: (2,1), (3,1)
        28: (3,2), (6,5)
        29: (2,1), (4,3), (7,3), (7,6), (8,4), (8,6)
        31: (2,1), (3,1), (3,2), (4,2), (5,2), (5,4), (6,1), (6,5)
        33: (3,1), (5,5), (6,5)
        34: (4,2)
        35: (5,2)
        37: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (9,2), (9,8)
        39: (3,1), (6,5)
        40: (3,2), (4,1)
        41: (2,1), (4,3), (5,1), (5,4), (6,3), (8,7)
        43: (2,1), (3,1), (3,2), (4,2), (6,5), (7,2), (7,3), (7,6), (8,4)
        45: (3,1), (5,1)
        46: (4,2), (6,2)
        47: (2,1)
        49: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,3)
        51: (3,1), (5,2), (6,3)
        52: (4,1)
        53: (2,1), (4,3)
        55: (3,1), (9,4)
        57: (3,1), (7,3), (8,1)
        59: (2,1)
        61: (2,1), (3,1), (3,2), (4,1), (4,3), (5,1), (5,4), (6,2), (6,3), (6,5)
        63: (3,1)
        64: (3,2), (4,1), (7,2), (7,6), (9,8)
        65: (5,1)
        67: (2,1), (3,1), (3,2), (6,5)
        69: (3,1)
        71: (2,1), (5,2), (5,4), (7,3), (7,6), (8,4)
        73: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,1), (9,8)
        75: (3,1), (5,2)
        76: (4,1)
        79: (2,1), (3,1), (3,2), (6,5)
        81: (2,1), (3,1), (4,3), (5,1), (5,4), (8,7)
        83: (2,1)
        85: (4,1), (7,2), (7,3), (8,2)
        89: (2,1), (4,3), (8,7)
        91: (6,1), (7,1)
        97: (2,1), (3,1), (3,2), (4,1), (4,3), (6,5), (8,7), (9,3)

    TESTS:

    Check more of the Wilson constructions from [Wi72]_::

        sage: Q5 = [241, 281,421,601,641, 661, 701, 821,881]
        sage: Q9 = [73, 1153, 1873, 2017]
        sage: Q15 = [76231]
        sage: Q4 = [13, 73, 97, 109, 181, 229, 241, 277, 337, 409, 421, 457]
        sage: Q8 = [1009, 3137, 3697]
        sage: for Q,k in [(Q4,4),(Q5,5),(Q8,8),(Q9,9),(Q15,15)]:
        ....:     for q in Q:
        ....:         assert designs.difference_family(q,k,1,existence=True) is True
        ....:         _ = designs.difference_family(q,k,1)

    Check Singer difference sets::

        sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1))

        sage: for q in range(2,10):
        ....:     if is_prime_power(q):
        ....:         for d in [2,3,4]:
        ....:           v,k,l = sgp(q,d)
        ....:           assert designs.difference_family(v,k,l,existence=True) is True
        ....:           _ = designs.difference_family(v,k,l)

    Check twin primes difference sets::

        sage: for p in [3,5,7,9,11]:
        ....:     v = p*(p+2); k = (v-1)/2;  lmbda = (k-1)/2
        ....:     G,D = designs.difference_family(v,k,lmbda)

    Check the database::

        sage: from sage.combinat.designs.database import DF,EDS
        sage: for v,k,l in DF:
        ....:     assert designs.difference_family(v,k,l,existence=True) is True
        ....:     df = designs.difference_family(v,k,l,check=True)

        sage: for k in EDS:
        ....:     for v in EDS[k]:
        ....:         assert designs.difference_family(v,k,1,existence=True) is True
        ....:         df = designs.difference_family(v,k,1,check=True)

    Check a failing construction (:trac:`17528`)::

        sage: designs.difference_family(9,3)
        Traceback (most recent call last):
        ...
        NotImplementedError: No construction available for (9,3,1)-difference family

    .. TODO::

        Implement recursive constructions from Buratti "Recursive for difference
        matrices and relative difference families" (1998) and Jungnickel
        "Composition theorems for difference families and regular planes" (1978)
    """
    from block_design import are_hyperplanes_in_projective_geometry_parameters

    from database import DF, EDS

    if (v,k,l) in DF:
        if existence:
            return True
        elif explain_construction:
            return "The database contains a ({},{},{})-difference family".format(v,k,l)

        vv, blocks = next(DF[v,k,l].iteritems())

        # Build the group
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        if len(vv) == 1:
            G = Zmod(vv[0])
        else:
            from sage.categories.cartesian_product import cartesian_product
            G = cartesian_product([Zmod(i) for i in vv])

        df = [[G(i) for i in b] for b in blocks]

        if check and not is_difference_family(G, df, v=v, k=k, l=l):
            raise RuntimeError("There is an invalid ({},{},{})-difference "
                    "family in the database... Please contact "
                    "*****@*****.**".format(v,k,l))

        return G,df

    elif l == 1 and k in EDS and v in EDS[k]:
        if existence:
            return True
        elif explain_construction:
            return "The database contains a ({},{})-evenly distributed set".format(v,k)

        from sage.rings.finite_rings.constructor import GF
        poly,B = EDS[k][v]
        if poly is None:  # q is prime
            K = G = GF(v)
        else:
            K = G = GF(v,'a',modulus=poly)

        B = map(K,B)
        e = k*(k-1)/2
        xe = G.multiplicative_generator()**e
        df = [[xe**j*b for b in B] for j in range((v-1)/(2*e))]
        if check and not is_difference_family(G, df, v=v, k=k, l=l):
            raise RuntimeError("There is an invalid ({},{})-evenly distributed "
                     "set in the database... Please contact "
                     "*****@*****.**".format(v,k,l))
        return G,df

    e = k*(k-1)
    if (l*(v-1)) % e:
        if existence:
            return Unknown
        raise NotImplementedError("No construction available for ({},{},{})-difference family".format(v,k,l))
    t = l*(v-1) // e  # number of blocks

    # trivial construction
    if k == (v-1) and l == (v-2):
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        G = Zmod(v)
        return G, [range(1,v)]

    factorization = arith.factor(v)
    D = None

    if len(factorization) == 1:  # i.e. is v a prime power
        from sage.rings.finite_rings.constructor import GF
        G = K = GF(v,'z')

        if radical_difference_family(K, k, l, existence=True):
            if existence:
                return True
            elif explain_construction:
                return "Radical difference family on a finite field"
            else:
                D = radical_difference_family(K,k,l)

        elif l == 1 and k == 6 and df_q_6_1(K,existence=True):
            if existence:
                return True
            elif explain_construction:
                return "Wilson 1972 difference family made from the union of two cyclotomic cosets"
            else:
                D = df_q_6_1(K)

    # Twin prime powers construction
    # i.e. v = p(p+2) where p and p+2 are prime powers
    #      k = (v-1)/2
    #      lambda = (k-1)/2 (ie 2l+1 = k)
    elif (k == (v-1)//2 and
          l == (k-1)//2 and
          len(factorization) == 2 and
          abs(pow(*factorization[0]) - pow(*factorization[1])) == 2):
        if existence:
            return True
        elif explain_construction:
            return "Twin prime powers difference family"
        else:
            p = pow(*factorization[0])
            q = pow(*factorization[1])
            if p > q:
                p,q = q,p
            G,D = twin_prime_powers_difference_set(p,check=False)

    if D is None and are_hyperplanes_in_projective_geometry_parameters(v,k,l):
        _, (q,d) = are_hyperplanes_in_projective_geometry_parameters(v,k,l,True)
        if existence:
            return True
        elif explain_construction:
            return "Singer difference set"
        else:
            G,D = singer_difference_set(q,d)

    if D is None:
        if existence:
            return Unknown
        raise NotImplementedError("No constructions for these parameters")

    if check and not is_difference_family(G,D,v=v,k=k,l=l,verbose=False):
        raise RuntimeError("There is a problem. Sage built the following "
                "difference family on G='{}' with parameters ({},{},{}):\n "
                "{}\nwhich seems to not be a difference family... "
                "Please contact [email protected]".format(G,v,k,l,D))

    return G, D
Exemplo n.º 23
0
def RandomBicubicPlanar(n):
    """
    Return the graph of a random bipartite cubic map with `3 n` edges.

    INPUT:

    `n` -- an integer (at least `1`)

    OUTPUT:

    a graph with multiple edges (no embedding is provided)

    The algorithm used is described in [Schaeffer99]_. This samples
    a random rooted bipartite cubic map, chosen uniformly at random.

    First one creates a random binary tree with `n` vertices. Next one
    turns this into a blossoming tree (at random) and reads the
    contour word of this blossoming tree.

    Then one performs a rotation on this word so that this becomes a
    balanced word. There are three ways to do that, one is picked at
    random. Then a graph is build from the balanced word by iterated
    closure (adding edges).

    In the returned graph, the three edges incident to any given
    vertex are colored by the integers 0, 1 and 2.

    .. SEEALSO:: the auxiliary method :func:`blossoming_contour`

    EXAMPLES::

        sage: n = randint(200, 300)
        sage: G = graphs.RandomBicubicPlanar(n)
        sage: G.order() == 2*n
        True
        sage: G.size() == 3*n
        True
        sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)
        True
        sage: dic = {'red':[v for v in G.vertices() if v[0] == 'n'],
        ....:        'blue': [v for v in G.vertices() if v[0] != 'n']}
        sage: G.plot(vertex_labels=False,vertex_size=20,vertex_colors=dic)
        Graphics object consisting of ... graphics primitives

    .. PLOT::
        :width: 300 px

        G = graphs.RandomBicubicPlanar(200)
        V0 = [v for v in G.vertices() if v[0] == 'n']
        V1 = [v for v in G.vertices() if v[0] != 'n']
        dic = {'red': V0, 'blue': V1}
        sphinx_plot(G.plot(vertex_labels=False,vertex_colors=dic))

    REFERENCES:

    .. [Schaeffer99] Gilles Schaeffer, *Random Sampling of Large Planar Maps and Convex Polyhedra*,
       Annual ACM Symposium on Theory of Computing (Atlanta, GA, 1999)
    """
    from sage.combinat.binary_tree import BinaryTrees
    from sage.rings.finite_rings.integer_mod_ring import Zmod
    if not n:
        raise ValueError("n must be at least 1")
    # first pick a random binary tree
    t = BinaryTrees(n).random_element()

    # next pick a random blossoming of this tree, compute its contour
    contour = blossoming_contour(t) + [('xb', )]  # adding the final xb

    # first step : rotate the contour word to one of 3 balanced
    N = len(contour)
    double_contour = contour + contour
    pile = []
    not_touched = [i for i in range(N) if contour[i][0] in ['x', 'xb']]
    for i, w in enumerate(double_contour):
        if w[0] == 'x' and i < N:
            pile.append(i)
        elif w[0] == 'xb' and (i % N) in not_touched:
            if pile:
                j = pile.pop()
                not_touched.remove(i % N)
                not_touched.remove(j)

    # random choice among 3 possibilities for a balanced word
    idx = not_touched[randint(0, 2)]
    w = contour[idx + 1:] + contour[:idx + 1]

    # second step : create the graph by closure from the balanced word
    G = Graph(multiedges=True)

    pile = []
    Z3 = Zmod(3)
    colour = Z3.zero()
    not_touched = [i for i, v in enumerate(w) if v[0] in ['x', 'xb']]
    for i, v in enumerate(w):
        # internal edges
        if v[0] == 'i':
            colour += 1
            if w[i + 1][0] == 'n':
                G.add_edge((w[i], w[i + 1], colour))
        elif v[0] == 'n':
            colour += 2
        elif v[0] == 'x':
            pile.append(i)
        elif v[0] == 'xb' and i in not_touched:
            if pile:
                j = pile.pop()
                G.add_edge((w[i + 1], w[j - 1], colour))
                not_touched.remove(i)
                not_touched.remove(j)

    # there remains to add three edges to elements of "not_touched"
    # from a new vertex labelled "n"
    for i in not_touched:
        taken_colours = [edge[2] for edge in G.edges_incident(w[i - 1])]
        colour = [u for u in Z3 if u not in taken_colours][0]
        G.add_edge((('n', -1), w[i - 1], colour))

    return G
Exemplo n.º 24
0
def find_root_order(p, n, r=0, accept=accept, verbose=True):
    '''
    Assuming that r divides n and p is prime,
    search for a small integer m such that:

    1. the order of <p> ⊂ ℤ/m* is equal to r⋅o;
    2. gcd(n, o) = 1;
    3. ℤ/m* = <p^o> × G for some G ⊂ ℤ/m*;

    then return o and a set of generators for G, together with their
    respective orders.

    The first condition implies that the m-th roots of unity generate
    a superfield of F_{p^r}.

    The second condition is not strictly necessary, but it makes
    the algorithm much more efficient by ensuring that the superfield
    is generated over F_{p^n} by a polynomial with coefficients in F_p.

    When r strictly divides n, the weaker condition:

    2'. gcd(n, r⋅o / gcd(n, r⋅o)) = 1; 

    can be used to work in a smaller superfield.

    The third condition is needed so that the construction of
    `find_unique_orbit` applies. In his paper, Rains' gives a
    sufficient condition for (3), namely that

    3'. gcd(r, φ(m)/r) = 1.

    It is easy to see that this condition is also necessary when ℤ/m*
    is cyclic, but there are easy counterexamples when it is not
    (e.g., take p=233, r=6, m=21).

    The integer m and the decomposition of ℤ/m are computed by the
    function `sieve` below, with acceptance criterion given by (1),
    (2) and (3').

    To conclude: bounds on m, hard to tell. When r is prime, m must be
    prime, and under GRH the best bound is m ∈ O(r^{2.4 + ε})
    [1]. Heuristically m ∈ O(r log r).  Pinch [2] and Rains give some
    tabulations.

    Note: this algorithm loops forever if p=2 and 8|r. Rains proposes
    two fixes in his paper, which we haven't implemented yet.

    [1]: D. R. Heath-Brown, Zero-free regions for Dirichlet L-functions, and
    the least prime in an arithmetic progression
    [2]: R. G. E. Pinch. Recognizing elements of finite fields.
    '''
    # For each prime power dividing r, find the smallest multiplier k.
    m = sieve(p, n, r, accept)

    if verbose:
        print "Using roots of unity of order {}".format(m)

    # Construct ℤ/m* as the product of the factors ℤ/f*
    R = Zmod(prod(f for f, _, _ in m))
    crt = map(R, crt_basis([f for f, _, _ in m]))
    G = [(sum(crt[:i]) +
          R(-1 if f % 2 == 0 and f != 4 else (Zmod(f).unit_gens()[0]**s)) *
          crt[i] + sum(crt[i + 1:]), t) for i, (f, s, t) in enumerate(m)]
    assert (all(g**e == 1 for (g, e) in G))

    ord = R(p).multiplicative_order()
    assert ord % r == 0

    return ord // r, G
Exemplo n.º 25
0
def blift(LF, Li, p, k, S=None, all_orbits=False):
    r"""
    Search for a solution to the given list of inequalities.

    If found, lift the solution to
    an appropriate valuation. See Lemma 3.3.6 in [Molnar]_

    INPUT:

    - ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients)

    - ``Li`` -- an integer, the bound on coefficients

    - ``p`` -- a prime

    - ``k`` -- the scaling factor that makes the solution a ``p``-adic integer

    - ``S`` -- polynomial ring to use

    - ``all_orbits`` -- boolean; whether or not to use ``==`` in the
      inequalities to find all orbits

    OUTPUT:

    - boolean -- whether or not the lift is successful

    - integer -- the lift

    EXAMPLES::

        sage: R.<b> = PolynomialRing(QQ)
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import blift
        sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341,\
        ....: -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3, 2)
        [[True, 4]]
    """

    P = LF[0].parent()
    #Determine which inequalities are trivial, and scale the rest, so that we only lift
    #as many times as needed.
    keepScaledIneqs = [scale(P(coeff), Li, p) for coeff in LF if coeff != 0]
    keptVals = [i[2] for i in keepScaledIneqs if i[0]]
    if keptVals != []:
        #Determine the valuation to lift until.
        liftval = max(keptVals)
    else:
        #All inequalities are satisfied.
        if all_orbits:
            return [[True, t] for t in range(p)]
        return [[True, 1]]
    if S is None:
        S = PolynomialRing(Zmod(p), 'b')
    keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]]
    #We need a solution for each polynomial on the left hand side of the inequalities,
    #so we need only find a solution for their gcd.
    g = gcd(keptScaledIneqs)
    rts = g.roots(multiplicities=False)
    good = []
    for r in rts:
        #Recursively try to lift each root
        r_initial = QQ(r)
        newInput = P([r_initial, p])
        LG = [F(newInput) for F in LF]
        new_good = blift(LG, Li, p, k, S=S)
        for lift, lifted in new_good:
            if lift:
                #Lift successful.
                if not all_orbits:
                    return [[True, r_initial + p * lifted]]

                #only need up to SL(2,ZZ) equivalence
                #this helps control the size of the resulting coefficients
                if r_initial + p * lifted < p**k:
                    good.append([True, r_initial + p * lifted])
                else:
                    new_r = r_initial + p * lifted - p**k
                    while new_r > p**k:
                        new_r -= p**k
                    if [True, new_r] not in good:
                        good.append([True, new_r])
    if good:
        return good
    #Lift non successful.
    return [[False, 0]]
Exemplo n.º 26
0
def mcfarland_1973_construction(q, s):
    r"""
    Return a difference set.

    The difference set returned has the following parameters

    .. MATH::

        v = \frac{q^{s+1}(q^{s+1}+q-2)}{q-1},
        k = \frac{q^s (q^{s+1}-1)}{q-1},
        \lambda = \frac{q^s(q^s-1)}{q-1}

    This construction is due to [McF1973]_.

    INPUT:

    - ``q``, ``s`` - (integers) parameters for the difference set (see the above
      formulas for the expression of ``v``, ``k``, ``l`` in terms of ``q`` and
      ``s``)

    .. SEEALSO::

        The function :func:`are_mcfarland_1973_parameters` makes the translation
        between the parameters `(q,s)` corresponding to a given triple
        `(v,k,\lambda)`.

    REFERENCES:

    .. [McF1973] Robert L. McFarland
       "A family of difference sets in non-cyclic groups"
       Journal of Combinatorial Theory (A) vol 15 (1973).
       http://dx.doi.org/10.1016/0097-3165(73)90031-9

    EXAMPLES::

        sage: from sage.combinat.designs.difference_family import (
        ....:    mcfarland_1973_construction, is_difference_family)

        sage: G,D = mcfarland_1973_construction(3, 1)
        sage: assert is_difference_family(G, D, 45, 12, 3)

        sage: G,D = mcfarland_1973_construction(2, 2)
        sage: assert is_difference_family(G, D, 64, 28, 12)
    """
    from sage.rings.finite_rings.finite_field_constructor import GF
    from sage.modules.free_module import VectorSpace
    from sage.rings.finite_rings.integer_mod_ring import Zmod
    from sage.categories.cartesian_product import cartesian_product
    from itertools import izip

    r = (q**(s + 1) - 1) // (q - 1)
    F = GF(q, 'a')
    V = VectorSpace(F, s + 1)
    K = Zmod(r + 1)

    G = cartesian_product([F] * (s + 1) + [K])

    D = []
    for k, H in izip(K, V.subspaces(s)):
        for v in H:
            D.append(G((tuple(v) + (k, ))))

    return G, [D]
Exemplo n.º 27
0
def v_5_1_BIBD(v, check=True):
    r"""
    Returns a `(v,5,1)`-BIBD.

    This method follows the constuction from [ClaytonSmith]_.

    INPUT:

    - ``v`` (integer)

    .. SEEALSO::

        * :meth:`BalancedIncompleteBlockDesign`

    EXAMPLES::

        sage: from sage.combinat.designs.bibd import v_5_1_BIBD
        sage: i = 0
        sage: while i<200:
        ....:    i += 20
        ....:    _ = v_5_1_BIBD(i+1)
        ....:    _ = v_5_1_BIBD(i+5)
    """
    v = int(v)

    assert (v > 1)
    assert (v % 20 == 5 or v % 20 == 1
            )  # note: equivalent to (v-1)%4 == 0 and (v*(v-1))%20 == 0

    # Lemma 27
    if v % 5 == 0 and (v // 5) % 4 == 1 and is_prime_power(v // 5):
        bibd = BIBD_5q_5_for_q_prime_power(v // 5)
    # Lemma 28
    elif v == 21:
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        bibd = BIBD_from_difference_family(Zmod(21), [[0, 1, 4, 14, 16]],
                                           check=False)
    elif v == 41:
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        bibd = BIBD_from_difference_family(
            Zmod(41), [[0, 1, 4, 11, 29], [0, 2, 8, 17, 22]], check=False)
    elif v == 61:
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        bibd = BIBD_from_difference_family(
            Zmod(61),
            [[0, 1, 3, 13, 34], [0, 4, 9, 23, 45], [0, 6, 17, 24, 32]],
            check=False)
    elif v == 81:
        from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup
        D = [[(0, 0, 0, 1), (2, 0, 0, 1), (0, 0, 2, 1), (1, 2, 0, 2),
              (0, 1, 1, 1)],
             [(0, 0, 1, 0), (1, 1, 0, 2), (0, 2, 1, 0), (1, 2, 0, 1),
              (1, 1, 1, 0)],
             [(2, 2, 1, 1), (1, 2, 2, 2), (2, 0, 1, 2), (0, 1, 2, 1),
              (1, 1, 0, 0)],
             [(0, 2, 0, 2), (1, 1, 0, 1), (1, 2, 1, 2), (1, 2, 1, 0),
              (0, 2, 1, 1)]]
        bibd = BIBD_from_difference_family(AdditiveAbelianGroup([3] * 4),
                                           D,
                                           check=False)
    elif v == 161:
        # VI.16.16 of the Handbook of Combinatorial Designs, Second Edition
        D = [(0, 19, 34, 73, 80), (0, 16, 44, 71, 79), (0, 12, 33, 74, 78),
             (0, 13, 30, 72, 77), (0, 11, 36, 67, 76), (0, 18, 32, 69, 75),
             (0, 10, 48, 68, 70), (0, 3, 29, 52, 53)]
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        bibd = BIBD_from_difference_family(Zmod(161), D, check=False)
    elif v == 281:
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        D = [[3**(2 * a + 56 * b) for b in range(5)] for a in range(14)]
        bibd = BIBD_from_difference_family(Zmod(281), D, check=False)
    # Lemma 29
    elif v == 165:
        bibd = BIBD_from_PBD(v_5_1_BIBD(41, check=False), 165, 5, check=False)
    elif v == 181:
        bibd = BIBD_from_PBD(v_5_1_BIBD(45, check=False), 181, 5, check=False)
    elif v in (201, 285, 301, 401, 421, 425):
        # Call directly the BIBD_from_TD function
        bibd = BIBD_from_TD(v, 5)
    # Lemma 30
    elif v == 141:
        # VI.16.16 of the Handbook of Combinatorial Designs, Second Edition
        from sage.rings.finite_rings.integer_mod_ring import Zmod
        D = [(0, 33, 60, 92, 97), (0, 3, 45, 88, 110), (0, 18, 39, 68, 139),
             (0, 12, 67, 75, 113), (0, 1, 15, 84, 94), (0, 7, 11, 24, 30),
             (0, 36, 90, 116, 125)]
        bibd = BIBD_from_difference_family(Zmod(141), D, check=False)

    # Theorem 31.2
    elif (v - 1) // 4 in [
            80, 81, 85, 86, 90, 91, 95, 96, 110, 111, 115, 116, 120, 121, 250,
            251, 255, 256, 260, 261, 265, 266, 270, 271
    ]:
        r = (v - 1) // 4
        if r <= 96:
            k, t, u = 5, 16, r - 80
        elif r <= 121:
            k, t, u = 10, 11, r - 110
        else:
            k, t, u = 10, 25, r - 250
        bibd = BIBD_from_PBD(PBD_from_TD(k, t, u), v, 5, check=False)

    else:
        r, s, t, u = _get_r_s_t_u(v)
        bibd = BIBD_from_PBD(PBD_from_TD(5, t, u), v, 5, check=False)

    if check:
        _check_pbd(bibd, v, [5])

    return bibd